diff --git a/Assets/Scripts/Commands/BreakModelApartCommand.cs b/Assets/Scripts/Commands/BreakModelApartCommand.cs index 0ee683fde4..19f5e49bbe 100644 --- a/Assets/Scripts/Commands/BreakModelApartCommand.cs +++ b/Assets/Scripts/Commands/BreakModelApartCommand.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using System.Linq; +using System.Text; using UnityEngine; namespace TiltBrush @@ -167,13 +168,16 @@ public BreakModelApartCommand(ModelWidget initialWidget, BaseCommand parent = nu private static string GetHierarchyPath(Transform root, Transform obj) { - string path = "/" + obj.name; + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Insert(0, "/" + obj.name); + while (obj.transform.parent != root) { obj = obj.transform.parent; - path = "/" + obj.name + path; + stringBuilder.Insert(0, "/" + obj.name); } - return path; + + return stringBuilder.ToString(); } protected override void OnRedo() diff --git a/Assets/Scripts/Model.cs b/Assets/Scripts/Model.cs index 38a7d8b19a..f6537790e0 100644 --- a/Assets/Scripts/Model.cs +++ b/Assets/Scripts/Model.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Threading.Tasks; using TiltBrushToolkit; +using Unity.Profiling; using Unity.VectorGraphics; using Debug = UnityEngine.Debug; using UObject = UnityEngine.Object; @@ -857,11 +858,44 @@ public void EndCreatePrefab(GameObject go, List warnings) } m_ModelParent = go.transform; +#if DEVELOPMENT_BUILD || UNITY_EDITOR + ProfilerMarker generateUniqueNamesPerfMarker = new ProfilerMarker("Model.GenerateUniqueNames"); + generateUniqueNamesPerfMarker.Begin(); +#endif + + GenerateUniqueNames(m_ModelParent); + +#if DEVELOPMENT_BUILD || UNITY_EDITOR + generateUniqueNamesPerfMarker.End(); +#endif + // !!! Add to material dictionary here? m_Valid = true; DisplayWarnings(warnings); + } + + + // This method is called when the model has been loaded and the node tree is available + // This method is necessary because (1) nodes in e.g glTF files don't need to have unique names + // and (2) there's code in at least ModelWidget that searches for specific nodes using node names + private static void GenerateUniqueNames(Transform rootNode) + { + void SetUniqueNameForNode(Transform node) + { + // GetInstanceID returns a unique ID for every GameObject during a runtime session + node.name += " uid: " + node.gameObject.GetInstanceID(); + + foreach (Transform child in node) + { + SetUniqueNameForNode(child); + } + } + foreach (Transform child in rootNode) + { + SetUniqueNameForNode(child); + } } public void UnloadModel() diff --git a/Assets/Scripts/Widgets/ModelWidget.cs b/Assets/Scripts/Widgets/ModelWidget.cs index c8c74ef424..b44b9cf956 100644 --- a/Assets/Scripts/Widgets/ModelWidget.cs +++ b/Assets/Scripts/Widgets/ModelWidget.cs @@ -13,6 +13,7 @@ // limitations under the License. using System; +using System.Collections.Generic; using UnityEngine; using System.Linq; using System.Threading.Tasks; @@ -29,6 +30,18 @@ public class ModelWidget : MediaWidget [SerializeField] private float m_MaxBloat; private Model m_Model; + + + // What is Subtree? + // e.g. if we have 3d model with 3 chairs with the hierarchy below, + // then when the model is broken apart, we create a separate ModelWidget for each Chair1,Chair2,Chair3 + // e.g for Chair1, Subtree = "Root/Chair1" + /* + Root (empty node) + Chair1 (mesh) + Chair2 (mesh) + Chair3 (mesh) + */ private string m_Subtree; public string Subtree { @@ -322,6 +335,9 @@ public bool HasSubModels() return false; } + // Update the transform hierarchy of this ModelWidget to only contain m_Subtree + // e.g if Subtree = "CarBody/Floor/Wheel1", then this method will update the transform hierarchy to contain nodes + // starting at CarBody/Floor/Wheel1 public void SyncHierarchyToSubtree(string previousSubtree = null) { if (string.IsNullOrEmpty(Subtree)) return; @@ -355,9 +371,9 @@ public void SyncHierarchyToSubtree(string previousSubtree = null) bool excludeChildren = false; if (subpathToTraverse.EndsWith(".mesh")) { - subpathToTraverse = subpathToTraverse.Substring(0, subpathToTraverse.Length - 5); + subpathToTraverse = subpathToTraverse.Substring(0, subpathToTraverse.Length - ".mesh".Length); excludeChildren = true; - } + } if (node.name == subpathToTraverse) { // We're already at the right node @@ -366,7 +382,7 @@ public void SyncHierarchyToSubtree(string previousSubtree = null) } else { - // node will be null if not found + // - node will be null if not found node = node.Find(subpathToTraverse); }