From 75a319365417fc5e36c387e05619e3b797df4083 Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Thu, 2 May 2024 22:34:33 +0900 Subject: [PATCH 01/15] feat: MaterialUnusedPropertyRemove --- Editor/OptimizerPlugin.cs | 3 +- .../MaterialUnusedPropertyRemove.cs | 76 +++++++++++++++++++ .../MaterialUnusedPropertyRemove.cs.meta | 11 +++ .../TraceAndOptimizeProcessor.cs | 2 + Runtime/TraceAndOptimize.cs | 7 ++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs create mode 100644 Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta diff --git a/Editor/OptimizerPlugin.cs b/Editor/OptimizerPlugin.cs index 3e300f31c..3ed4ba4c0 100644 --- a/Editor/OptimizerPlugin.cs +++ b/Editor/OptimizerPlugin.cs @@ -1,4 +1,4 @@ -using System; +using System; using Anatawa12.AvatarOptimizer.ndmf; using nadena.dev.ndmf; using nadena.dev.ndmf.builtin; @@ -71,6 +71,7 @@ protected override void Configure() .Then.Run(Processors.TraceAndOptimizes.AutoMergeSkinnedMesh.Instance) .Then.Run(Processors.TraceAndOptimizes.FindUnusedObjects.Instance) .Then.Run(Processors.TraceAndOptimizes.ConfigureRemoveZeroSizedPolygon.Instance) + .Then.Run(Processors.TraceAndOptimizes.MaterialUnusedPropertyRemove.Instance) .Then.Run(Processors.MergeBoneProcessor.Instance) .Then.Run(Processors.RemoveZeroSizedPolygonProcessor.Instance) .Then.Run(Processors.AnimatorOptimizer.RemoveInvalidProperties.Instance) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs new file mode 100644 index 000000000..f41a66c2c --- /dev/null +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -0,0 +1,76 @@ +using System.Linq; +using nadena.dev.ndmf; +using UnityEditor; +using UnityEngine; + +namespace Anatawa12.AvatarOptimizer.Processors.TraceAndOptimizes +{ + internal class MaterialUnusedPropertyRemove : TraceAndOptimizePass + { + public override string DisplayName => "T&O: MaterialUnusedPropertyRemove"; + protected override void Execute(BuildContext context, TraceAndOptimizeState state) + { + if (!state.MaterialUnusedPropertyRemove) { return; } + + var renderers = context.GetComponents(); + var swapDict = renderers.SelectMany(i => i.sharedMaterials) + .Distinct().Where(i => i != null) + .ToDictionary(i => i, MaterialCleaning); + + foreach (var renderer in renderers) + { + var matArray = renderer.sharedMaterials; + for (var i = 0; matArray.Length > i; i += 1) + { + if (matArray[i] == null) { continue; } + matArray[i] = swapDict[matArray[i]]; + } + renderer.sharedMaterials = matArray; + } + + foreach (var matKv in swapDict) ObjectRegistry.RegisterReplacedObject(matKv.Key, matKv.Value); + } + + static Material MaterialCleaning(Material i) + { + var mat = UnityEngine.Object.Instantiate(i); + mat.name = i.name +"&AAO_MATERIAL_UNUSED_PROPERTIES_REMOLDED"; + RemoveUnusedProperties(mat); + return mat; + } + + //MIT License + //Copyright (c) 2020-2021 lilxyzw + //https://github.com/lilxyzw/lilToon/blob/b96470d3dd9092b840052578048b2307fe6d8786/Assets/lilToon/Editor/lilMaterialUtils.cs#L658-L686 + // + //https://light11.hatenadiary.com/entry/2018/12/04/224253 + public static void RemoveUnusedProperties(Material material) + { + var so = new SerializedObject(material); + so.Update(); + var savedProps = so.FindProperty("m_SavedProperties"); + + var texs = savedProps.FindPropertyRelative("m_TexEnvs"); + DeleteUnused(ref texs, material); + + var floats = savedProps.FindPropertyRelative("m_Floats"); + DeleteUnused(ref floats, material); + + var colors = savedProps.FindPropertyRelative("m_Colors"); + DeleteUnused(ref colors, material); + + so.ApplyModifiedProperties(); + } + + public static void DeleteUnused(ref SerializedProperty props, Material material) + { + for (int i = props.arraySize - 1; i >= 0; i--) + { + if (!material.HasProperty(props.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue)) + { + props.DeleteArrayElementAtIndex(i); + } + } + } + } +} diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta new file mode 100644 index 000000000..2c3649a0e --- /dev/null +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bccaca87ba114f34db008f501d1f0628 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs b/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs index aae588d3e..fdbe3ad55 100644 --- a/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs +++ b/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs @@ -15,6 +15,7 @@ public class TraceAndOptimizeState public bool MergeSkinnedMesh; public bool AllowShuffleMaterialSlots; public bool MmdWorldCompatibility = true; + public bool MaterialUnusedPropertyRemove; public bool PreserveEndBone; public HashSet Exclusions = new HashSet(); @@ -48,6 +49,7 @@ internal void Initialize(TraceAndOptimize config) MergeSkinnedMesh = config.mergeSkinnedMesh; AllowShuffleMaterialSlots = config.allowShuffleMaterialSlots; MmdWorldCompatibility = config.mmdWorldCompatibility; + MaterialUnusedPropertyRemove = config.materialUnusedPropertyRemove; PreserveEndBone = config.preserveEndBone; diff --git a/Runtime/TraceAndOptimize.cs b/Runtime/TraceAndOptimize.cs index 42b1cb657..5d1694a1b 100644 --- a/Runtime/TraceAndOptimize.cs +++ b/Runtime/TraceAndOptimize.cs @@ -74,6 +74,13 @@ public sealed class TraceAndOptimize : AvatarGlobalComponent [SerializeField] internal bool allowShuffleMaterialSlots; + [NotKeyable] + [AAOLocalized("TraceAndOptimize:prop:materialUnusedPropertyRemove", + "TraceAndOptimize:tooltip:materialUnusedPropertyRemove")] + [ToggleLeft] + [SerializeField] + internal bool materialUnusedPropertyRemove = true; + // common parsing configuration [NotKeyable] [AAOLocalized("TraceAndOptimize:prop:mmdWorldCompatibility", From 865db019613ec7093f09ea9e7bcbc2024408f993 Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Thu, 2 May 2024 23:10:53 +0900 Subject: [PATCH 02/15] chore: draw MaterialUnusedPropertyRemove toggle --- Editor/Inspector/TraceAndOptimizeEditor.cs | 5 ++++- Localization/en-us.po | 6 ++++++ Localization/ja-jp.po | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Editor/Inspector/TraceAndOptimizeEditor.cs b/Editor/Inspector/TraceAndOptimizeEditor.cs index d726d57e6..b473e5c09 100644 --- a/Editor/Inspector/TraceAndOptimizeEditor.cs +++ b/Editor/Inspector/TraceAndOptimizeEditor.cs @@ -14,6 +14,7 @@ internal class TraceAndOptimizeEditor : AvatarGlobalComponentEditorBase private SerializedProperty _optimizeAnimator; private SerializedProperty _mergeSkinnedMesh; private SerializedProperty _allowShuffleMaterialSlots; + private SerializedProperty _materialUnusedPropertyRemove; private SerializedProperty _animatorOptimizerEnabled; private SerializedProperty _animatorOptimizerEnd; private SerializedProperty _mmdWorldCompatibility; @@ -30,6 +31,7 @@ private void OnEnable() _optimizeAnimator = serializedObject.FindProperty(nameof(TraceAndOptimize.optimizeAnimator)); _mergeSkinnedMesh = serializedObject.FindProperty(nameof(TraceAndOptimize.mergeSkinnedMesh)); _allowShuffleMaterialSlots = serializedObject.FindProperty(nameof(TraceAndOptimize.allowShuffleMaterialSlots)); + _materialUnusedPropertyRemove = serializedObject.FindProperty(nameof(TraceAndOptimize.materialUnusedPropertyRemove)); _mmdWorldCompatibility = serializedObject.FindProperty(nameof(TraceAndOptimize.mmdWorldCompatibility)); _advancedSettings = serializedObject.FindProperty(nameof(TraceAndOptimize.advancedSettings)); } @@ -60,6 +62,7 @@ protected override void OnInspectorGUIInner() EditorGUILayout.PropertyField(_allowShuffleMaterialSlots); EditorGUI.indentLevel--; } + EditorGUILayout.PropertyField(_materialUnusedPropertyRemove); #if !UNITY_2021_3_OR_NEWER if (_optimizeAnimator.boolValue) @@ -84,4 +87,4 @@ protected override void OnInspectorGUIInner() serializedObject.ApplyModifiedProperties(); } } -} \ No newline at end of file +} diff --git a/Localization/en-us.po b/Localization/en-us.po index a30cde2ae..7fac67436 100644 --- a/Localization/en-us.po +++ b/Localization/en-us.po @@ -530,6 +530,12 @@ msgstr "Allow Shuffling Material Slots" msgid "TraceAndOptimize:tooltip:allowShuffleMaterialSlots" msgstr "Allow shuffling material slots to reduce draw calls. This may affect the rendering order." +msgid "TraceAndOptimize:prop:materialUnusedPropertyRemove" +msgstr "Material Unused Property Remove" + +msgid "TraceAndOptimize:tooltip:materialUnusedPropertyRemove" +msgstr "Remove unused textures and other properties from shaders from materials." + msgid "TraceAndOptimize:prop:mmdWorldCompatibility" msgstr "MMD World Compatibility" diff --git a/Localization/ja-jp.po b/Localization/ja-jp.po index 73ae6a177..96d8db53f 100644 --- a/Localization/ja-jp.po +++ b/Localization/ja-jp.po @@ -439,6 +439,12 @@ msgstr "マテリアルスロットの前後関係を変えることを許可す msgid "TraceAndOptimize:tooltip:allowShuffleMaterialSlots" msgstr "マテリアルスロットの前後関係を変えることでドローコールを減らすことを許可します。これは描画順に影響を与える可能性があります。" +msgid "TraceAndOptimize:prop:materialUnusedPropertyRemove" +msgstr "マテリアルの未使用プロパティを削除する" + +msgid "TraceAndOptimize:tooltip:materialUnusedPropertyRemove" +msgstr "シェーダーから使用されていないテクスチャーなどのプロパティをマテリアルから削除します。" + msgid "TraceAndOptimize:prop:mmdWorldCompatibility" msgstr "MMDワールドとの互換性" From 7d5e05f5b3aae26a2a4b2a90b32c7a17c0ab0dbb Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Fri, 3 May 2024 02:51:32 +0900 Subject: [PATCH 03/15] chore: move in RemoveUnusedObjects --- Editor/Inspector/TraceAndOptimizeEditor.cs | 3 --- .../TraceAndOptimize/MaterialUnusedPropertyRemove.cs | 5 +++-- .../TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs | 4 ++-- Localization/en-us.po | 6 ------ Localization/ja-jp.po | 6 ------ Runtime/TraceAndOptimize.cs | 9 ++------- 6 files changed, 7 insertions(+), 26 deletions(-) diff --git a/Editor/Inspector/TraceAndOptimizeEditor.cs b/Editor/Inspector/TraceAndOptimizeEditor.cs index b473e5c09..7f5f3fa20 100644 --- a/Editor/Inspector/TraceAndOptimizeEditor.cs +++ b/Editor/Inspector/TraceAndOptimizeEditor.cs @@ -14,7 +14,6 @@ internal class TraceAndOptimizeEditor : AvatarGlobalComponentEditorBase private SerializedProperty _optimizeAnimator; private SerializedProperty _mergeSkinnedMesh; private SerializedProperty _allowShuffleMaterialSlots; - private SerializedProperty _materialUnusedPropertyRemove; private SerializedProperty _animatorOptimizerEnabled; private SerializedProperty _animatorOptimizerEnd; private SerializedProperty _mmdWorldCompatibility; @@ -31,7 +30,6 @@ private void OnEnable() _optimizeAnimator = serializedObject.FindProperty(nameof(TraceAndOptimize.optimizeAnimator)); _mergeSkinnedMesh = serializedObject.FindProperty(nameof(TraceAndOptimize.mergeSkinnedMesh)); _allowShuffleMaterialSlots = serializedObject.FindProperty(nameof(TraceAndOptimize.allowShuffleMaterialSlots)); - _materialUnusedPropertyRemove = serializedObject.FindProperty(nameof(TraceAndOptimize.materialUnusedPropertyRemove)); _mmdWorldCompatibility = serializedObject.FindProperty(nameof(TraceAndOptimize.mmdWorldCompatibility)); _advancedSettings = serializedObject.FindProperty(nameof(TraceAndOptimize.advancedSettings)); } @@ -62,7 +60,6 @@ protected override void OnInspectorGUIInner() EditorGUILayout.PropertyField(_allowShuffleMaterialSlots); EditorGUI.indentLevel--; } - EditorGUILayout.PropertyField(_materialUnusedPropertyRemove); #if !UNITY_2021_3_OR_NEWER if (_optimizeAnimator.boolValue) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index f41a66c2c..60b5a592f 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -10,7 +10,8 @@ internal class MaterialUnusedPropertyRemove : TraceAndOptimizePass "T&O: MaterialUnusedPropertyRemove"; protected override void Execute(BuildContext context, TraceAndOptimizeState state) { - if (!state.MaterialUnusedPropertyRemove) { return; } + if (!state.RemoveUnusedObjects) { return; } + if (state.SkipRemoveMaterialUnusedProperties) { return; } var renderers = context.GetComponents(); var swapDict = renderers.SelectMany(i => i.sharedMaterials) @@ -34,7 +35,7 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat static Material MaterialCleaning(Material i) { var mat = UnityEngine.Object.Instantiate(i); - mat.name = i.name +"&AAO_MATERIAL_UNUSED_PROPERTIES_REMOLDED"; + mat.name = i.name + "&AAO_MATERIAL_UNUSED_PROPERTIES_REMOLDED"; RemoveUnusedProperties(mat); return mat; } diff --git a/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs b/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs index fdbe3ad55..086b875dd 100644 --- a/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs +++ b/Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs @@ -15,7 +15,6 @@ public class TraceAndOptimizeState public bool MergeSkinnedMesh; public bool AllowShuffleMaterialSlots; public bool MmdWorldCompatibility = true; - public bool MaterialUnusedPropertyRemove; public bool PreserveEndBone; public HashSet Exclusions = new HashSet(); @@ -35,6 +34,7 @@ public class TraceAndOptimizeState public bool SkipMergeMaterialAnimatingSkinnedMesh; public bool SkipMergeMaterials; public bool SkipRemoveEmptySubMesh; + public bool SkipRemoveMaterialUnusedProperties; public Dictionary> PreserveBlendShapes = new Dictionary>(); @@ -49,7 +49,6 @@ internal void Initialize(TraceAndOptimize config) MergeSkinnedMesh = config.mergeSkinnedMesh; AllowShuffleMaterialSlots = config.allowShuffleMaterialSlots; MmdWorldCompatibility = config.mmdWorldCompatibility; - MaterialUnusedPropertyRemove = config.materialUnusedPropertyRemove; PreserveEndBone = config.preserveEndBone; @@ -70,6 +69,7 @@ internal void Initialize(TraceAndOptimize config) SkipMergeMaterialAnimatingSkinnedMesh = config.advancedSettings.skipMergeMaterialAnimatingSkinnedMesh; SkipMergeMaterials = config.advancedSettings.skipMergeMaterials; SkipRemoveEmptySubMesh = config.advancedSettings.skipRemoveEmptySubMesh; + SkipRemoveMaterialUnusedProperties = config.advancedSettings.skipRemoveMaterialUnusedProperties; Enabled = true; } diff --git a/Localization/en-us.po b/Localization/en-us.po index 7fac67436..a30cde2ae 100644 --- a/Localization/en-us.po +++ b/Localization/en-us.po @@ -530,12 +530,6 @@ msgstr "Allow Shuffling Material Slots" msgid "TraceAndOptimize:tooltip:allowShuffleMaterialSlots" msgstr "Allow shuffling material slots to reduce draw calls. This may affect the rendering order." -msgid "TraceAndOptimize:prop:materialUnusedPropertyRemove" -msgstr "Material Unused Property Remove" - -msgid "TraceAndOptimize:tooltip:materialUnusedPropertyRemove" -msgstr "Remove unused textures and other properties from shaders from materials." - msgid "TraceAndOptimize:prop:mmdWorldCompatibility" msgstr "MMD World Compatibility" diff --git a/Localization/ja-jp.po b/Localization/ja-jp.po index 96d8db53f..73ae6a177 100644 --- a/Localization/ja-jp.po +++ b/Localization/ja-jp.po @@ -439,12 +439,6 @@ msgstr "マテリアルスロットの前後関係を変えることを許可す msgid "TraceAndOptimize:tooltip:allowShuffleMaterialSlots" msgstr "マテリアルスロットの前後関係を変えることでドローコールを減らすことを許可します。これは描画順に影響を与える可能性があります。" -msgid "TraceAndOptimize:prop:materialUnusedPropertyRemove" -msgstr "マテリアルの未使用プロパティを削除する" - -msgid "TraceAndOptimize:tooltip:materialUnusedPropertyRemove" -msgstr "シェーダーから使用されていないテクスチャーなどのプロパティをマテリアルから削除します。" - msgid "TraceAndOptimize:prop:mmdWorldCompatibility" msgstr "MMDワールドとの互換性" diff --git a/Runtime/TraceAndOptimize.cs b/Runtime/TraceAndOptimize.cs index 5d1694a1b..c8f99dc38 100644 --- a/Runtime/TraceAndOptimize.cs +++ b/Runtime/TraceAndOptimize.cs @@ -74,13 +74,6 @@ public sealed class TraceAndOptimize : AvatarGlobalComponent [SerializeField] internal bool allowShuffleMaterialSlots; - [NotKeyable] - [AAOLocalized("TraceAndOptimize:prop:materialUnusedPropertyRemove", - "TraceAndOptimize:tooltip:materialUnusedPropertyRemove")] - [ToggleLeft] - [SerializeField] - internal bool materialUnusedPropertyRemove = true; - // common parsing configuration [NotKeyable] [AAOLocalized("TraceAndOptimize:prop:mmdWorldCompatibility", @@ -132,6 +125,8 @@ internal struct AdvancedSettings public bool skipMergeMaterials; [ToggleLeft] public bool skipRemoveEmptySubMesh; + [ToggleLeft] + public bool skipRemoveMaterialUnusedProperties; } } } From 6dcb0615051a6cc2a113fe36a8be6e1453f5f12d Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Fri, 3 May 2024 03:53:44 +0900 Subject: [PATCH 04/15] chore: If SkinnedMesh then use MeshInfo2 --- .../MaterialUnusedPropertyRemove.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index 60b5a592f..05e21c5f1 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -18,15 +18,29 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat .Distinct().Where(i => i != null) .ToDictionary(i => i, MaterialCleaning); - foreach (var renderer in renderers) + void SwapMaterialArray(Material[] matArray) { - var matArray = renderer.sharedMaterials; for (var i = 0; matArray.Length > i; i += 1) { if (matArray[i] == null) { continue; } matArray[i] = swapDict[matArray[i]]; } - renderer.sharedMaterials = matArray; + } + + foreach (var renderer in renderers) + { + if (renderer is SkinnedMeshRenderer smr) + { + var meshInfo = context.GetMeshInfoFor(smr); + foreach (var subMesh in meshInfo.SubMeshes) + SwapMaterialArray(subMesh.SharedMaterials); + } + else + { + var matArray = renderer.sharedMaterials; + SwapMaterialArray(matArray); + renderer.sharedMaterials = matArray; + } } foreach (var matKv in swapDict) ObjectRegistry.RegisterReplacedObject(matKv.Key, matKv.Value); From 38e6a5ca8a394bb0daaa6790ce08ba4fd40026c3 Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Sat, 4 May 2024 18:44:17 +0900 Subject: [PATCH 05/15] chore: If SkinnedMesh then use MeshInfo2 collect materials --- .../TraceAndOptimize/MaterialUnusedPropertyRemove.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index 05e21c5f1..1632e7cae 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -14,7 +14,8 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat if (state.SkipRemoveMaterialUnusedProperties) { return; } var renderers = context.GetComponents(); - var swapDict = renderers.SelectMany(i => i.sharedMaterials) + var swapDict = renderers.SelectMany(i => + i is SkinnedMeshRenderer smr ? context.GetMeshInfoFor(smr).SubMeshes.SelectMany(sm => sm.SharedMaterials) : i.sharedMaterials) .Distinct().Where(i => i != null) .ToDictionary(i => i, MaterialCleaning); From 82551f4bcfb30f58e90bf5e416d39bc0e351926e Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Sat, 4 May 2024 18:54:51 +0900 Subject: [PATCH 06/15] chore: make MaterialCleaning public --- .../Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index 1632e7cae..d3185bd62 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -47,7 +47,7 @@ void SwapMaterialArray(Material[] matArray) foreach (var matKv in swapDict) ObjectRegistry.RegisterReplacedObject(matKv.Key, matKv.Value); } - static Material MaterialCleaning(Material i) + public static Material MaterialCleaning(Material i) { var mat = UnityEngine.Object.Instantiate(i); mat.name = i.name + "&AAO_MATERIAL_UNUSED_PROPERTIES_REMOLDED"; From 7d1ee87ad18734a6a0be3f50f050ddf0ad8ef13d Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Sun, 5 May 2024 00:21:20 +0900 Subject: [PATCH 07/15] chore: MaterialCleaning run as need time --- .../MaterialUnusedPropertyRemove.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index d3185bd62..6a79ec36b 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using nadena.dev.ndmf; using UnityEditor; @@ -14,17 +15,17 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat if (state.SkipRemoveMaterialUnusedProperties) { return; } var renderers = context.GetComponents(); - var swapDict = renderers.SelectMany(i => - i is SkinnedMeshRenderer smr ? context.GetMeshInfoFor(smr).SubMeshes.SelectMany(sm => sm.SharedMaterials) : i.sharedMaterials) - .Distinct().Where(i => i != null) - .ToDictionary(i => i, MaterialCleaning); + var swapDict = new Dictionary(); void SwapMaterialArray(Material[] matArray) { for (var i = 0; matArray.Length > i; i += 1) { - if (matArray[i] == null) { continue; } - matArray[i] = swapDict[matArray[i]]; + var sourceMaterial = matArray[i]; + if (sourceMaterial == null) { continue; } + + if (swapDict.TryGetValue(sourceMaterial, out var cleanMaterial)) { matArray[i] = cleanMaterial; } + else { swapDict[sourceMaterial] = matArray[i] = MaterialCleaning(sourceMaterial); } } } From 6b91ec15d6b32cb9909b1ae54b2be49656d0f717 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 23 Aug 2024 23:02:43 +0900 Subject: [PATCH 08/15] docs(changelog): Automatically remove unnecessary material properties based on shader --- CHANGELOG-PRERELEASE.md | 4 ++++ CHANGELOG.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG-PRERELEASE.md b/CHANGELOG-PRERELEASE.md index f500ef8b8..597dbb112 100644 --- a/CHANGELOG-PRERELEASE.md +++ b/CHANGELOG-PRERELEASE.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog]. ## [Unreleased] ### Added +- Automatically remove unnecessary material properties based on shader `#1041` + - This feature is added to `Remove Unused Objects` in `Trace and Optimize`. + - When you changed shader for an material, properties for previously used shaders might be remain + - This may increase your avatar size by unexpectedly including unused textures ### Changed diff --git a/CHANGELOG.md b/CHANGELOG.md index fc150f67a..3bf3f3993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog]. ## [Unreleased] ### Added +- Automatically remove unnecessary material properties based on shader `#1041` + - This feature is added to `Remove Unused Objects` in `Trace and Optimize`. + - When you changed shader for an material, properties for previously used shaders might be remain + - This may increase your avatar size by unexpectedly including unused textures ### Changed From 930f047d3f49a3b56f59251fb20adc8962541a07 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 23 Aug 2024 23:10:28 +0900 Subject: [PATCH 09/15] fix: compilation error due to nullable reference type --- .../Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index 6a79ec36b..ff6fa5c35 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -17,7 +17,7 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat var renderers = context.GetComponents(); var swapDict = new Dictionary(); - void SwapMaterialArray(Material[] matArray) + void SwapMaterialArray(Material?[] matArray) { for (var i = 0; matArray.Length > i; i += 1) { From 9f5e282890f3637d8a061a4dbf91f5051939dba2 Mon Sep 17 00:00:00 2001 From: Reina_Sakiria Date: Wed, 16 Oct 2024 19:51:39 +0900 Subject: [PATCH 10/15] chore: cleaning in place --- .../MaterialUnusedPropertyRemove.cs | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs index ff6fa5c35..fa2fd7d5a 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs @@ -15,18 +15,16 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat if (state.SkipRemoveMaterialUnusedProperties) { return; } var renderers = context.GetComponents(); - var swapDict = new Dictionary(); + var cleaned = new HashSet(); - void SwapMaterialArray(Material?[] matArray) + void MaterialCleaning(IEnumerable materials) { - for (var i = 0; matArray.Length > i; i += 1) - { - var sourceMaterial = matArray[i]; - if (sourceMaterial == null) { continue; } - - if (swapDict.TryGetValue(sourceMaterial, out var cleanMaterial)) { matArray[i] = cleanMaterial; } - else { swapDict[sourceMaterial] = matArray[i] = MaterialCleaning(sourceMaterial); } - } + foreach (var m in materials) + if (m is not null && cleaned.Contains(m) is false) + { + RemoveUnusedProperties(m); + cleaned.Add(m); + } } foreach (var renderer in renderers) @@ -35,25 +33,10 @@ void SwapMaterialArray(Material?[] matArray) { var meshInfo = context.GetMeshInfoFor(smr); foreach (var subMesh in meshInfo.SubMeshes) - SwapMaterialArray(subMesh.SharedMaterials); - } - else - { - var matArray = renderer.sharedMaterials; - SwapMaterialArray(matArray); - renderer.sharedMaterials = matArray; + MaterialCleaning(subMesh.SharedMaterials); } + else { MaterialCleaning(renderer.sharedMaterials); } } - - foreach (var matKv in swapDict) ObjectRegistry.RegisterReplacedObject(matKv.Key, matKv.Value); - } - - public static Material MaterialCleaning(Material i) - { - var mat = UnityEngine.Object.Instantiate(i); - mat.name = i.name + "&AAO_MATERIAL_UNUSED_PROPERTIES_REMOLDED"; - RemoveUnusedProperties(mat); - return mat; } //MIT License From eda5998b4c175dbeeed2469c80d8c3caf33cd856 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 18 Oct 2024 09:37:46 +0900 Subject: [PATCH 11/15] chore: rename pass name to RemoveUnusedMaterialProperties --- Editor/OptimizerPlugin.cs | 2 +- ...sedPropertyRemove.cs => RemoveUnusedMaterialProperties.cs} | 4 ++-- ...yRemove.cs.meta => RemoveUnusedMaterialProperties.cs.meta} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename Editor/Processors/TraceAndOptimize/{MaterialUnusedPropertyRemove.cs => RemoveUnusedMaterialProperties.cs} (93%) rename Editor/Processors/TraceAndOptimize/{MaterialUnusedPropertyRemove.cs.meta => RemoveUnusedMaterialProperties.cs.meta} (100%) diff --git a/Editor/OptimizerPlugin.cs b/Editor/OptimizerPlugin.cs index 785e17a6e..f20712689 100644 --- a/Editor/OptimizerPlugin.cs +++ b/Editor/OptimizerPlugin.cs @@ -77,7 +77,7 @@ protected override void Configure() .Then.Run(Processors.TraceAndOptimizes.AutoMergeSkinnedMesh.Instance) .Then.Run(Processors.TraceAndOptimizes.FindUnusedObjects.Instance) .Then.Run(Processors.TraceAndOptimizes.ConfigureRemoveZeroSizedPolygon.Instance) - .Then.Run(Processors.TraceAndOptimizes.MaterialUnusedPropertyRemove.Instance) + .Then.Run(Processors.TraceAndOptimizes.RemoveUnusedMaterialProperties.Instance) .Then.Run(Processors.MergeBoneProcessor.Instance) .Then.Run(Processors.RemoveZeroSizedPolygonProcessor.Instance) .Then.Run(Processors.TraceAndOptimizes.OptimizeTexture.Instance) diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs similarity index 93% rename from Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs rename to Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs index fa2fd7d5a..66050d792 100644 --- a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs +++ b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs @@ -6,9 +6,9 @@ namespace Anatawa12.AvatarOptimizer.Processors.TraceAndOptimizes { - internal class MaterialUnusedPropertyRemove : TraceAndOptimizePass + internal class RemoveUnusedMaterialProperties : TraceAndOptimizePass { - public override string DisplayName => "T&O: MaterialUnusedPropertyRemove"; + public override string DisplayName => "T&O: RemoveUnusedMaterialProperties"; protected override void Execute(BuildContext context, TraceAndOptimizeState state) { if (!state.RemoveUnusedObjects) { return; } diff --git a/Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs.meta similarity index 100% rename from Editor/Processors/TraceAndOptimize/MaterialUnusedPropertyRemove.cs.meta rename to Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs.meta From c3ac6e9a20661a62e5f9efe69dae6f8f38ea76ce Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 18 Oct 2024 09:43:35 +0900 Subject: [PATCH 12/15] fix: Properties used by fallback shader will be removed incorrectly --- .../RemoveUnusedMaterialProperties.cs | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs index 66050d792..7b83ad98b 100644 --- a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs +++ b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs @@ -64,13 +64,50 @@ public static void RemoveUnusedProperties(Material material) public static void DeleteUnused(ref SerializedProperty props, Material material) { - for (int i = props.arraySize - 1; i >= 0; i--) + for (var i = props.arraySize - 1; i >= 0; i--) { - if (!material.HasProperty(props.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue)) + var porpertyName = props.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue; + if (!material.HasProperty(porpertyName) && !fallbackShaderProperties.Contains(porpertyName)) { props.DeleteArrayElementAtIndex(i); } } } + + // https://creators.vrchat.com/avatars/shader-fallback-system + private static HashSet fallbackShaderProperties = new HashSet + { + "_MainTex", + "_MetallicGlossMap", + "_SpecGlossMap", + "_BumpMap", + "_ParallaxMap", + "_OcclusionMap", + "_EmissionMap", + "_DetailMask", + "_DetailAlbedoMap", + "_DetailNormalMap", + "_Color", + "_EmissionColor", + "_SpecColor", + "_Cutoff", + "_Glossiness", + "_GlossMapScale", + "_SpecularHighlights", + "_GlossyReflections", + "_SmoothnessTextureChannel", + "_Metallic", + "_SpecularHighlights", + "_GlossyReflections", + "_BumpScale", + "_Parallax", + "_OcclusionStrength", + "_DetailNormalMapScale", + "_UVSec", + "_Mode", + "_SrcBlend", + "_DstBlend", + "_ZWrite", + }; } } From 1c3615055e16a65fdc02f55ec68c05551445ea33 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 18 Oct 2024 09:45:11 +0900 Subject: [PATCH 13/15] feat: support cleaning animation materials --- .../TraceAndOptimize/RemoveUnusedMaterialProperties.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs index 7b83ad98b..c43d867a6 100644 --- a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs +++ b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs @@ -35,7 +35,14 @@ void MaterialCleaning(IEnumerable materials) foreach (var subMesh in meshInfo.SubMeshes) MaterialCleaning(subMesh.SharedMaterials); } - else { MaterialCleaning(renderer.sharedMaterials); } + else + { + MaterialCleaning(renderer.sharedMaterials); + } + + MaterialCleaning(context.GetAnimationComponent(renderer).GetAllObjectProperties() + .SelectMany(x => x.node.Value.PossibleValues) + .OfType()); } } From 8542571499ffcc2952ab183b440d13fb85c97bed Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 18 Oct 2024 09:48:11 +0900 Subject: [PATCH 14/15] chore: check the material is temporary asset before modification --- .../RemoveUnusedMaterialProperties.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs index c43d867a6..95115ed89 100644 --- a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs +++ b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs @@ -17,14 +17,17 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat var renderers = context.GetComponents(); var cleaned = new HashSet(); - void MaterialCleaning(IEnumerable materials) + void CleanMaterial(IEnumerable materials) { foreach (var m in materials) - if (m is not null && cleaned.Contains(m) is false) + { + if (m != null && !cleaned.Contains(m)) { - RemoveUnusedProperties(m); + if (context.IsTemporaryAsset(m)) + RemoveUnusedProperties(m); cleaned.Add(m); } + } } foreach (var renderer in renderers) @@ -33,14 +36,14 @@ void MaterialCleaning(IEnumerable materials) { var meshInfo = context.GetMeshInfoFor(smr); foreach (var subMesh in meshInfo.SubMeshes) - MaterialCleaning(subMesh.SharedMaterials); + CleanMaterial(subMesh.SharedMaterials); } else { - MaterialCleaning(renderer.sharedMaterials); + CleanMaterial(renderer.sharedMaterials); } - MaterialCleaning(context.GetAnimationComponent(renderer).GetAllObjectProperties() + CleanMaterial(context.GetAnimationComponent(renderer).GetAllObjectProperties() .SelectMany(x => x.node.Value.PossibleValues) .OfType()); } From bae5ed417d30021a5e31fb1f9ffc3be82f7bcd11 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 18 Oct 2024 09:52:01 +0900 Subject: [PATCH 15/15] chore: add TODO comments for future improvements --- .../TraceAndOptimize/RemoveUnusedMaterialProperties.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs index 95115ed89..5cbf4ca9c 100644 --- a/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs +++ b/Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs @@ -56,6 +56,7 @@ void CleanMaterial(IEnumerable materials) //https://light11.hatenadiary.com/entry/2018/12/04/224253 public static void RemoveUnusedProperties(Material material) { + // TODO: support material variant var so = new SerializedObject(material); so.Update(); var savedProps = so.FindProperty("m_SavedProperties"); @@ -84,6 +85,7 @@ public static void DeleteUnused(ref SerializedProperty props, Material material) } } + // TODO: change set of properties by fallback shader names // https://creators.vrchat.com/avatars/shader-fallback-system private static HashSet fallbackShaderProperties = new HashSet {