From e39a77855a429dc4d5288bfcceff061901cfb699 Mon Sep 17 00:00:00 2001
From: bd_ <bd_@nadena.dev>
Date: Sun, 3 Mar 2024 20:26:09 -0800
Subject: [PATCH] fix: don't enable scale proxy when no relevant bones are used
 in the mesh (#728)

---
 .../ScaleAdjuster/ScaleAdjusterRenderer.cs    | 62 +++++++++++++++----
 1 file changed, 51 insertions(+), 11 deletions(-)

diff --git a/Runtime/ScaleAdjuster/ScaleAdjusterRenderer.cs b/Runtime/ScaleAdjuster/ScaleAdjusterRenderer.cs
index 142a40b0..f53655ac 100644
--- a/Runtime/ScaleAdjuster/ScaleAdjusterRenderer.cs
+++ b/Runtime/ScaleAdjuster/ScaleAdjusterRenderer.cs
@@ -1,12 +1,11 @@
 #region
 
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using nadena.dev.modular_avatar.JacksonDunstan.NativeCollections;
 #if UNITY_EDITOR
 using UnityEditor;
 #endif
+using System.Collections.Generic;
+using System.Linq;
+using nadena.dev.modular_avatar.JacksonDunstan.NativeCollections;
 using UnityEngine;
 using VRC.SDKBase;
 using Object = System.Object;
@@ -51,6 +50,7 @@ namespace nadena.dev.modular_avatar.core
 
         private bool wasActive = false;
         private bool redoBoneMappings = true;
+        private bool hasRelevantBones = false;
         private int lastRecreateHierarchyIndex = -1;
 
         internal Dictionary<Transform, Transform> BoneMappings = new Dictionary<Transform, Transform>(
@@ -119,11 +119,16 @@ namespace nadena.dev.modular_avatar.core
                 ClearHooks();
             }
 
+            if (!hasRelevantBones)
+            {
+                return;
+            }
+            
             if (transform.parent == null)
             {
                 return;
             }
-
+            
 #if UNITY_EDITOR
             AssemblyReloadEvents.beforeAssemblyReload += ClearHooks;
 #endif
@@ -133,6 +138,8 @@ namespace nadena.dev.modular_avatar.core
             proxyObjects[gameObject] = parent;
             originalObjects[parent] = this;
             originalParent[this] = parent;
+
+            CheckBoneUsage(); // register the proxy if needed
         }
 
         private void ClearHooks()
@@ -180,15 +187,13 @@ namespace nadena.dev.modular_avatar.core
             {
                 parentRenderer = transform.parent.GetComponent<SkinnedMeshRenderer>();
             }
-            
-            CameraHooks.RegisterProxy(parentRenderer, myRenderer);
 
             Configure();
-
+            
             myRenderer.sharedMaterials = parentRenderer.sharedMaterials;
-            myRenderer.sharedMesh = parentRenderer.sharedMesh;
             myRenderer.localBounds = parentRenderer.localBounds;
-            if (redoBoneMappings || lastRecreateHierarchyIndex != RecreateHierarchyIndexCount)
+            if (redoBoneMappings || lastRecreateHierarchyIndex != RecreateHierarchyIndexCount
+                                 || myRenderer.sharedMesh != parentRenderer.sharedMesh)
             {
                 CleanDeadObjects(BoneMappings);
 
@@ -200,12 +205,17 @@ namespace nadena.dev.modular_avatar.core
                     #endif
                 }
 
+                myRenderer.sharedMesh = parentRenderer.sharedMesh;
                 myRenderer.rootBone = MapBone(parentRenderer.rootBone);
                 myRenderer.bones = parentRenderer.bones.Select(MapBone).ToArray();
                 redoBoneMappings = false;
                 lastRecreateHierarchyIndex = RecreateHierarchyIndexCount;
+
+                CheckBoneUsage();
             }
 
+            if (!hasRelevantBones) return;
+
             myRenderer.quality = parentRenderer.quality;
             myRenderer.shadowCastingMode = parentRenderer.shadowCastingMode;
             myRenderer.receiveShadows = parentRenderer.receiveShadows;
@@ -225,8 +235,38 @@ namespace nadena.dev.modular_avatar.core
                 }
             }
         }
-
 #endif
+        private void CheckBoneUsage()
+        {
+            hasRelevantBones = false;
+            if (myRenderer.sharedMesh != null)
+            {
+                var weights = myRenderer.sharedMesh.GetAllBoneWeights();
+                var parentBones = parentRenderer.bones;
+                foreach (var weight in weights)
+                {
+                    if (weight.weight < 0.0001f) continue;
+                    if (weight.boneIndex < 0 || weight.boneIndex >= parentBones.Length) continue;
+
+                    var bone = parentBones[weight.boneIndex];
+                    if (BoneMappings.ContainsKey(bone))
+                    {
+                        hasRelevantBones = true;
+                        break;
+                    }
+                }
+            }
+
+            if (hasRelevantBones)
+            {
+                CameraHooks.RegisterProxy(parentRenderer, myRenderer);
+            }
+            else
+            {
+                CameraHooks.UnregisterProxy(parentRenderer);
+                myRenderer.enabled = false;
+            }
+        }
 
         public void ClearBoneCache()
         {