From e2f9f40423426d1d26da917304116b9f1eecf06a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 15:14:38 +0900 Subject: [PATCH 1/8] importer validation --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 87 +++++++++++++++++----- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index 557b51b7d..4c1c9a5d5 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -651,24 +651,27 @@ namespace UniVRM10 if (UniGLTF.Extensions.VRMC_springBone_limit.GltfDeserializer.TryGet(gltfJoint.Extensions as glTFExtension, out var extensionSpringBoneLimit)) { - if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone) + if (VRMC_springBone_limit_Validate(go.transform, extensionSpringBoneLimit)) { - joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone; - joint.m_limitSpaceOffset = QuaternionFromFloat4(cone.Rotation); - joint.m_pitch = cone.Angle.GetValueOrDefault(); - } - else if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) - { - joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge; - joint.m_limitSpaceOffset = QuaternionFromFloat4(hinge.Rotation); - joint.m_pitch = hinge.Angle.GetValueOrDefault(); - } - else if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) - { - joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical; - joint.m_limitSpaceOffset = QuaternionFromFloat4(spherical.Rotation); - joint.m_pitch = spherical.Pitch.GetValueOrDefault(); - joint.m_yaw = spherical.Yaw.GetValueOrDefault(); + if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone) + { + joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone; + joint.m_limitSpaceOffset = QuaternionFromFloat4(cone.Rotation); + joint.m_pitch = cone.Angle.GetValueOrDefault(); + } + else if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) + { + joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge; + joint.m_limitSpaceOffset = QuaternionFromFloat4(hinge.Rotation); + joint.m_pitch = hinge.Angle.GetValueOrDefault(); + } + else if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) + { + joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical; + joint.m_limitSpaceOffset = QuaternionFromFloat4(spherical.Rotation); + joint.m_pitch = spherical.Pitch.GetValueOrDefault(); + joint.m_yaw = spherical.Yaw.GetValueOrDefault(); + } } } @@ -679,6 +682,56 @@ namespace UniVRM10 } } + private static bool VRMC_springBone_limit_Validate(Transform node, VRMC_springBone_limit extensionSpringBoneLimit) + { + var validate = true; + if (extensionSpringBoneLimit.SpecVersion != "1.0-draft") + { + UniGLTFLogger.Warning($"Unknown VRMC_springBone_limit specVersion: {extensionSpringBoneLimit.SpecVersion}"); + } + + var count = 0; + if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone) + { + ++count; + } + else if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) + { + ++count; + } + else if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) + { + ++count; + } + + switch (count) + { + case 0: + // Limit 欠落 + validate = false; + UniGLTFLogger.Warning($"No VRMC_springBone_limit.Limit: skip"); + break; + + case 1: + // ok + break; + + default: + validate = false; + UniGLTFLogger.Warning($"Multiple VRMC_springBone_limit.Limit: skip"); + break; + } + + if (node.childCount == 0) + { + // leaf + UniGLTFLogger.Warning($"VRMC_springBone_limit: Leaf node cannot. skip"); + validate = false; + } + + return validate; + } + private static Quaternion QuaternionFromFloat4(float[] xyzw) { var q = (xyzw != null && xyzw.Length == 4) From 528568b5b4ca153de6d323eecfa443e02d38309b Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 15:20:11 +0900 Subject: [PATCH 2/8] write SpecVersion --- Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 2 ++ Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index fc6724f5d..c9078701f 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -14,6 +14,7 @@ namespace UniVRM10 public const string SPRINGBONE_EXTENDED_COLLIDER_SPEC_VERSION = "1.0"; public const string NODE_CONSTRAINT_SPEC_VERSION = "1.0"; public const string MTOON_SPEC_VERSION = "1.0"; + public const string VRMC_springBone_limit_SPEC_VERSION = "1.0-draft"; public const string LICENSE_URL_JA = "https://vrm.dev/licenses/1.0/"; public const string LICENSE_URL_EN = "https://vrm.dev/licenses/1.0/en/"; @@ -457,6 +458,7 @@ namespace UniVRM10 { var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { + SpecVersion = VRMC_springBone_limit_SPEC_VERSION, Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { Cone = new UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index 4c1c9a5d5..6265a326b 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -685,7 +685,7 @@ namespace UniVRM10 private static bool VRMC_springBone_limit_Validate(Transform node, VRMC_springBone_limit extensionSpringBoneLimit) { var validate = true; - if (extensionSpringBoneLimit.SpecVersion != "1.0-draft") + if (extensionSpringBoneLimit.SpecVersion != Vrm10Exporter.VRMC_springBone_limit_SPEC_VERSION) { UniGLTFLogger.Warning($"Unknown VRMC_springBone_limit specVersion: {extensionSpringBoneLimit.SpecVersion}"); } From f5cfec8ca91daeb33630f81813f0d949c0c243eb Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 15:25:03 +0900 Subject: [PATCH 3/8] check childCount --- Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 94 +++++++++++----------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index c9078701f..4c56105e8 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -452,64 +452,68 @@ namespace UniVRM10 GravityPower = y.m_gravityPower, }; - switch (y.m_anglelimitType) + if (y.transform.childCount > 0) { - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: - { - var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit + // childが存在する => 末端でない + switch (y.m_anglelimitType) + { + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: { - SpecVersion = VRMC_springBone_limit_SPEC_VERSION, - Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit + var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { - Cone = new UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit + SpecVersion = VRMC_springBone_limit_SPEC_VERSION, + Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { - Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), - Angle = y.m_pitch, + Cone = new UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit + { + Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), + Angle = y.m_pitch, + } } - } - }; - glTFExtension extensions = default; - UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); - joint.Extensions = extensions; - break; - } - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: - { - var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit + }; + glTFExtension extensions = default; + UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); + joint.Extensions = extensions; + break; + } + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: { - Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit + var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { - Hinge = new UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit + Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { - Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), - Angle = y.m_pitch, + Hinge = new UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit + { + Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), + Angle = y.m_pitch, + } } - } - }; - glTFExtension extensions = default; - UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); - joint.Extensions = extensions; - break; - } - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: - { - var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit + }; + glTFExtension extensions = default; + UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); + joint.Extensions = extensions; + break; + } + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: { - Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit + var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { - Spherical = new UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit + Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { - Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), - Pitch = y.m_pitch, - Yaw = y.m_yaw, + Spherical = new UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit + { + Rotation = ReverseXToFloat4(y.m_limitSpaceOffset), + Pitch = y.m_pitch, + Yaw = y.m_yaw, + } } - } - }; - glTFExtension extensions = default; - UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); - joint.Extensions = extensions; - break; - } + }; + glTFExtension extensions = default; + UniGLTF.Extensions.VRMC_springBone_limit.GltfSerializer.SerializeTo(ref extensions, limit); + joint.Extensions = extensions; + break; + } + } } return joint; } From c48507904e70da89f17ae616a9d0e8f5f009c863 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 11:43:33 +0900 Subject: [PATCH 4/8] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index 6265a326b..f8c9e6a7a 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -725,7 +725,7 @@ namespace UniVRM10 if (node.childCount == 0) { // leaf - UniGLTFLogger.Warning($"VRMC_springBone_limit: Leaf node cannot. skip"); + UniGLTFLogger.Warning($"VRMC_springBone_limit: leaf node '{node.name}' must not have limit. skip"); validate = false; } From a89dd975ccd58316c0e25a201a00ffb9080f10d2 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 11:41:39 +0900 Subject: [PATCH 5/8] export SpecVersion for Hinge and Spherical --- Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index 4c56105e8..e285ec744 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -480,6 +480,7 @@ namespace UniVRM10 { var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { + SpecVersion = VRMC_springBone_limit_SPEC_VERSION, Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { Hinge = new UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit @@ -498,6 +499,7 @@ namespace UniVRM10 { var limit = new UniGLTF.Extensions.VRMC_springBone_limit.VRMC_springBone_limit { + SpecVersion = VRMC_springBone_limit_SPEC_VERSION, Limit = new UniGLTF.Extensions.VRMC_springBone_limit.Limit { Spherical = new UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit From 0efba67a9490e5d0df82f401598d1e42a9c5b206 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 11:48:29 +0900 Subject: [PATCH 6/8] unknown specVersion --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index f8c9e6a7a..232d57c1d 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -687,6 +687,7 @@ namespace UniVRM10 var validate = true; if (extensionSpringBoneLimit.SpecVersion != Vrm10Exporter.VRMC_springBone_limit_SPEC_VERSION) { + validate = false; UniGLTFLogger.Warning($"Unknown VRMC_springBone_limit specVersion: {extensionSpringBoneLimit.SpecVersion}"); } From 833d5a4bf6cabbdec09a594226607f00275cf9ed Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:21:22 +0900 Subject: [PATCH 7/8] else --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index 232d57c1d..e197660a2 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -696,11 +696,11 @@ namespace UniVRM10 { ++count; } - else if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) + if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) { ++count; } - else if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) + if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) { ++count; } From 7b02c7e4617661dfd4cb34d817275535e2c33f73 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:23:24 +0900 Subject: [PATCH 8/8] extensionSpringBoneLimit.Limit != null --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index e197660a2..4088f61cf 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -692,17 +692,20 @@ namespace UniVRM10 } var count = 0; - if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone) + if (extensionSpringBoneLimit.Limit != null) { - ++count; - } - if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) - { - ++count; - } - if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) - { - ++count; + if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone) + { + ++count; + } + if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge) + { + ++count; + } + if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical) + { + ++count; + } } switch (count)