Skip to content

Commit

Permalink
Merge pull request #278 from anatawa12/remove-always-disabled-objects
Browse files Browse the repository at this point in the history
Remove always disabled objects
  • Loading branch information
anatawa12 authored Aug 4, 2023
2 parents aae5e0e + d3107df commit 92dd0e3
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ weight: 1
現在、以下の機能の自動設定が可能です。
- [FreezeBlendShape](../freeze-blendshape)
アニメーションなどで使われていないBlendShapeを自動的に固定・除去します。
- `使われていないGameObjectを自動的に削除する`
アニメーションなどを走査して、使われていないGameObjectを自動的に削除します。

また、以下の設定で自動設定を調節できます。
- `MMDワールドとの互換性`
Expand Down
2 changes: 2 additions & 0 deletions .docs/content/docs/reference/automatic-configuration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ You can enable/disable some automatic configuration features with checkboxes.
Currently the following features can be configured automatically
- [FreezeBlendShape](../freeze-blendshape)
Automatically freezes unused BlendShapes in animation or else.
- `Remove unused GameObjects`
By scanning animation, etc., Automatically removes unused GameObjects.

Also, You can adjust automatic configuration with the following settings
- `MMD World Compatibility`
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog].

## [Unreleased]
### Added
- Remove always disabled objects `#278`

### Changed
- Use UnityEditor api to compress texture `#276`
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog].

## [Unreleased]
### Added
- Remove always disabled objects `#278`

### Changed
- Use UnityEditor api to compress texture `#276`
Expand Down
3 changes: 3 additions & 0 deletions Editor/AutomaticConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ namespace Anatawa12.AvatarOptimizer
internal class AutomaticConfigurationEditor : AvatarGlobalComponentEditorBase
{
private SerializedProperty _freezeBlendShape;
private SerializedProperty _removeUnusedObjects;
private SerializedProperty _mmdWorldCompatibility;

private void OnEnable()
{
_freezeBlendShape = serializedObject.FindProperty(nameof(AutomaticConfiguration.freezeBlendShape));
_removeUnusedObjects = serializedObject.FindProperty(nameof(AutomaticConfiguration.removeUnusedObjects));
_mmdWorldCompatibility = serializedObject.FindProperty(nameof(AutomaticConfiguration.mmdWorldCompatibility));
}

Expand All @@ -24,6 +26,7 @@ protected override void OnInspectorGUIInner()
EditorGUILayout.PropertyField(_mmdWorldCompatibility);
GUILayout.Label("Features", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_freezeBlendShape);
EditorGUILayout.PropertyField(_removeUnusedObjects);

serializedObject.ApplyModifiedProperties();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,21 +249,20 @@ private void GatherAnimationModificationsInController(GameObject root, RuntimeAn

readonly struct ParsedAnimation
{
public readonly IReadOnlyDictionary<Component, IReadOnlyDictionary<string, AnimationProperty>> Components;
public readonly IReadOnlyDictionary<Object, IReadOnlyDictionary<string, AnimationProperty>> Components;

public ParsedAnimation(IReadOnlyDictionary<Component, IReadOnlyDictionary<string, AnimationProperty>> components)
public ParsedAnimation(IReadOnlyDictionary<Object, IReadOnlyDictionary<string, AnimationProperty>> components)
{
Components = components;
}

public static ParsedAnimation Parse(GameObject root, AnimationClip clip)
{
var components = new Dictionary<Component, IReadOnlyDictionary<string, AnimationProperty>>();
var components = new Dictionary<Object, IReadOnlyDictionary<string, AnimationProperty>>();

foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
if (!typeof(Component).IsAssignableFrom(binding.type)) continue;
var obj = (Component)AnimationUtility.GetAnimatedObject(root, binding);
var obj = AnimationUtility.GetAnimatedObject(root, binding);
if (obj == null) continue;

var curve = AnimationUtility.GetEditorCurve(clip, binding);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using VRC.Dynamics;
using Object = UnityEngine.Object;

namespace Anatawa12.AvatarOptimizer.Processors
{
partial class AutomaticConfigurationProcessor
{
void FindUnusedObjects()
{
// mark & sweep
var gameObjects = new HashSet<GameObject>(_session.GetComponents<Transform>().Select(x => x.gameObject));
var referenced = new HashSet<GameObject>();
var newReferenced = new Queue<GameObject>();

void AddGameObject(GameObject gameObject)
{
if (gameObject && gameObjects.Contains(gameObject) && referenced.Add(gameObject))
newReferenced.Enqueue(gameObject);
}

// entry points: active GameObjects
foreach (var component in gameObjects.Where(x => x.activeInHierarchy))
AddGameObject(component);

// entry points: modified enable/disable
foreach (var keyValuePair in _modifiedProperties)
{
if (!(keyValuePair.Key is GameObject gameObject)) continue;
if (!keyValuePair.Value.TryGetValue("m_Active", out _)) continue;

AddGameObject(gameObject);
}

while (newReferenced.Count != 0)
{
var gameObject = newReferenced.Dequeue();

foreach (var component in gameObject.GetComponents<Component>())
{
if (component is Transform transform)
{
if (transform.parent)
AddGameObject(transform.parent.gameObject);
continue;
}

if (component is VRCPhysBoneBase)
{
foreach (var child in component.GetComponentsInChildren<Transform>(true))
AddGameObject(child.gameObject);
}

using (var serialized = new SerializedObject(component))
{
var iter = serialized.GetIterator();
var enterChildren = true;
while (iter.Next(enterChildren))
{
if (iter.propertyType == SerializedPropertyType.ObjectReference)
{
var value = iter.objectReferenceValue;
if (value is Component c && !EditorUtility.IsPersistent(value))
AddGameObject(c.gameObject);
}

switch (iter.propertyType)
{
case SerializedPropertyType.Integer:
case SerializedPropertyType.Boolean:
case SerializedPropertyType.Float:
case SerializedPropertyType.String:
case SerializedPropertyType.Color:
case SerializedPropertyType.ObjectReference:
case SerializedPropertyType.Enum:
case SerializedPropertyType.Vector2:
case SerializedPropertyType.Vector3:
case SerializedPropertyType.Vector4:
case SerializedPropertyType.Rect:
case SerializedPropertyType.ArraySize:
case SerializedPropertyType.Character:
case SerializedPropertyType.Bounds:
case SerializedPropertyType.Quaternion:
case SerializedPropertyType.FixedBufferSize:
case SerializedPropertyType.Vector2Int:
case SerializedPropertyType.Vector3Int:
case SerializedPropertyType.RectInt:
case SerializedPropertyType.BoundsInt:
enterChildren = false;
break;
case SerializedPropertyType.Generic:
case SerializedPropertyType.LayerMask:
case SerializedPropertyType.AnimationCurve:
case SerializedPropertyType.Gradient:
case SerializedPropertyType.ExposedReference:
case SerializedPropertyType.ManagedReference:
default:
enterChildren = true;
break;
}
}
}
}
}

// sweep
foreach (var gameObject in gameObjects.Where(x => !referenced.Contains(x)))
{
if (gameObject)
Object.DestroyImmediate(gameObject);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Anatawa12.AvatarOptimizer.Processors
{
Expand All @@ -10,8 +11,8 @@ internal partial class AutomaticConfigurationProcessor
private AutomaticConfiguration _config;
private OptimizerSession _session;

private Dictionary<Component, Dictionary<string, AnimationProperty>> _modifiedProperties =
new Dictionary<Component, Dictionary<string, AnimationProperty>>();
private Dictionary<Object, Dictionary<string, AnimationProperty>> _modifiedProperties =
new Dictionary<Object, Dictionary<string, AnimationProperty>>();

public void Process(OptimizerSession session)
{
Expand All @@ -23,13 +24,20 @@ public void Process(OptimizerSession session)
GatherAnimationModifications();
if (_config.freezeBlendShape)
AutoFreezeBlendShape();
if (_config.removeUnusedObjects)
FindUnusedObjects();
}

private IReadOnlyDictionary<string, AnimationProperty> GetModifiedProperties(Component component)
{
return _modifiedProperties.TryGetValue(component, out var value) ? value : EmptyProperties;
}

private IReadOnlyDictionary<string, AnimationProperty> GetModifiedProperties(GameObject component)
{
return _modifiedProperties.TryGetValue(component, out var value) ? value : EmptyProperties;
}

private static readonly IReadOnlyDictionary<string, AnimationProperty> EmptyProperties =
new ReadOnlyDictionary<string, AnimationProperty>(new Dictionary<string, AnimationProperty>());

Expand Down
3 changes: 3 additions & 0 deletions Localization/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ msgstr "Configure Freeze Blend Shape"
msgid "AutomaticConfiguration:prop:mmdWorldCompatibility"
msgstr "MMD World Compatibility"

msgid "AutomaticConfiguration:prop:removeUnusedObjects"
msgstr "Remove unused GameObjects"

msgid "AutomaticConfiguration:tooltip:mmdWorldCompatibility"
msgstr "Enable MMD World Compatibility features such as keeping some BlendShapes"

Expand Down
3 changes: 3 additions & 0 deletions Localization/ja.po
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ msgstr "このコンポーネントをアバターにつけると、アニメー
msgid "AutomaticConfiguration:prop:freezeBlendShape"
msgstr "Freeze Blend Shapeを自動設定する"

msgid "AutomaticConfiguration:prop:removeUnusedObjects"
msgstr "使われていないGameObjectを自動的に削除する"

msgid "AutomaticConfiguration:prop:mmdWorldCompatibility"
msgstr "MMDワールドとの互換性"

Expand Down
3 changes: 3 additions & 0 deletions Runtime/AutomaticConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ internal class AutomaticConfiguration : AvatarGlobalComponent
[CL4EELocalized("AutomaticConfiguration:prop:freezeBlendShape")]
[ToggleLeft]
public bool freezeBlendShape = true;
[CL4EELocalized("AutomaticConfiguration:prop:removeUnusedObjects")]
[ToggleLeft]
public bool removeUnusedObjects = true;
[CL4EELocalized("AutomaticConfiguration:prop:mmdWorldCompatibility",
"AutomaticConfiguration:tooltip:mmdWorldCompatibility")]
[ToggleLeft]
Expand Down

0 comments on commit 92dd0e3

Please sign in to comment.