From b0ebebdfca3c8cadad45c45769f340d4ab1645a0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 20 Aug 2025 15:55:13 +0900 Subject: [PATCH 1/4] add FixZBlendShapeNameUnique --- .../UniGLTF/IO/Parser/GlbLowLevelParser.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index c1b8798d9..b1668959a 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -83,6 +83,7 @@ namespace UniGLTF RestoreOlderVersionValues(json, GLTF); FixMeshNameUnique(GLTF); + FixBlendShapeNameUnique(GLTF); foreach (var image in GLTF.images) { image.uri = PrepareUri(image.uri); @@ -121,6 +122,44 @@ namespace UniGLTF } } + // https://github.com/vrm-c/UniVRM/issues/2619 + private static void FixBlendShapeNameUnique(glTF GLTF) + { + foreach (var mesh in GLTF.meshes) + { + /// https://github.com/KhronosGroup/glTF/pull/1631/files + if (gltf_mesh_extras_targetNames.TryGet(mesh, out var targetNames)) + { + var used = new HashSet(); + int rename = 0; + for (int i = 0; i < targetNames.Count; ++i) + { + var target_name = targetNames[i]; + if (string.IsNullOrEmpty(target_name)) + { + // no name + targetNames[i] = $"__{i}__"; + UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {target_name[i]}"); + rename += 1; + } + else if (used.Contains(target_name)) + { + // rename + var uname = $"__{i}__{target_name}"; + targetNames[i] = uname; + UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {target_name[i]}"); + rename += 1; + } + used.Add(targetNames[i]); + } + if (rename > 0) + { + gltf_mesh_extras_targetNames.Serialize(mesh, targetNames, BlendShapeTargetNameLocationFlags.Mesh); + } + } + } + } + private static void RenameImageFromTexture(glTF GLTF, int i) { foreach (var texture in GLTF.textures) From 81abd951d7f4aa1511cfc2a2b81853659071e3b0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 21 Aug 2025 14:43:08 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E5=8B=95=E7=A2=BA=20unittest=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ベースにした glTF https://github.com/KhronosGroup/glTF-Tutorials/blob/main/gltfTutorial/gltfTutorial_017_SimpleMorphTarget.md --- .../UniGLTF/IO/Parser/GlbLowLevelParser.cs | 24 ++- .../Runtime/UniJSON/Json/JsonParser.cs | 2 +- Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs | 98 +++++++++ .../gltfTutorial_017_SimpleMorphTarget.txt | 198 ++++++++++++++++++ ...ltfTutorial_017_SimpleMorphTarget.txt.meta | 7 + 5 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt create mode 100644 Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt.meta diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index b1668959a..6f1061cd0 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -139,7 +139,7 @@ namespace UniGLTF { // no name targetNames[i] = $"__{i}__"; - UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {target_name[i]}"); + UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {targetNames[i]}"); rename += 1; } else if (used.Contains(target_name)) @@ -147,14 +147,32 @@ namespace UniGLTF // rename var uname = $"__{i}__{target_name}"; targetNames[i] = uname; - UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {target_name[i]}"); + UniGLTFLogger.Log($"rename blendshape: {mesh.name}[{i}]{target_name} => {targetNames[i]}"); rename += 1; } used.Add(targetNames[i]); } if (rename > 0) { - gltf_mesh_extras_targetNames.Serialize(mesh, targetNames, BlendShapeTargetNameLocationFlags.Mesh); + + // var extrans = new Dictionary() + // { + // {"targetNames", targetNames }, + // }; + var f = new JsonFormatter(); + f.BeginMap(); + f.Key("targetNames"); + { + f.BeginList(); + foreach (var name in targetNames) + { + f.Value(name); + } + f.EndList(); + } + f.EndMap(); + var json = f.ToString(); + mesh.extras = new UniGLTF.glTFExtensionImport(JsonParser.Parse(json)); } } } diff --git a/Assets/UniGLTF/Runtime/UniJSON/Json/JsonParser.cs b/Assets/UniGLTF/Runtime/UniJSON/Json/JsonParser.cs index a43262214..1da036317 100644 --- a/Assets/UniGLTF/Runtime/UniJSON/Json/JsonParser.cs +++ b/Assets/UniGLTF/Runtime/UniJSON/Json/JsonParser.cs @@ -53,7 +53,7 @@ namespace UniJSON } default: - throw new ParserException(segment + " is not valid json start"); + throw new ParserException(segment + " is not valid json start(maybe invalid ',')"); } } diff --git a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs index 58e0f7e76..57d427c97 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs @@ -233,5 +233,103 @@ namespace UniGLTF } } } + + // https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_017_SimpleMorphTarget.html + [Test] + public void Preprocess_AutoNodeName() + { + var json = @" +{ + ""scene"": 0, + ""scenes"" : [ + { + ""nodes"" : [ 0 ] + } + ], + + ""nodes"" : [ + { + ""mesh"" : 0 + } + ], + + ""meshes"" : [ + { + ""primitives"" : [ { + ""attributes"" : { + ""POSITION"" : 1 + }, + ""indices"" : 0 + } ] + } + ], + + ""buffers"" : [ + { + ""uri"" : ""data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA="", + ""byteLength"" : 44 + } + ], + ""bufferViews"" : [ + { + ""buffer"" : 0, + ""byteOffset"" : 0, + ""byteLength"" : 6, + ""target"" : 34963 + }, + { + ""buffer"" : 0, + ""byteOffset"" : 8, + ""byteLength"" : 36, + ""target"" : 34962 + } + ], + ""accessors"" : [ + { + ""bufferView"" : 0, + ""byteOffset"" : 0, + ""componentType"" : 5123, + ""count"" : 3, + ""type"" : ""SCALAR"", + ""max"" : [ 2 ], + ""min"" : [ 0 ] + }, + { + ""bufferView"" : 1, + ""byteOffset"" : 0, + ""componentType"" : 5126, + ""count"" : 3, + ""type"" : ""VEC3"", + ""max"" : [ 1.0, 1.0, 0.0 ], + ""min"" : [ 0.0, 0.0, 0.0 ] + } + ], + + ""asset"" : { + ""version"" : ""2.0"" + } +} + "; + + var gltf = GlbLowLevelParser.ParseGltf("tmp", json, null, null, default); + Assert.AreEqual(1, gltf.GLTF.nodes.Count); + Assert.AreEqual("0", gltf.GLTF.nodes[0].name); + } + + // https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_017_SimpleMorphTarget.html + [Test] + public void Preprocess_DupMophTargetName() + { + var asset = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt"); + Assert.True(asset); + var gltf = GlbLowLevelParser.ParseGltf("tmp", asset.text, null, null, default); + Assert.AreEqual(1, gltf.GLTF.nodes.Count); + Assert.AreEqual("0", gltf.GLTF.nodes[0].name); + Assert.True(gltf_mesh_extras_targetNames.TryGet(gltf.GLTF.meshes[0], out List targetNames)); + // [dup_name, dup_name] => [dup_name, __1__dup_name] + Assert.AreEqual(2, targetNames.Count); + Assert.AreEqual("dup_name", targetNames[0]); + Assert.AreEqual("__1__dup_name", targetNames[1]); + } } } diff --git a/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt b/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt new file mode 100644 index 000000000..93654b4df --- /dev/null +++ b/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt @@ -0,0 +1,198 @@ +{ + "scene": 0, + "scenes":[ + { + "nodes":[ + 0 + ] + } + ], + "nodes":[ + { + "mesh":0 + } + ], + "meshes":[ + { + "primitives":[ + { + "attributes":{ + "POSITION":1 + }, + "targets":[ + { + "POSITION":2 + }, + { + "POSITION":3 + } + ], + "indices":0 + } + ], + "weights":[ + 1.0, + 0.5 + ], + "extras":{ + "targetNames": [ + "dup_name", + "dup_name" + ] + } + } + ], + + "animations":[ + { + "samplers":[ + { + "input":4, + "interpolation":"LINEAR", + "output":5 + } + ], + "channels":[ + { + "sampler":0, + "target":{ + "node":0, + "path":"weights" + } + } + ] + } + ], + + "buffers":[ + { + "uri":"data:application/gltf-buffer;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAAAA=", + "byteLength":116 + }, + { + "uri":"data:application/gltf-buffer;base64,AAAAAAAAgD8AAABAAABAQAAAgEAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAA", + "byteLength":60 + } + ], + "bufferViews":[ + { + "buffer":0, + "byteOffset":0, + "byteLength":6, + "target":34963 + }, + { + "buffer":0, + "byteOffset":8, + "byteLength":108, + "byteStride":12, + "target":34962 + }, + { + "buffer":1, + "byteOffset":0, + "byteLength":20 + }, + { + "buffer":1, + "byteOffset":20, + "byteLength":40 + } + ], + "accessors":[ + { + "bufferView":0, + "byteOffset":0, + "componentType":5123, + "count":3, + "type":"SCALAR", + "max":[ + 2 + ], + "min":[ + 0 + ] + }, + { + "bufferView":1, + "byteOffset":0, + "componentType":5126, + "count":3, + "type":"VEC3", + "max":[ + 1.0, + 0.5, + 0.0 + ], + "min":[ + 0.0, + 0.0, + 0.0 + ] + }, + { + "bufferView":1, + "byteOffset":36, + "componentType":5126, + "count":3, + "type":"VEC3", + "max":[ + 0.0, + 1.0, + 0.0 + ], + "min":[ + -1.0, + 0.0, + 0.0 + ] + }, + { + "bufferView":1, + "byteOffset":72, + "componentType":5126, + "count":3, + "type":"VEC3", + "max":[ + 1.0, + 1.0, + 0.0 + ], + "min":[ + 0.0, + 0.0, + 0.0 + ] + }, + { + "bufferView":2, + "byteOffset":0, + "componentType":5126, + "count":5, + "type":"SCALAR", + "max":[ + 4.0 + ], + "min":[ + 0.0 + ] + }, + { + "bufferView":3, + "byteOffset":0, + "componentType":5126, + "count":10, + "type":"SCALAR", + "max":[ + 1.0 + ], + "min":[ + 0.0 + ] + } + ], + + "asset":{ + "version":"2.0" + } +} diff --git a/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt.meta b/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt.meta new file mode 100644 index 000000000..fae89f1c0 --- /dev/null +++ b/Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff5b21eda4deae14583275d904ae3d08 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 820d46758f6d6f080d5308c29ca874e559d826d1 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 21 Aug 2025 16:55:54 +0900 Subject: [PATCH 3/4] Update Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index 6f1061cd0..2207bc6cd 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -158,7 +158,6 @@ namespace UniGLTF // var extrans = new Dictionary() // { // {"targetNames", targetNames }, - // }; var f = new JsonFormatter(); f.BeginMap(); f.Key("targetNames"); From 2759669c67e84b130797186b87e5e104d7468e1e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 21 Aug 2025 16:55:59 +0900 Subject: [PATCH 4/4] Update Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs index 57d427c97..e9d7aa201 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/GltfLoadTests.cs @@ -318,7 +318,7 @@ namespace UniGLTF // https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_017_SimpleMorphTarget.html [Test] - public void Preprocess_DupMophTargetName() + public void Preprocess_DupMorphTargetName() { var asset = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/UniGLTF/Tests/UniGLTF/gltfTutorial_017_SimpleMorphTarget.txt"); Assert.True(asset);