From 744221f847fcccc0ae3c5b4db77a6b4455537b40 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 27 Oct 2021 22:00:31 +0900 Subject: [PATCH 1/4] Add MigrationVrmExpression.Check --- .../VRM10/Runtime/Migration/MigrationVrm.cs | 3 +- .../Migration/MigrationVrmExpression.cs | 84 +++++++++++++++++++ Assets/VRM10/Tests/MigrationTests.cs | 15 +++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index 3e736a4a4..5f0d7472e 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -119,10 +119,11 @@ namespace UniVRM10 return Glb.Create(vrm1Json, bin).ToBytes(); } - public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1) + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1, Func MeshToNode) { MigrationVrmMeta.Check(vrm0["meta"], vrm1.Meta); MigrationVrmHumanoid.Check(vrm0["humanoid"], vrm1.Humanoid); + MigrationVrmExpression.Check(vrm0["blendShapeMaster"], vrm1.Expressions, MeshToNode); } public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs index 427bb1cbe..ffe0d5d7e 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -221,5 +221,89 @@ namespace UniVRM10 yield return (preset, name, expression); } } + + static void Check(string name, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expression vrm1, Func MeshToNode) + { + if (vrm0["binds"].GetArrayCount() == 0) + { + if (vrm1.MorphTargetBinds == null) + { + // OK + return; + } + else + { + throw new MigrationException($"expression.{name}.binds", "different count"); + } + } + + foreach (var (l, r) in Enumerable.Zip(vrm0["binds"].ArrayItems(), vrm1.MorphTargetBinds, (x, y) => (x, y))) + { + var mesh = l["mesh"].GetInt32(); + var node = MeshToNode(mesh); + if (node != r.Node) + { + throw new MigrationException($"expression.{name}.binds.node", $"{node} != {r.Node}"); + } + + var index = l["index"].GetInt32(); + if (index != r.Index) + { + throw new MigrationException($"expression.{name}.binds.index", $"{index} != {r.Index}"); + } + + var weight = l["weight"].GetSingle(); + if (weight != r.Weight) + { + throw new MigrationException($"expression.{name}.binds.weight", $"{weight} != {r.Weight}"); + } + } + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expressions vrm1, Func MeshToNode) + { + foreach (var blendShape in vrm0["blendShapeGroups"].ArrayItems()) + { + Debug.Log($"{blendShape}"); + var name = blendShape["presetName"].GetString().ToLower(); + switch (name) + { + case "a": Check(name, blendShape, vrm1.Preset.Aa, MeshToNode); break; + case "i": Check(name, blendShape, vrm1.Preset.Ih, MeshToNode); break; + case "u": Check(name, blendShape, vrm1.Preset.Ou, MeshToNode); break; + case "e": Check(name, blendShape, vrm1.Preset.Ee, MeshToNode); break; + case "o": Check(name, blendShape, vrm1.Preset.Oh, MeshToNode); break; + case "blink": Check(name, blendShape, vrm1.Preset.Blink, MeshToNode); break; + case "joy": Check(name, blendShape, vrm1.Preset.Happy, MeshToNode); break; + case "angry": Check(name, blendShape, vrm1.Preset.Angry, MeshToNode); break; + case "sorrow": Check(name, blendShape, vrm1.Preset.Sad, MeshToNode); break; + case "fun": Check(name, blendShape, vrm1.Preset.Relaxed, MeshToNode); break; + case "lookup": Check(name, blendShape, vrm1.Preset.LookUp, MeshToNode); break; + case "lookdown": Check(name, blendShape, vrm1.Preset.LookDown, MeshToNode); break; + case "lookleft": Check(name, blendShape, vrm1.Preset.LookLeft, MeshToNode); break; + case "lookright": Check(name, blendShape, vrm1.Preset.LookRight, MeshToNode); break; + case "blink_l": Check(name, blendShape, vrm1.Preset.BlinkLeft, MeshToNode); break; + case "blink_r": Check(name, blendShape, vrm1.Preset.BlinkRight, MeshToNode); break; + default: + { + string found = default; + foreach (var kv in vrm1.Custom) + { + if (kv.Key.ToLower() == name) + { + Check(name, blendShape, kv.Value, MeshToNode); + found = kv.Key; + break; + } + } + if (found == null) + { + throw new MigrationException(name, $"expression not migrated"); + } + break; + } + } + } + } } } diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index d06b496a2..8a68cbfe8 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -54,8 +54,21 @@ namespace UniVRM10 var json = glb.Json.Bytes.ParseAsJson(); var gltf = UniGLTF.GltfDeserializer.Deserialize(json); + Func meshToNode = (int mesh) => + { + for (int i = 0; i < gltf.nodes.Count; ++i) + { + var node = gltf.nodes[i]; + if (node.mesh == mesh) + { + return i; + } + } + throw new KeyNotFoundException(); + }; + MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8, - UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize)); + UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), meshToNode); MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.ExtensionNameUtf8, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes); } From 71f1eb32b007cadef6b4cb2fd0219c9aff611531 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 27 Oct 2021 22:02:32 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BB=A3=E5=85=A5=E6=BC=8F=E3=82=8C?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs index ffe0d5d7e..a65656b3a 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -68,6 +68,7 @@ namespace UniVRM10 Debug.LogWarning($"[MigrationVrmExpression] node.mesh == {meshIndex} index"); continue; } + bind.Node = nodeIndex; bind.Index = morphTargetIndex; // https://github.com/vrm-c/vrm-specification/issues/209 bind.Weight = weight * 0.01f; From bfb4e74489c2f2a756ee75683fcf2729fb059256 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 27 Oct 2021 22:05:30 +0900 Subject: [PATCH 3/4] fix test --- Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs index a65656b3a..6bf153a6a 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -253,7 +253,7 @@ namespace UniVRM10 throw new MigrationException($"expression.{name}.binds.index", $"{index} != {r.Index}"); } - var weight = l["weight"].GetSingle(); + var weight = l["weight"].GetSingle() * 0.01f; // [0, 100] to [0, 1.0f] if (weight != r.Weight) { throw new MigrationException($"expression.{name}.binds.weight", $"{weight} != {r.Weight}"); @@ -265,7 +265,6 @@ namespace UniVRM10 { foreach (var blendShape in vrm0["blendShapeGroups"].ArrayItems()) { - Debug.Log($"{blendShape}"); var name = blendShape["presetName"].GetString().ToLower(); switch (name) { From 3ba9d1cc7ccc4e35e8ef29d5a4645eecdf88747a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 28 Oct 2021 14:58:03 +0900 Subject: [PATCH 4/4] Func to delegage int MeshIndexToNodeIndexFunc(int meshIndex) --- .../VRM10/Runtime/Migration/MigrationVrm.cs | 26 +++++++- .../Migration/MigrationVrmExpression.cs | 61 +++++++++---------- Assets/VRM10/Tests/MigrationTests.cs | 15 +---- 3 files changed, 53 insertions(+), 49 deletions(-) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index 5f0d7472e..079cd30c4 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -42,6 +42,8 @@ namespace UniVRM10 static byte[] MigrateVrm(glTF gltf, ArraySegment bin, JsonNode vrm0) { + var meshToNode = CreateMeshToNode(gltf); + { // vrm var vrm1 = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm(); @@ -59,7 +61,7 @@ namespace UniVRM10 Preset = new UniGLTF.Extensions.VRMC_vrm.Preset(), Custom = new Dictionary(), }; - foreach (var (preset, customName, expression) in MigrationVrmExpression.Migrate(gltf, vrm0BlendShape)) + foreach (var (preset, customName, expression) in MigrationVrmExpression.Migrate(gltf, vrm0BlendShape, meshToNode)) { switch (preset) { @@ -119,11 +121,29 @@ namespace UniVRM10 return Glb.Create(vrm1Json, bin).ToBytes(); } - public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1, Func MeshToNode) + public delegate int MeshIndexToNodeIndexFunc(int meshIndex); + + public static MeshIndexToNodeIndexFunc CreateMeshToNode(UniGLTF.glTF gltf) + { + return (int mesh) => + { + for (int i = 0; i < gltf.nodes.Count; ++i) + { + var node = gltf.nodes[i]; + if (node.mesh == mesh) + { + return i; + } + } + return -1; + }; + } + + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1, MeshIndexToNodeIndexFunc meshToNode) { MigrationVrmMeta.Check(vrm0["meta"], vrm1.Meta); MigrationVrmHumanoid.Check(vrm0["humanoid"], vrm1.Humanoid); - MigrationVrmExpression.Check(vrm0["blendShapeMaster"], vrm1.Expressions, MeshToNode); + MigrationVrmExpression.Check(vrm0["blendShapeMaster"], vrm1.Expressions, meshToNode); } public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs index 6bf153a6a..b0eb44603 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -42,7 +42,8 @@ namespace UniVRM10 throw new NotImplementedException(); } - static IEnumerable ToMorphTargetBinds(UniGLTF.glTF gltf, JsonNode json) + static IEnumerable ToMorphTargetBinds(JsonNode json, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) { foreach (var x in json.ArrayItems()) { @@ -54,18 +55,11 @@ namespace UniVRM10 // https://github.com/vrm-c/vrm-specification/pull/106 // https://github.com/vrm-c/vrm-specification/pull/153 - var node = gltf.nodes.FirstOrDefault(y => y.mesh == meshIndex); - if (node == null) - { - // invalid data. skip - Debug.LogWarning($"[MigrationVrmExpression] node.mesh == {meshIndex} is not found"); - continue; - } - var nodeIndex = gltf.nodes.IndexOf(node); + var nodeIndex = meshToNode(meshIndex); if (nodeIndex == -1) { // invalid data. skip - Debug.LogWarning($"[MigrationVrmExpression] node.mesh == {meshIndex} index"); + Debug.LogWarning($"[MigrationVrmExpression] node.mesh == {meshIndex} not found"); continue; } bind.Node = nodeIndex; @@ -194,7 +188,8 @@ namespace UniVRM10 } } - public static IEnumerable<(ExpressionPreset, string, UniGLTF.Extensions.VRMC_vrm.Expression)> Migrate(UniGLTF.glTF gltf, JsonNode json) + public static IEnumerable<(ExpressionPreset, string, UniGLTF.Extensions.VRMC_vrm.Expression)> Migrate(UniGLTF.glTF gltf, JsonNode json, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) { foreach (var blendShapeClip in json["blendShapeGroups"].ArrayItems()) { @@ -212,7 +207,7 @@ namespace UniVRM10 MaterialColorBinds = new List(), TextureTransformBinds = new List(), }; - expression.MorphTargetBinds = ToMorphTargetBinds(gltf, blendShapeClip["binds"]).ToList(); + expression.MorphTargetBinds = ToMorphTargetBinds(blendShapeClip["binds"], meshToNode).ToList(); if (blendShapeClip.TryGet("materialValues", out JsonNode materialValues)) { @@ -223,7 +218,8 @@ namespace UniVRM10 } } - static void Check(string name, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expression vrm1, Func MeshToNode) + static void Check(string name, JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expression vrm1, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) { if (vrm0["binds"].GetArrayCount() == 0) { @@ -241,7 +237,7 @@ namespace UniVRM10 foreach (var (l, r) in Enumerable.Zip(vrm0["binds"].ArrayItems(), vrm1.MorphTargetBinds, (x, y) => (x, y))) { var mesh = l["mesh"].GetInt32(); - var node = MeshToNode(mesh); + var node = meshToNode(mesh); if (node != r.Node) { throw new MigrationException($"expression.{name}.binds.node", $"{node} != {r.Node}"); @@ -261,29 +257,30 @@ namespace UniVRM10 } } - public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expressions vrm1, Func MeshToNode) + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Expressions vrm1, + MigrationVrm.MeshIndexToNodeIndexFunc meshToNode) { foreach (var blendShape in vrm0["blendShapeGroups"].ArrayItems()) { var name = blendShape["presetName"].GetString().ToLower(); switch (name) { - case "a": Check(name, blendShape, vrm1.Preset.Aa, MeshToNode); break; - case "i": Check(name, blendShape, vrm1.Preset.Ih, MeshToNode); break; - case "u": Check(name, blendShape, vrm1.Preset.Ou, MeshToNode); break; - case "e": Check(name, blendShape, vrm1.Preset.Ee, MeshToNode); break; - case "o": Check(name, blendShape, vrm1.Preset.Oh, MeshToNode); break; - case "blink": Check(name, blendShape, vrm1.Preset.Blink, MeshToNode); break; - case "joy": Check(name, blendShape, vrm1.Preset.Happy, MeshToNode); break; - case "angry": Check(name, blendShape, vrm1.Preset.Angry, MeshToNode); break; - case "sorrow": Check(name, blendShape, vrm1.Preset.Sad, MeshToNode); break; - case "fun": Check(name, blendShape, vrm1.Preset.Relaxed, MeshToNode); break; - case "lookup": Check(name, blendShape, vrm1.Preset.LookUp, MeshToNode); break; - case "lookdown": Check(name, blendShape, vrm1.Preset.LookDown, MeshToNode); break; - case "lookleft": Check(name, blendShape, vrm1.Preset.LookLeft, MeshToNode); break; - case "lookright": Check(name, blendShape, vrm1.Preset.LookRight, MeshToNode); break; - case "blink_l": Check(name, blendShape, vrm1.Preset.BlinkLeft, MeshToNode); break; - case "blink_r": Check(name, blendShape, vrm1.Preset.BlinkRight, MeshToNode); break; + case "a": Check(name, blendShape, vrm1.Preset.Aa, meshToNode); break; + case "i": Check(name, blendShape, vrm1.Preset.Ih, meshToNode); break; + case "u": Check(name, blendShape, vrm1.Preset.Ou, meshToNode); break; + case "e": Check(name, blendShape, vrm1.Preset.Ee, meshToNode); break; + case "o": Check(name, blendShape, vrm1.Preset.Oh, meshToNode); break; + case "blink": Check(name, blendShape, vrm1.Preset.Blink, meshToNode); break; + case "joy": Check(name, blendShape, vrm1.Preset.Happy, meshToNode); break; + case "angry": Check(name, blendShape, vrm1.Preset.Angry, meshToNode); break; + case "sorrow": Check(name, blendShape, vrm1.Preset.Sad, meshToNode); break; + case "fun": Check(name, blendShape, vrm1.Preset.Relaxed, meshToNode); break; + case "lookup": Check(name, blendShape, vrm1.Preset.LookUp, meshToNode); break; + case "lookdown": Check(name, blendShape, vrm1.Preset.LookDown, meshToNode); break; + case "lookleft": Check(name, blendShape, vrm1.Preset.LookLeft, meshToNode); break; + case "lookright": Check(name, blendShape, vrm1.Preset.LookRight, meshToNode); break; + case "blink_l": Check(name, blendShape, vrm1.Preset.BlinkLeft, meshToNode); break; + case "blink_r": Check(name, blendShape, vrm1.Preset.BlinkRight, meshToNode); break; default: { string found = default; @@ -291,7 +288,7 @@ namespace UniVRM10 { if (kv.Key.ToLower() == name) { - Check(name, blendShape, kv.Value, MeshToNode); + Check(name, blendShape, kv.Value, meshToNode); found = kv.Key; break; } diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index 8a68cbfe8..cc0c44e85 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -54,21 +54,8 @@ namespace UniVRM10 var json = glb.Json.Bytes.ParseAsJson(); var gltf = UniGLTF.GltfDeserializer.Deserialize(json); - Func meshToNode = (int mesh) => - { - for (int i = 0; i < gltf.nodes.Count; ++i) - { - var node = gltf.nodes[i]; - if (node.mesh == mesh) - { - return i; - } - } - throw new KeyNotFoundException(); - }; - MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8, - UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), meshToNode); + UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), MigrationVrm.CreateMeshToNode(gltf)); MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.ExtensionNameUtf8, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes); }