node rename 作り直し。parse 終了時に rename が完了している方がよい。

vrm-0.x, vrm-1.0, vrma に対して実装した。
This commit is contained in:
ousttrue
2025-04-17 19:23:33 +09:00
parent f7c782f1f2
commit ea826146e6
11 changed files with 173 additions and 46 deletions

View File

@@ -2,52 +2,70 @@ using System;
using System.Collections.Generic;
using UnityEngine;
namespace UniGLTF.Utils
{
public class ForceTransformUniqueName
{
public delegate string GetNameFunc<T>(T t);
public delegate void SetNameFunc<T>(T t, string newName);
public delegate string GetLeafNameFunc<T>(T t);
HashSet<string> m_uniqueNameSet = new HashSet<string>();
int m_counter = 1;
public static void Process(Transform root)
{
var uniqueName = new ForceTransformUniqueName();
var transforms = root.GetComponentsInChildren<Transform>();
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<T>(IReadOnlyList<T> transforms,
GetNameFunc<T> getName,
SetNameFunc<T> setName,
GetLeafNameFunc<T> 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 t,
GetNameFunc<T> getName,
SetNameFunc<T> setName,
GetLeafNameFunc<T> 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 t,
GetNameFunc<T> getName,
SetNameFunc<T> setName,
string newName)
{
UniGLTFLogger.Warning($"force rename !!: {getName(t)} => {newName}");
setName(t, newName);
m_uniqueNameSet.Add(newName);
}
}
}

View File

@@ -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<glTFNode, glTFNode> 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)

View File

@@ -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<Vrm10AnimationInstance>();
// 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<Vrm10AnimationInstance>();
// context.AddObjectToAsset("__boxman_mesh__", vrma.BoxMan.sharedMesh);
// context.AddObjectToAsset("__boxman_mesh__material__", vrma.BoxMan.sharedMaterial);
context.AddObjectToAsset(root.name, root, AssetIcon);
context.SetMainObject(root);
}
}
}
}

View File

@@ -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<Vrm10AnimationInstance>();

View File

@@ -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<glTFNode, glTFNode> 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;
});
}
/// <summary>

View File

@@ -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<glTFNode, glTFNode> 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;
});
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 384f2feacbf53ae4abfb7d291837d48d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -17,11 +17,11 @@ namespace UniVRM10
ExpressionInfo[] m_expressions;
Material m_defaultMaterial;
public VrmAnimationImporter(GltfData data,
public VrmAnimationImporter(VrmAnimationData data,
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> 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);
}

View File

@@ -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<Vrm10AnimationInstance>();
instance.GetComponent<Animation>().Play();

View File

@@ -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<Vrm10AnimationInstance>();

View File

@@ -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<Vrm10AnimationInstance>();
instance.GetComponent<Animation>().Play();