From 2a99f9a2f24d02ba9f17136dacfab132acb08786 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:39:38 +0900 Subject: [PATCH 1/7] chore: move MeshInfo2Holder to another file --- .../EditSkinnedMeshComponentProcessor.cs | 51 ----------------- Editor/Processors/MeshInfo2Holder.cs | 56 +++++++++++++++++++ Editor/Processors/MeshInfo2Holder.cs.meta | 3 + 3 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 Editor/Processors/MeshInfo2Holder.cs create mode 100644 Editor/Processors/MeshInfo2Holder.cs.meta diff --git a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs index c872afcb5..07db464a2 100644 --- a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs +++ b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Linq; using Anatawa12.AvatarOptimizer.ErrorReporting; -using Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes; using UnityEngine; namespace Anatawa12.AvatarOptimizer.Processors @@ -36,52 +33,4 @@ public void Process(OptimizerSession session) holder.SaveToMesh(session); } } - - internal class MeshInfo2Holder - { - private readonly Dictionary _skinnedCache = - new Dictionary(); - - private readonly Dictionary _staticCache = new Dictionary(); - - public MeshInfo2 GetMeshInfoFor(SkinnedMeshRenderer renderer) => - _skinnedCache.TryGetValue(renderer, out var cached) - ? cached - : _skinnedCache[renderer] = new MeshInfo2(renderer); - - - public MeshInfo2 GetMeshInfoFor(MeshRenderer renderer) => - _staticCache.TryGetValue(renderer, out var cached) - ? cached - : _staticCache[renderer] = new MeshInfo2(renderer); - - public void SaveToMesh(OptimizerSession session) - { - foreach (var keyValuePair in _skinnedCache) - { - var targetRenderer = keyValuePair.Key; - if (!targetRenderer) continue; - - keyValuePair.Value.WriteToSkinnedMeshRenderer(targetRenderer, session); - } - - foreach (var keyValuePair in _staticCache) - { - var targetRenderer = keyValuePair.Key; - if (!targetRenderer) continue; - var meshInfo = keyValuePair.Value; - var meshFilter = targetRenderer.GetComponent(); - - BuildReport.ReportingObject(targetRenderer, () => - { - var mesh = meshFilter.sharedMesh - ? session.MayCreate(meshFilter.sharedMesh) - : session.AddToAsset(new Mesh()); - meshInfo.WriteToMesh(mesh); - meshFilter.sharedMesh = mesh; - targetRenderer.sharedMaterials = meshInfo.SubMeshes.Select(x => x.SharedMaterial).ToArray(); - }); - } - } - } } diff --git a/Editor/Processors/MeshInfo2Holder.cs b/Editor/Processors/MeshInfo2Holder.cs new file mode 100644 index 000000000..eedbde876 --- /dev/null +++ b/Editor/Processors/MeshInfo2Holder.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using Anatawa12.AvatarOptimizer.ErrorReporting; +using Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes; +using UnityEngine; + +namespace Anatawa12.AvatarOptimizer.Processors +{ + internal class MeshInfo2Holder + { + private readonly Dictionary _skinnedCache = + new Dictionary(); + + private readonly Dictionary _staticCache = new Dictionary(); + + public MeshInfo2 GetMeshInfoFor(SkinnedMeshRenderer renderer) => + _skinnedCache.TryGetValue(renderer, out var cached) + ? cached + : _skinnedCache[renderer] = new MeshInfo2(renderer); + + + public MeshInfo2 GetMeshInfoFor(MeshRenderer renderer) => + _staticCache.TryGetValue(renderer, out var cached) + ? cached + : _staticCache[renderer] = new MeshInfo2(renderer); + + public void SaveToMesh(OptimizerSession session) + { + foreach (var keyValuePair in _skinnedCache) + { + var targetRenderer = keyValuePair.Key; + if (!targetRenderer) continue; + + keyValuePair.Value.WriteToSkinnedMeshRenderer(targetRenderer, session); + } + + foreach (var keyValuePair in _staticCache) + { + var targetRenderer = keyValuePair.Key; + if (!targetRenderer) continue; + var meshInfo = keyValuePair.Value; + var meshFilter = targetRenderer.GetComponent(); + + BuildReport.ReportingObject(targetRenderer, () => + { + var mesh = meshFilter.sharedMesh + ? session.MayCreate(meshFilter.sharedMesh) + : session.AddToAsset(new Mesh()); + meshInfo.WriteToMesh(mesh); + meshFilter.sharedMesh = mesh; + targetRenderer.sharedMaterials = meshInfo.SubMeshes.Select(x => x.SharedMaterial).ToArray(); + }); + } + } + } +} diff --git a/Editor/Processors/MeshInfo2Holder.cs.meta b/Editor/Processors/MeshInfo2Holder.cs.meta new file mode 100644 index 000000000..59330146b --- /dev/null +++ b/Editor/Processors/MeshInfo2Holder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4d725df830c94738818c4d414a734060 +timeCreated: 1693993131 \ No newline at end of file From 6237135f6d962b47a8797dc232f04f5f5d669df8 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:46:17 +0900 Subject: [PATCH 2/7] chore: move MeshInfo2 to OptimizerSession --- Editor/OptimizerProcessor.cs | 1 + Editor/OptimizerSession.cs | 8 ++++++++ Editor/Processors/EditSkinnedMeshComponentProcessor.cs | 8 +++----- .../Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs | 4 ++-- .../Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs | 2 +- .../InternalAutoFreezeMeaninglessBlendShapeProcessor.cs | 2 +- .../Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs | 6 +++--- .../Processors/SkinnedMeshes/RemoveMeshInBoxProcessor.cs | 2 +- 8 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Editor/OptimizerProcessor.cs b/Editor/OptimizerProcessor.cs index ba12283b9..de482218c 100644 --- a/Editor/OptimizerProcessor.cs +++ b/Editor/OptimizerProcessor.cs @@ -163,6 +163,7 @@ private static void DoProcessObject(OptimizerSession session) new Processors.ClearEndpointPositionProcessor().Process(session); new Processors.MergePhysBoneProcessor().Process(session); new Processors.EditSkinnedMeshComponentProcessor().Process(session); + session.SaveMeshInfo2(); new Processors.MergeBoneProcessor().Process(session); new Processors.MakeChildrenProcessor(early: false).Process(session); diff --git a/Editor/OptimizerSession.cs b/Editor/OptimizerSession.cs index 5a56e52cf..5b33a26d6 100644 --- a/Editor/OptimizerSession.cs +++ b/Editor/OptimizerSession.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Anatawa12.AvatarOptimizer.Processors; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; @@ -14,6 +15,7 @@ internal class OptimizerSession private readonly DummyObject _assetFileObject; public bool IsTest { get; } public ObjectMappingBuilder MappingBuilder { get; } + public MeshInfo2Holder MeshInfo2Holder { get; set; } public OptimizerSession(GameObject rootObject, bool addToAsset, bool isTest) : this(rootObject, addToAsset ? Utils.CreateAssetFile() : null, isTest) @@ -69,5 +71,11 @@ public string RelativePath(Transform child) return Utils.RelativePath(_rootObject.transform, child) ?? throw new ArgumentException("child is not child of rootObject", nameof(child)); } + + public void SaveMeshInfo2() + { + MeshInfo2Holder.SaveToMesh(this); + MeshInfo2Holder = null; + } } } diff --git a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs index 07db464a2..015d16442 100644 --- a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs +++ b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs @@ -11,26 +11,24 @@ public void Process(OptimizerSession session) foreach (var component in session.GetComponents()) graph.AddComponent(component); - var holder = new MeshInfo2Holder(); + session.MeshInfo2Holder = new MeshInfo2Holder(); var renderers = session.GetComponents(); var processorLists = graph.GetSortedProcessors(renderers); foreach (var processors in processorLists) { - var target = holder.GetMeshInfoFor(processors.Target); + var target = session.MeshInfo2Holder.GetMeshInfoFor(processors.Target); foreach (var processor in processors.GetSorted()) { // TODO - BuildReport.ReportingObject(processor.Component, () => processor.Process(session, target, holder)); + BuildReport.ReportingObject(processor.Component, () => processor.Process(session, target)); target.AssertInvariantContract( $"after {processor.GetType().Name} " + $"for {processor.Target.gameObject.name}"); Object.DestroyImmediate(processor.Component); } } - - holder.SaveToMesh(session); } } } diff --git a/Editor/Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs b/Editor/Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs index 49d321a11..4557db1fc 100644 --- a/Editor/Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs @@ -22,7 +22,7 @@ protected EditSkinnedMeshProcessor(TComponent component) Target = component.GetComponent(); } - public abstract void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder); + public abstract void Process(OptimizerSession session, MeshInfo2 target); public abstract IMeshInfoComputer GetComputer(IMeshInfoComputer upstream); @@ -42,7 +42,7 @@ internal interface IEditSkinnedMeshProcessor IEnumerable Dependencies { get; } SkinnedMeshRenderer Target { get; } EditSkinnedMeshComponent Component { get; } - void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder); + void Process(OptimizerSession session, MeshInfo2 target); [NotNull] IMeshInfoComputer GetComputer([NotNull] IMeshInfoComputer upstream); } diff --git a/Editor/Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs b/Editor/Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs index 5ecf7d493..6642f68bb 100644 --- a/Editor/Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs @@ -13,7 +13,7 @@ public FreezeBlendShapeProcessor(FreezeBlendShape component) : base(component) public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AfterRemoveMesh; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { FreezeBlendShapes(Target, session, target, Component.FreezingShapeKeys); } diff --git a/Editor/Processors/SkinnedMeshes/InternalAutoFreezeMeaninglessBlendShapeProcessor.cs b/Editor/Processors/SkinnedMeshes/InternalAutoFreezeMeaninglessBlendShapeProcessor.cs index 0e1ce7b2d..00f98b4ca 100644 --- a/Editor/Processors/SkinnedMeshes/InternalAutoFreezeMeaninglessBlendShapeProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/InternalAutoFreezeMeaninglessBlendShapeProcessor.cs @@ -12,7 +12,7 @@ public InternalAutoFreezeMeaninglessBlendShapeProcessor(InternalAutoFreezeMeanin public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AutoConfigureFreezeBlendShape; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { var meaningfulBlendShapes = new HashSet(); diff --git a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs index 55d429384..b3510f820 100644 --- a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs @@ -17,10 +17,10 @@ public MergeSkinnedMeshProcessor(MergeSkinnedMesh component) : base(component) public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.Generation; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { - var meshInfos = Component.renderersSet.GetAsList().Select(meshInfo2Holder.GetMeshInfoFor) - .Concat(Component.staticRenderersSet.GetAsList().Select(meshInfo2Holder.GetMeshInfoFor)) + var meshInfos = Component.renderersSet.GetAsList().Select(session.MeshInfo2Holder.GetMeshInfoFor) + .Concat(Component.staticRenderersSet.GetAsList().Select(session.MeshInfo2Holder.GetMeshInfoFor)) .ToArray(); var sourceMaterials = meshInfos.Select(x => x.SubMeshes.Select(y => y.SharedMaterial).ToArray()).ToArray(); diff --git a/Editor/Processors/SkinnedMeshes/RemoveMeshInBoxProcessor.cs b/Editor/Processors/SkinnedMeshes/RemoveMeshInBoxProcessor.cs index 6cd465c90..1465a2e8b 100644 --- a/Editor/Processors/SkinnedMeshes/RemoveMeshInBoxProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/RemoveMeshInBoxProcessor.cs @@ -12,7 +12,7 @@ public RemoveMeshInBoxProcessor(RemoveMeshInBox component) : base(component) public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.RemovingMesh; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { var inBoxVertices = new HashSet(); // Vertex.AdditionalTemporal: 0 if in box, 1 if out of box From ee45fe60ab135320a8ada97f88bfe582e3a9a2c1 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:49:10 +0900 Subject: [PATCH 3/7] chore: rewrite MergeBoneProcessor with MeshInfo2 from session --- Editor/OptimizerProcessor.cs | 2 +- Editor/Processors/MergeBoneProcessor.cs | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Editor/OptimizerProcessor.cs b/Editor/OptimizerProcessor.cs index de482218c..27456ba37 100644 --- a/Editor/OptimizerProcessor.cs +++ b/Editor/OptimizerProcessor.cs @@ -163,9 +163,9 @@ private static void DoProcessObject(OptimizerSession session) new Processors.ClearEndpointPositionProcessor().Process(session); new Processors.MergePhysBoneProcessor().Process(session); new Processors.EditSkinnedMeshComponentProcessor().Process(session); - session.SaveMeshInfo2(); new Processors.MergeBoneProcessor().Process(session); new Processors.MakeChildrenProcessor(early: false).Process(session); + session.SaveMeshInfo2(); new Processors.ApplyObjectMapping().Apply(session); traceAndOptimize.ProcessLater(session); diff --git a/Editor/Processors/MergeBoneProcessor.cs b/Editor/Processors/MergeBoneProcessor.cs index 9b62e596c..3bdd4af59 100644 --- a/Editor/Processors/MergeBoneProcessor.cs +++ b/Editor/Processors/MergeBoneProcessor.cs @@ -26,7 +26,7 @@ public void Process(OptimizerSession session) BuildReport.ReportingObjects(session.GetComponents(), renderer => { if (renderer.bones.Where(x => x).Any(mergeMapping.ContainsKey)) - DoBoneMap2(session, renderer, mergeMapping); + DoBoneMap2(session.MeshInfo2Holder.GetMeshInfoFor(renderer), mergeMapping); }); foreach (var pair in mergeMapping) @@ -42,10 +42,8 @@ public void Process(OptimizerSession session) Object.DestroyImmediate(pair.gameObject); } - private void DoBoneMap2(OptimizerSession session, SkinnedMeshRenderer renderer, - Dictionary mergeMapping) + private void DoBoneMap2(MeshInfo2 meshInfo2, Dictionary mergeMapping) { - var meshInfo2 = new MeshInfo2(renderer); var primaryBones = new Dictionary(); var boneReplaced = false; @@ -138,8 +136,6 @@ private void DoBoneMap2(OptimizerSession session, SkinnedMeshRenderer renderer, .Select(g => (g.Key, g.Sum(x => x.weight))) .ToList(); } - - meshInfo2.WriteToSkinnedMeshRenderer(renderer, session); } private readonly struct BoneUniqKey : IEquatable From 2deb5e901627196f7a812c94b4077f9915dadf6a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:52:34 +0900 Subject: [PATCH 4/7] chore: initialize MeshInfo2Holder inside OptimizerSession constructor --- Editor/OptimizerSession.cs | 2 +- Editor/Processors/EditSkinnedMeshComponentProcessor.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Editor/OptimizerSession.cs b/Editor/OptimizerSession.cs index 5b33a26d6..c03dbe5b1 100644 --- a/Editor/OptimizerSession.cs +++ b/Editor/OptimizerSession.cs @@ -15,7 +15,7 @@ internal class OptimizerSession private readonly DummyObject _assetFileObject; public bool IsTest { get; } public ObjectMappingBuilder MappingBuilder { get; } - public MeshInfo2Holder MeshInfo2Holder { get; set; } + public MeshInfo2Holder MeshInfo2Holder { get; private set; } = new MeshInfo2Holder(); public OptimizerSession(GameObject rootObject, bool addToAsset, bool isTest) : this(rootObject, addToAsset ? Utils.CreateAssetFile() : null, isTest) diff --git a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs index 015d16442..a6dca2655 100644 --- a/Editor/Processors/EditSkinnedMeshComponentProcessor.cs +++ b/Editor/Processors/EditSkinnedMeshComponentProcessor.cs @@ -11,8 +11,6 @@ public void Process(OptimizerSession session) foreach (var component in session.GetComponents()) graph.AddComponent(component); - session.MeshInfo2Holder = new MeshInfo2Holder(); - var renderers = session.GetComponents(); var processorLists = graph.GetSortedProcessors(renderers); foreach (var processors in processorLists) From 74c79642f832933cd17267c2f19e4e6986a949e9 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:54:26 +0900 Subject: [PATCH 5/7] docs(changelog): add Share MeshInfo2 between SkinnedMesh processing and MergeBone --- CHANGELOG-PRERELEASE.md | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG-PRERELEASE.md b/CHANGELOG-PRERELEASE.md index b009a4ec8..4b05057b0 100644 --- a/CHANGELOG-PRERELEASE.md +++ b/CHANGELOG-PRERELEASE.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog]. ### Added ### Changed +- Performance: Share MeshInfo2 between SkinnedMesh processing and MergeBone `#421` ### Deprecated diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fe872fca..c8059610e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog]. ### Changed - Improved 'Remove Unused Objects' `#401` - Remove Unused Objects now removes unnecessary Components & Bones! +- Performance: Share MeshInfo2 between SkinnedMesh processing and MergeBone `#421` ### Deprecated From 32838c35691d6a709f39354d053ccb42f6ad6b7e Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:55:41 +0900 Subject: [PATCH 6/7] fix: Compilation Error --- .../Processors/SkinnedMeshes/MergeToonLitMaterialProcessor.cs | 2 +- .../Processors/SkinnedMeshes/RemoveMeshByBlendShapeProcessor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Processors/SkinnedMeshes/MergeToonLitMaterialProcessor.cs b/Editor/Processors/SkinnedMeshes/MergeToonLitMaterialProcessor.cs index d56cbea29..140291392 100644 --- a/Editor/Processors/SkinnedMeshes/MergeToonLitMaterialProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/MergeToonLitMaterialProcessor.cs @@ -26,7 +26,7 @@ public MergeToonLitMaterialProcessor(MergeToonLitMaterial component) : base(comp public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AfterRemoveMesh; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { // compute usages. AdditionalTemporal is usage count for now. // if #usages is not zero for merging triangles diff --git a/Editor/Processors/SkinnedMeshes/RemoveMeshByBlendShapeProcessor.cs b/Editor/Processors/SkinnedMeshes/RemoveMeshByBlendShapeProcessor.cs index 02eafecc0..aef705724 100644 --- a/Editor/Processors/SkinnedMeshes/RemoveMeshByBlendShapeProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/RemoveMeshByBlendShapeProcessor.cs @@ -12,7 +12,7 @@ public RemoveMeshByBlendShapeProcessor(RemoveMeshByBlendShape component) : base( // This needs to be less than FreezeBlendshapeProcessor.ProcessOrder. public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.RemovingMesh; - public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder) + public override void Process(OptimizerSession session, MeshInfo2 target) { var byBlendShapeVertices = new HashSet(); var sqrTolerance = Component.tolerance * Component.tolerance; From 31b0e738223cb225b17489dc850b0e8143106e16 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 6 Sep 2023 18:59:06 +0900 Subject: [PATCH 7/7] fix: MergeBone may does not process required SMR --- Editor/Processors/MergeBoneProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Editor/Processors/MergeBoneProcessor.cs b/Editor/Processors/MergeBoneProcessor.cs index 3bdd4af59..54a279698 100644 --- a/Editor/Processors/MergeBoneProcessor.cs +++ b/Editor/Processors/MergeBoneProcessor.cs @@ -25,8 +25,9 @@ public void Process(OptimizerSession session) BuildReport.ReportingObjects(session.GetComponents(), renderer => { - if (renderer.bones.Where(x => x).Any(mergeMapping.ContainsKey)) - DoBoneMap2(session.MeshInfo2Holder.GetMeshInfoFor(renderer), mergeMapping); + var meshInfo2 = session.MeshInfo2Holder.GetMeshInfoFor(renderer); + if (meshInfo2.Bones.Any(x => x.Transform && mergeMapping.ContainsKey(x.Transform))) + DoBoneMap2(meshInfo2, mergeMapping); }); foreach (var pair in mergeMapping)