From ea826146e60b2d6f74d37d993f6e8eb2239295d9 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 17 Apr 2025 19:23:33 +0900 Subject: [PATCH] =?UTF-8?q?node=20rename=20=E4=BD=9C=E3=82=8A=E7=9B=B4?= =?UTF-8?q?=E3=81=97=E3=80=82parse=20=E7=B5=82=E4=BA=86=E6=99=82=E3=81=AB?= =?UTF-8?q?=20rename=20=E3=81=8C=E5=AE=8C=E4=BA=86=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=82=8B=E6=96=B9=E3=81=8C=E3=82=88=E3=81=84=E3=80=82?= =?UTF-8?q?=20vrm-0.x,=20vrm-1.0,=20vrma=20=E3=81=AB=E5=AF=BE=E3=81=97?= =?UTF-8?q?=E3=81=A6=E5=AE=9F=E8=A3=85=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/Utils/ForceTransformUniqueName.cs | 80 +++++++++++++------ Assets/VRM/Runtime/IO/VRMData.cs | 25 +++++- .../ScriptedImporter/VrmaScriptedImporter.cs | 29 ++++--- .../VrmAnimationInstance/Vrm10PoseLoader.cs | 3 +- Assets/VRM10/Runtime/IO/Vrm10Data.cs | 21 +++++ Assets/VRM10/Runtime/IO/VrmAnimationData.cs | 37 +++++++++ .../VRM10/Runtime/IO/VrmAnimationData.cs.meta | 11 +++ .../VRM10/Runtime/IO/VrmAnimationImporter.cs | 4 +- .../ClothSample/ClothViewer/ClothViewerUI.cs | 3 +- Assets/VRM10_Samples/SimpleVrma/SimpleVrma.cs | 3 +- .../VRM10Viewer/VRM10ViewerController.cs | 3 +- 11 files changed, 173 insertions(+), 46 deletions(-) create mode 100644 Assets/VRM10/Runtime/IO/VrmAnimationData.cs create mode 100644 Assets/VRM10/Runtime/IO/VrmAnimationData.cs.meta diff --git a/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs b/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs index 37032d16a..f5f5ac8bd 100644 --- a/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs +++ b/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs @@ -2,52 +2,70 @@ using System; using System.Collections.Generic; using UnityEngine; + namespace UniGLTF.Utils { public class ForceTransformUniqueName { + public delegate string GetNameFunc(T t); + public delegate void SetNameFunc(T t, string newName); + public delegate string GetLeafNameFunc(T t); + HashSet m_uniqueNameSet = new HashSet(); int m_counter = 1; public static void Process(Transform root) { - var uniqueName = new ForceTransformUniqueName(); var transforms = root.GetComponentsInChildren(); + Process(transforms, + t => t.name, + (t, name) => t.name = name, + (t) => (t.parent != null && t.childCount == 0) ? $"{t.parent.name}-{t.name}" : null); + } + + public static void Process(IReadOnlyList transforms, + GetNameFunc getName, + SetNameFunc setName, + GetLeafNameFunc getLeafName) + { + var uniqueName = new ForceTransformUniqueName(); foreach (var t in transforms) { - uniqueName.RenameIfDupName(t); + uniqueName.RenameIfDupName(t, + getName, + setName, + getLeafName + ); } } - private void DoRename(Transform t, string newName) + public void RenameIfDupName(T t, + GetNameFunc getName, + SetNameFunc setName, + GetLeafNameFunc getLeafName) { - UniGLTFLogger.Warning($"force rename !!: {t.name} => {newName}"); - t.name = newName; - m_uniqueNameSet.Add(newName); - } - - public void RenameIfDupName(Transform t) - { - if (!m_uniqueNameSet.Contains(t.name)) + if (!m_uniqueNameSet.Contains(getName(t))) { - m_uniqueNameSet.Add(t.name); + m_uniqueNameSet.Add(getName(t)); return; } - if (t.parent != null && t.childCount == 0) { - /// AvatarBuilder:BuildHumanAvatar で同名の Transform があるとエラーになる。 - /// - /// AvatarBuilder 'GLTF': Ambiguous Transform '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/neck_1/neck_2/head/ENDSITE' and '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/l_shoulder/l_up_arm/l_low_arm/l_hand/ENDSITE' found in hierarchy for human bone 'Head'. Transform name mapped to a human bone must be unique. - /// UnityEngine.AvatarBuilder:BuildHumanAvatar (UnityEngine.GameObject,UnityEngine.HumanDescription) - /// - /// 主に BVH の EndSite 由来の GameObject 名が重複することへの対策 - /// ex: parent-ENDSITE - var newName = $"{t.parent.name}-{t.name}"; - if (!m_uniqueNameSet.Contains(newName)) + var leafName = getLeafName(t); + if (!string.IsNullOrEmpty(leafName)) { - DoRename(t, newName); - return; + /// AvatarBuilder:BuildHumanAvatar で同名の Transform があるとエラーになる。 + /// + /// AvatarBuilder 'GLTF': Ambiguous Transform '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/neck_1/neck_2/head/ENDSITE' and '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/l_shoulder/l_up_arm/l_low_arm/l_hand/ENDSITE' found in hierarchy for human bone 'Head'. Transform name mapped to a human bone must be unique. + /// UnityEngine.AvatarBuilder:BuildHumanAvatar (UnityEngine.GameObject,UnityEngine.HumanDescription) + /// + /// 主に BVH の EndSite 由来の GameObject 名が重複することへの対策 + /// ex: parent-ENDSITE + if (!m_uniqueNameSet.Contains(leafName)) + { + DoRename(t, getName, setName, leafName); + return; + } } } @@ -55,15 +73,25 @@ namespace UniGLTF.Utils for (int i = 0; i < 100; ++i) { // ex: name.1 - var newName = $"{t.name}{m_counter++}"; + var newName = $"{getName(t)}{m_counter++}"; if (!m_uniqueNameSet.Contains(newName)) { - DoRename(t, newName); + DoRename(t, getName, setName, newName); return; } } throw new NotImplementedException(); } + + private void DoRename(T t, + GetNameFunc getName, + SetNameFunc setName, + string newName) + { + UniGLTFLogger.Warning($"force rename !!: {getName(t)} => {newName}"); + setName(t, newName); + m_uniqueNameSet.Add(newName); + } } } \ No newline at end of file diff --git a/Assets/VRM/Runtime/IO/VRMData.cs b/Assets/VRM/Runtime/IO/VRMData.cs index 763ccde72..e6f4c74b8 100644 --- a/Assets/VRM/Runtime/IO/VRMData.cs +++ b/Assets/VRM/Runtime/IO/VRMData.cs @@ -1,4 +1,7 @@ -using UniGLTF; +using System; +using System.Linq; +using UniGLTF; +using UniGLTF.Utils; namespace VRM { @@ -18,6 +21,26 @@ namespace VRM VrmExtension = vrm; UpdateMigrationFlags(Data.MigrationFlags, VrmExtension.exporterVersion); + + // ヒューマノイド向け + Func getParent = (node) => + { + var index = Data.GLTF.nodes.IndexOf(node); + return Data.GLTF.nodes.FirstOrDefault(x => x.children != null && x.children.Contains(index)); + }; + + ForceTransformUniqueName.Process(Data.GLTF.nodes, + node => node.name, + (node, name) => node.name = name, + node => + { + var parent = getParent(node); + if (parent != null && node.children != null && node.children.Length == 0) + { + return $"{parent.name}-{node.name}"; + } + return null; + }); } private static void UpdateMigrationFlags(MigrationFlags migrationFlags, string exportedVrmVersionString) diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs index da1791206..df4680277 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs @@ -39,24 +39,27 @@ namespace UniVRM10 .ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value); using (var data = new AutoGltfFileParser(assetPath).Parse()) - using (var loader = new VrmAnimationImporter(data, extractedObjects)) { - var loaded = loader.Load(); - - loaded.TransferOwnership((k, o) => + var vrmaData = new VrmAnimationData(data); + using (var loader = new VrmAnimationImporter(vrmaData, extractedObjects)) { - context.AddObjectToAsset(k.Name, o); - }); + var loaded = loader.Load(); - var root = loaded.Root; - GameObject.DestroyImmediate(loaded); + loaded.TransferOwnership((k, o) => + { + context.AddObjectToAsset(k.Name, o); + }); - // var vrma = root.GetComponent(); - // context.AddObjectToAsset("__boxman_mesh__", vrma.BoxMan.sharedMesh); - // context.AddObjectToAsset("__boxman_mesh__material__", vrma.BoxMan.sharedMaterial); + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); - context.AddObjectToAsset(root.name, root, AssetIcon); - context.SetMainObject(root); + // var vrma = root.GetComponent(); + // context.AddObjectToAsset("__boxman_mesh__", vrma.BoxMan.sharedMesh); + // context.AddObjectToAsset("__boxman_mesh__material__", vrma.BoxMan.sharedMaterial); + + context.AddObjectToAsset(root.name, root, AssetIcon); + context.SetMainObject(root); + } } } } diff --git a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs index aa9883aa3..7bafc39a9 100644 --- a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs +++ b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10PoseLoader.cs @@ -226,7 +226,8 @@ namespace UniVRM10 new FileSystemStorage("_dummy_root_"), // .gltf file has resource path at file system. new MigrationFlags() ); - using var loader = new VrmAnimationImporter(data); + var vrmaData = new VrmAnimationData(data); + using var loader = new VrmAnimationImporter(vrmaData); var gltfInstance = await loader.LoadAsync(new ImmediateCaller()); var instance = gltfInstance.GetComponentOrThrow(); diff --git a/Assets/VRM10/Runtime/IO/Vrm10Data.cs b/Assets/VRM10/Runtime/IO/Vrm10Data.cs index 1a14449ca..679dd100c 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Data.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Data.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using UniGLTF; using UniGLTF.Extensions.VRMC_vrm; +using UniGLTF.Utils; using UniJSON; using UnityEngine; @@ -17,6 +18,26 @@ namespace UniVRM10 { Data = data; VrmExtension = vrm; + + // ヒューマノイド向け + Func getParent = (node) => + { + var index = Data.GLTF.nodes.IndexOf(node); + return Data.GLTF.nodes.FirstOrDefault(x => x.children != null && x.children.Contains(index)); + }; + + ForceTransformUniqueName.Process(Data.GLTF.nodes, + node => node.name, + (node, name) => node.name = name, + node => + { + var parent = getParent(node); + if (parent != null && node.children != null && node.children.Length == 0) + { + return $"{parent.name}-{node.name}"; + } + return null; + }); } /// diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationData.cs b/Assets/VRM10/Runtime/IO/VrmAnimationData.cs new file mode 100644 index 000000000..f689faf0b --- /dev/null +++ b/Assets/VRM10/Runtime/IO/VrmAnimationData.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using UniGLTF; +using UniGLTF.Utils; + +namespace UniVRM10 +{ + public class VrmAnimationData + { + public GltfData Data { get; } + + public VrmAnimationData(GltfData data) + { + Data = data; + + // ヒューマノイド向け + Func getParent = (node) => + { + var index = Data.GLTF.nodes.IndexOf(node); + return Data.GLTF.nodes.FirstOrDefault(x => x.children != null && x.children.Contains(index)); + }; + + ForceTransformUniqueName.Process(Data.GLTF.nodes, + node => node.name, + (node, name) => node.name = name, + node => + { + var parent = getParent(node); + if (parent != null && node.children != null && node.children.Length == 0) + { + return $"{parent.name}-{node.name}"; + } + return null; + }); + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationData.cs.meta b/Assets/VRM10/Runtime/IO/VrmAnimationData.cs.meta new file mode 100644 index 000000000..ee9ea0fce --- /dev/null +++ b/Assets/VRM10/Runtime/IO/VrmAnimationData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 384f2feacbf53ae4abfb7d291837d48d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs index 152d1d77d..cffee617b 100644 --- a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs +++ b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs @@ -17,11 +17,11 @@ namespace UniVRM10 ExpressionInfo[] m_expressions; Material m_defaultMaterial; - public VrmAnimationImporter(GltfData data, + public VrmAnimationImporter(VrmAnimationData data, IReadOnlyDictionary externalObjectMap = null, ITextureDeserializer textureDeserializer = null, IMaterialDescriptorGenerator materialGenerator = null) - : base(data, externalObjectMap, textureDeserializer, materialGenerator, new ImporterContextSettings(invertAxis: Axes.X)) + : base(data.Data, externalObjectMap, textureDeserializer, materialGenerator, new ImporterContextSettings(invertAxis: Axes.X)) { m_vrma = GetExtension(Data); } diff --git a/Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs b/Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs index a71347aa4..7e7744cbc 100644 --- a/Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs +++ b/Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs @@ -279,7 +279,8 @@ namespace UniVRM10.Cloth.Viewer // gltf, glb etc... using GltfData data = new AutoGltfFileParser(path).Parse(); - using var loader = new VrmAnimationImporter(data); + var vrmaData = new VrmAnimationData(data); + using var loader = new VrmAnimationImporter(vrmaData); var instance = await loader.LoadAsync(new ImmediateCaller()); Motion = instance.GetComponent(); instance.GetComponent().Play(); diff --git a/Assets/VRM10_Samples/SimpleVrma/SimpleVrma.cs b/Assets/VRM10_Samples/SimpleVrma/SimpleVrma.cs index 9d40e48b5..dcd4660e0 100644 --- a/Assets/VRM10_Samples/SimpleVrma/SimpleVrma.cs +++ b/Assets/VRM10_Samples/SimpleVrma/SimpleVrma.cs @@ -54,7 +54,8 @@ public class SimpleVrma : MonoBehaviour { // load vrma using GltfData data = new AutoGltfFileParser(path).Parse(); - using var loader = new VrmAnimationImporter(data); + var vrmaData = new VrmAnimationData(data); + using var loader = new VrmAnimationImporter(vrmaData); var instance = await loader.LoadAsync(new ImmediateCaller()); Vrma = instance.GetComponent(); diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerController.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerController.cs index 63bfe36ff..067fe204b 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerController.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerController.cs @@ -192,7 +192,8 @@ namespace UniVRM10.VRM10Viewer // gltf, glb etc... using GltfData data = new AutoGltfFileParser(path).Parse(); - using var loader = new VrmAnimationImporter(data); + var vrmaData = new VrmAnimationData(data); + using var loader = new VrmAnimationImporter(vrmaData); var instance = await loader.LoadAsync(new ImmediateCaller()); Motion = instance.GetComponent(); instance.GetComponent().Play();