From 75ef36b0766d1ab82c1be36f87bdf42d31dc1558 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:15:09 +0900 Subject: [PATCH 01/28] fix dot fallback --- .../SpringBoneJobs/Anglelimit/Anglelimit.cs | 91 ++++++++++--------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs index 52f916f6c..fd58c3d23 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs @@ -6,9 +6,19 @@ namespace UniGLTF.SpringBoneJobs public static class Anglelimit { public static float3 Apply( - in BlittableJointImmutable logic, in BlittableJointMutable joint, - in quaternion parentRotation, in float3 head, in float3 nextTail) + in BlittableJointImmutable logic, + in BlittableJointMutable joint, + in quaternion parentRotation, + in float3 head, + in float3 nextTail + ) { + var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation); + var tailDir = math.mul( + math.inverse(angleSpaceToWorld), + math.normalizesafe(nextTail - head) + ); + switch (joint.anglelimitType) { case AnglelimitTypes.None: @@ -16,51 +26,48 @@ namespace UniGLTF.SpringBoneJobs return nextTail; case AnglelimitTypes.Cone: - { - var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation); - var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head)); - tailDir = AnglelimitCone.Apply(tailDir, joint.anglelimit1); - return head + math.mul(angleSpaceToWorld, tailDir) * logic.length; - } + + tailDir = AnglelimitCone.Apply(tailDir, joint.anglelimit1); + break; case AnglelimitTypes.Hinge: - { - var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation); - var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head)); - tailDir = AnglelimitHinge.Apply(tailDir, joint.anglelimit1); - return head + math.mul(angleSpaceToWorld, tailDir) * logic.length; - } - + tailDir = AnglelimitHinge.Apply(tailDir, joint.anglelimit1); + break; case AnglelimitTypes.Spherical: - { - var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation); - var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head)); - tailDir = AnglelimitSpherical.Apply(tailDir, joint.anglelimit1, joint.anglelimit2); - return head + math.mul(angleSpaceToWorld, tailDir) * logic.length; - } + tailDir = AnglelimitSpherical.Apply( + tailDir, + joint.anglelimit1, + joint.anglelimit2 + ); + break; default: - throw new System.ArgumentException($"unknown joint.anglelimitType: {joint.anglelimitType}"); + throw new System.ArgumentException( + $"unknown joint.anglelimitType: {joint.anglelimitType}" + ); } + + return head + math.mul(angleSpaceToWorld, tailDir) * logic.length; } /// nextTail(position vector in world space) /// tailDir(directionay vector in angle space) /// - public static quaternion anglelimitSpaceToWorld(in BlittableJointImmutable logic, in BlittableJointMutable joint, - in quaternion parentRotation) + public static quaternion anglelimitSpaceToWorld( + in BlittableJointImmutable logic, + in BlittableJointMutable joint, + in quaternion parentRotation + ) { // Y+方向からjointのheadからtailに向かうベクトルへの最小回転 var axisRotation = getAxisRotation(logic.boneAxis); // limitのローカル空間をワールド空間に写像する回転 - return - math.mul(parentRotation, - math.mul(logic.localRotation, - math.mul(axisRotation, - joint.anglelimitOffset))) - ; + return math.mul( + parentRotation, + math.mul(logic.localRotation, math.mul(axisRotation, joint.anglelimitOffset)) + ); } /// @@ -71,20 +78,22 @@ namespace UniGLTF.SpringBoneJobs /// /// TODO: Replace with the appropriate link to the specification later /// - public static quaternion getAxisRotation(in float3 to) + public static quaternion getAxisRotation(in float3 boneAxis) { - // dot(from, to) + 1 - var dot1 = to.y + 1f; + // headからtailに向かうベクトルとY+方向との内積 + var dot = boneAxis.y; - // Handle the case where from and to are parallel and opposite - if (dot1 < 1e-8f) // dot is approximately -1 + if (dot == -1.0) { - return new quaternion(1f, 0f, 0f, 0f); + // headからtailに向かうベクトルがY-方向の場合、X軸周りに180度回転させた回転を設定する + return new quaternion(1, 0, 0, 0); + } + else + { + // それ以外の場合、Y+方向からjointのheadからtailに向かうベクトルへの最小回転を設定する + // quaternion(cross(from, to); dot(from, to) + 1).normalized + return math.normalizesafe(new quaternion(boneAxis.z, 0, -boneAxis.x, dot + 1)); } - - // General case - // quaternion(cross(from, to); dot(from, to) + 1).normalized - return math.normalizesafe(new quaternion(to.z, 0f, -to.x, dot1)); } } -} \ No newline at end of file +} From d4a7a92c8aaed08073014e4ec5a26499eb53ce7a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:27:02 +0900 Subject: [PATCH 02/28] ConeLimit --- .../Anglelimit/AnglelimitCone.cs | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs index d8c159f86..041f7bc94 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs @@ -4,30 +4,41 @@ namespace UniGLTF.SpringBoneJobs { public static class AnglelimitCone { - /// AngleLimit空間の方向ベクトル - /// radius + /// AngleLimit空間の方向ベクトル + /// radius /// AngleLimit空間の方向ベクトル - public static float3 Apply(in float3 src, float angleLimit) + public static float3 Apply(float3 tailDir, float limitAngle) { - // tailDirのy要素をjointに設定されたangleの余弦と比較する - var cosAngle = math.cos(angleLimit); - if (src.y >= cosAngle) - { - return src; - } + // angleを0以上π以下に制限する + limitAngle = math.clamp(limitAngle, 0.0f, math.PI); - var tailDir = src; + // tailDirのy要素をlimitに設定されたangleの余弦と比較する + var cosLimitAngle = math.cos(limitAngle); + if (tailDir.y < cosLimitAngle) { // x・z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする - var ratio = math.sqrt((1.0f - cosAngle * cosAngle) / (1.0f - tailDir.y * tailDir.y)); - tailDir.x *= ratio; - tailDir.z *= ratio; + var horizontalLengthSquared = 1.0f - tailDir.y * tailDir.y; - // y要素を、jointに設定されたangleの余弦とする - tailDir.y = cosAngle; + if (horizontalLengthSquared == 0.0) + { + // tailDirがy軸負方向の場合、z軸正方向側を選択する + tailDir.x = 0.0f; + tailDir.z = math.sqrt(1.0f - cosLimitAngle * cosLimitAngle); + } + else + { + var scale = math.sqrt( + (1.0f - cosLimitAngle * cosLimitAngle) / horizontalLengthSquared + ); + tailDir.x *= scale; + tailDir.z *= scale; + } + + // y要素をlimitに設定されたangleの余弦とする + tailDir.y = cosLimitAngle; } return tailDir; } } -} \ No newline at end of file +} From 1d840a6bed289c34eed72ee6d0701c72410fef72 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:31:02 +0900 Subject: [PATCH 03/28] HingeLimit --- .../Anglelimit/AnglelimitHinge.cs | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs index 45f291929..6010d94be 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs @@ -4,29 +4,39 @@ namespace UniGLTF.SpringBoneJobs { public static class AnglelimitHinge { - /// AngleLimit空間の方向ベクトル - /// radius + /// AngleLimit空間の方向ベクトル + /// radius /// AngleLimit空間の方向ベクトル - public static float3 Apply(in float3 src, float limitAngle) + public static float3 Apply(float3 tailDir, float limitAngle) { - // x要素を0にし、正規化する - float3 tailDir = src; - tailDir.x = 0.0f; - tailDir = math.normalizesafe(tailDir); + // angleを0以上π以下に制限する + limitAngle = math.clamp(limitAngle, 0.0f, math.PI); - // tailDirのy要素をjointに設定されたangleの余弦と比較する - var cosAngle = math.cos(limitAngle); - if (tailDir.y < cosAngle) + var projectedLengthSquared = tailDir.y * tailDir.y + tailDir.z * tailDir.z; + if (projectedLengthSquared == 0.0f) { - // z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする - var ratio = math.sqrt((1.0f - cosAngle * cosAngle) / (1.0f - tailDir.y * tailDir.y)); - tailDir.z *= ratio; - - // y要素を、jointに設定されたangleの余弦とする - tailDir.y = cosAngle; + // tailDirがx軸正方向または負方向の場合、Y軸正方向を選択する + tailDir = math.float3(0.0f, 1.0f, 0.0f); } + else + { + // tailDirをヒンジのYZ平面へ射影する + tailDir = + math.float3(0.0f, tailDir.y, tailDir.z) / math.sqrt(projectedLengthSquared); + // tailDirのy要素をlimitに設定されたangleの余弦と比較する + var cosLimitAngle = math.cos(limitAngle); + if (tailDir.y < cosLimitAngle) + { + var sinLimitAngle = math.sqrt(1.0f - cosLimitAngle * cosLimitAngle); + + // tailDirがy軸負方向の場合、z軸正方向側を選択する + var zSign = (tailDir.z < 0.0f) ? -1.0f : 1.0f; + tailDir.y = cosLimitAngle; + tailDir.z = sinLimitAngle * zSign; + } + } return tailDir; } } -} \ No newline at end of file +} From 6924fb96a9f4d519e995f237bd3567c85a1540b5 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:42:56 +0900 Subject: [PATCH 04/28] SphericalLimit --- .../Anglelimit/AnglelimitSpherical.cs | 60 +++++++++++++------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs index b15ce10fa..06090da62 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs @@ -1,37 +1,61 @@ +using System; using Unity.Mathematics; +using UnityEngine; namespace UniGLTF.SpringBoneJobs { public static class AnglelimitSpherical { /// AngleLimit空間の方向ベクトル - /// radius - /// radius + /// radius + /// radius /// AngleLimit空間の方向ベクトル - public static float3 Apply(in float3 tailDir, float limitAnglePhi, float limitAngleTheta) + public static float3 Apply(float3 tailDir, float limitPitch, float limitYaw) { - // tailDirのphi・thetaを計算する - var phi = math.atan2(tailDir.z, tailDir.y); - var theta = math.asin(tailDir.x); + // pitchを0以上π以下、yawを0以上π/2以下に制限する + limitPitch = math.clamp(limitPitch, 0.0f, math.PI); + limitYaw = math.clamp(limitYaw, 0.0f, math.PI / 2.0f); - // phi・thetaをjointに設定されたphi・thetaを用いて制限する - // var isLimited = false; - if (math.abs(phi) > limitAnglePhi) + // tailDirのpitch・yawを計算する + float pitch; + if (tailDir.y == -1.0) + { + // tailDirがy軸負方向の場合、Z軸正方向側の境界を選択するため、pitchをπとする + pitch = math.PI; + } + else if (math.abs(tailDir.x) == 1.0f) + { + // tailDirがx軸正方向または負方向の場合、pitchを0とする + pitch = 0.0f; + } + else + { + pitch = math.atan2(tailDir.z, tailDir.y); + } + var yaw = math.asin(tailDir.x); + + // pitchをlimitに設定されたpitchを用いて制限する + if (math.abs(pitch) > limitPitch) { // isLimited = true; - phi = limitAnglePhi * math.sign(phi); + pitch = limitPitch * math.sign(pitch); } - // thetaをjointに設定されたthetaを用いて制限する - if (math.abs(theta) > limitAngleTheta) + // yawをlimitに設定されたyawを用いて制限する + if (math.abs(yaw) > limitYaw) { - // isLimited = true; - theta = limitAngleTheta * math.sign(theta); + // isLimited = true; + yaw = limitYaw * math.sign(yaw); } - // tailDirをphi・thetaを用いて再計算する - var cos_theta = math.cos(theta); - return new float3(math.sin(theta), cos_theta * math.cos(phi), cos_theta * math.sin(phi)); + // tailDirをpitch・yawを用いて再計算する + tailDir = math.float3( + math.sin(yaw), + math.cos(yaw) * math.cos(pitch), + math.cos(yaw) * math.sin(pitch) + ); + + return tailDir; } } -} \ No newline at end of file +} From af6847c2c83ab7d2766f80de007ec037f7ece272 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:52:07 +0900 Subject: [PATCH 05/28] clamp when import --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index 557b51b7d..698d11554 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using UniGLTF; -using UniGLTF.Extensions.VRMC_springBone_limit; using UniGLTF.Utils; +using Unity.Mathematics; using UnityEngine; namespace UniVRM10 @@ -655,20 +654,20 @@ namespace UniVRM10 { joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone; joint.m_limitSpaceOffset = QuaternionFromFloat4(cone.Rotation); - joint.m_pitch = cone.Angle.GetValueOrDefault(); + joint.m_pitch = math.clamp(cone.Angle.GetValueOrDefault(), 0.0f, math.PI); } 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(); + joint.m_pitch = math.clamp(hinge.Angle.GetValueOrDefault(), 0.0f, math.PI); } 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(); + joint.m_pitch = math.clamp(spherical.Pitch.GetValueOrDefault(), 0.0f, math.PI); + joint.m_yaw = math.clamp(spherical.Yaw.GetValueOrDefault(), 0.0f, math.PI / 2); } } From e2f9f40423426d1d26da917304116b9f1eecf06a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 15:14:38 +0900 Subject: [PATCH 06/28] 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 07/28] 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 08/28] 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 97bb3bfaa03ea717f453ef2b287709e2f44d335c Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 16:14:26 +0900 Subject: [PATCH 09/28] fix ui --- .../Blittables/BlittableJointMutable.cs | 2 + .../SpringBone/VRM10SpringBoneJointEditor.cs | 45 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs index ccc69d2b6..8c592ac2e 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs @@ -38,6 +38,8 @@ namespace UniGLTF.SpringBoneJobs.Blittables public float anglelimit2 => _data.c2.z; public quaternion anglelimitOffset => _data.c3.xyzw; + /// pitch when Spherical + /// yaw when Spherical public BlittableJointMutable(float stiffnessForce = 0, float gravityPower = 0, float3 gravityDir = default, diff --git a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs index d2f44d272..72ce15e8b 100644 --- a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs +++ b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -88,7 +88,7 @@ namespace UniVRM10 // // angle limit // - var fold = EditorGUILayout.Foldout(m_showAnglelimitSettings, "AngleLimit Settings (experimental)"); + var fold = EditorGUILayout.Foldout(m_showAnglelimitSettings, $"AngleLimit Settings (1.0-draft)"); if (m_showAnglelimitSettings != fold) { m_showAnglelimitSettings = fold; @@ -96,29 +96,36 @@ namespace UniVRM10 } if (m_showAnglelimitSettings) { - EditorGUILayout.HelpBox("SpringBoneの角度制限はまだdraft仕様です。将来的に仕様が変更される可能性があります。また、VRMファイルへのインポート・エクスポート機能はまだ実装されていません。\nThe angle limit feature for SpringBone is still in draft status. The specifications may change in the future. Also, the import/export of VRM files has not yet been implemented.", MessageType.Warning); + EditorGUILayout.HelpBox("SpringBoneの角度制限はまだdraft仕様です。将来的に仕様が変更される可能性があります。\nThe angle limit feature for SpringBone is still in draft status. The specifications may change in the future.", MessageType.Warning); - EditorGUILayout.PropertyField(m_angleLimitType); - switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex) + if (isLastTail) { - case UniGLTF.SpringBoneJobs.AnglelimitTypes.None: - break; + EditorGUILayout.HelpBox("末端ノードでは無効です。", MessageType.Warning); + } + else + { + EditorGUILayout.PropertyField(m_angleLimitType); + switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex) + { + case UniGLTF.SpringBoneJobs.AnglelimitTypes.None: + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch); - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch); - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch); - EditorGUILayout.PropertyField(m_angleLimitYaw); - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch); + EditorGUILayout.PropertyField(m_angleLimitYaw); + break; + } } } From 9b8886da968972687b2bb337b1fd68e4889a8786 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 09:57:03 +0900 Subject: [PATCH 10/28] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs index 041f7bc94..6fe2a8557 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs @@ -19,7 +19,7 @@ namespace UniGLTF.SpringBoneJobs // x・z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする var horizontalLengthSquared = 1.0f - tailDir.y * tailDir.y; - if (horizontalLengthSquared == 0.0) + if (horizontalLengthSquared <= 1e-8f) { // tailDirがy軸負方向の場合、z軸正方向側を選択する tailDir.x = 0.0f; From dc9de498d681b235eac7418d3467d9b5ace69e4a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 10:20:48 +0900 Subject: [PATCH 11/28] =?UTF-8?q?SINGULARITY=5FEPSILON=20=E7=89=B9?= =?UTF-8?q?=E7=95=B0=E7=82=B9=5F=E9=96=BE=E5=80=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs | 5 ++++- .../Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs | 2 +- .../Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs | 4 ++-- .../SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs | 8 +++----- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs index fd58c3d23..7a39c62ca 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs @@ -1,3 +1,4 @@ +using System; using UniGLTF.SpringBoneJobs.Blittables; using Unity.Mathematics; @@ -5,6 +6,8 @@ namespace UniGLTF.SpringBoneJobs { public static class Anglelimit { + public static readonly float SINGULARITY_EPSILON = MathF.Sqrt(float.Epsilon); + public static float3 Apply( in BlittableJointImmutable logic, in BlittableJointMutable joint, @@ -83,7 +86,7 @@ namespace UniGLTF.SpringBoneJobs // headからtailに向かうベクトルとY+方向との内積 var dot = boneAxis.y; - if (dot == -1.0) + if (dot <= -1f + SINGULARITY_EPSILON) { // headからtailに向かうベクトルがY-方向の場合、X軸周りに180度回転させた回転を設定する return new quaternion(1, 0, 0, 0); diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs index 6fe2a8557..bd530af4e 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs @@ -19,7 +19,7 @@ namespace UniGLTF.SpringBoneJobs // x・z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする var horizontalLengthSquared = 1.0f - tailDir.y * tailDir.y; - if (horizontalLengthSquared <= 1e-8f) + if (horizontalLengthSquared <= Anglelimit.SINGULARITY_EPSILON) { // tailDirがy軸負方向の場合、z軸正方向側を選択する tailDir.x = 0.0f; diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs index 6010d94be..9e4fcf387 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs @@ -13,7 +13,7 @@ namespace UniGLTF.SpringBoneJobs limitAngle = math.clamp(limitAngle, 0.0f, math.PI); var projectedLengthSquared = tailDir.y * tailDir.y + tailDir.z * tailDir.z; - if (projectedLengthSquared == 0.0f) + if (projectedLengthSquared <= Anglelimit.SINGULARITY_EPSILON) { // tailDirがx軸正方向または負方向の場合、Y軸正方向を選択する tailDir = math.float3(0.0f, 1.0f, 0.0f); @@ -30,7 +30,7 @@ namespace UniGLTF.SpringBoneJobs { var sinLimitAngle = math.sqrt(1.0f - cosLimitAngle * cosLimitAngle); - // tailDirがy軸負方向の場合、z軸正方向側を選択する + // zの符号を維持し、z==0 の場合は z軸正方向側を選択する var zSign = (tailDir.z < 0.0f) ? -1.0f : 1.0f; tailDir.y = cosLimitAngle; tailDir.z = sinLimitAngle * zSign; diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs index 06090da62..61cdfc2b3 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs @@ -1,6 +1,4 @@ -using System; using Unity.Mathematics; -using UnityEngine; namespace UniGLTF.SpringBoneJobs { @@ -18,12 +16,12 @@ namespace UniGLTF.SpringBoneJobs // tailDirのpitch・yawを計算する float pitch; - if (tailDir.y == -1.0) + if (tailDir.y <= -1.0 + Anglelimit.SINGULARITY_EPSILON) { // tailDirがy軸負方向の場合、Z軸正方向側の境界を選択するため、pitchをπとする pitch = math.PI; } - else if (math.abs(tailDir.x) == 1.0f) + else if (math.abs(tailDir.x) <= 1.0f - Anglelimit.SINGULARITY_EPSILON) { // tailDirがx軸正方向または負方向の場合、pitchを0とする pitch = 0.0f; @@ -32,7 +30,7 @@ namespace UniGLTF.SpringBoneJobs { pitch = math.atan2(tailDir.z, tailDir.y); } - var yaw = math.asin(tailDir.x); + var yaw = math.asin(math.clamp(tailDir.x, -1f, 1f)); // pitchをlimitに設定されたpitchを用いて制限する if (math.abs(pitch) > limitPitch) From c48507904e70da89f17ae616a9d0e8f5f009c863 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 11:43:33 +0900 Subject: [PATCH 12/28] 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 13/28] 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 14/28] 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 ec8f58d0f300d8287ed7dfbf3b269be32e5b2176 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 11:49:06 +0900 Subject: [PATCH 15/28] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../SpringBoneJobs/Blittables/BlittableJointMutable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs index 8c592ac2e..1f63fae43 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Blittables/BlittableJointMutable.cs @@ -38,8 +38,8 @@ namespace UniGLTF.SpringBoneJobs.Blittables public float anglelimit2 => _data.c2.z; public quaternion anglelimitOffset => _data.c3.xyzw; - /// pitch when Spherical - /// yaw when Spherical + // angleLimit1: angle (Cone/Hinge), pitch (Spherical) + // angleLimit2: yaw (Spherical) public BlittableJointMutable(float stiffnessForce = 0, float gravityPower = 0, float3 gravityDir = default, From e9c1050f11c16e08a93caad9c82ebf8281ce2ddc Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 12:55:25 +0900 Subject: [PATCH 16/28] show if isLastTail --- .../SpringBone/VRM10SpringBoneJointEditor.cs | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs index 72ce15e8b..e52e4ff0f 100644 --- a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs +++ b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -98,34 +98,32 @@ namespace UniVRM10 { EditorGUILayout.HelpBox("SpringBoneの角度制限はまだdraft仕様です。将来的に仕様が変更される可能性があります。\nThe angle limit feature for SpringBone is still in draft status. The specifications may change in the future.", MessageType.Warning); + if (isLastTail) { EditorGUILayout.HelpBox("末端ノードでは無効です。", MessageType.Warning); } - else + EditorGUILayout.PropertyField(m_angleLimitType); + switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex) { - EditorGUILayout.PropertyField(m_angleLimitType); - switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex) - { - case UniGLTF.SpringBoneJobs.AnglelimitTypes.None: - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.None: + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); - break; + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch, new GUIContent("Angle")); + break; - case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: - EditorGUILayout.PropertyField(m_angleLimitRotation); - EditorGUILayout.PropertyField(m_angleLimitPitch); - EditorGUILayout.PropertyField(m_angleLimitYaw); - break; - } + case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical: + EditorGUILayout.PropertyField(m_angleLimitRotation); + EditorGUILayout.PropertyField(m_angleLimitPitch); + EditorGUILayout.PropertyField(m_angleLimitYaw); + break; } } From 2a20b44ab1f13dc0cae3335e84d49400c6ee5a13 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 13:07:35 +0900 Subject: [PATCH 17/28] fix msg --- .../Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs index e52e4ff0f..537ba365c 100644 --- a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs +++ b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -101,7 +101,7 @@ namespace UniVRM10 if (isLastTail) { - EditorGUILayout.HelpBox("末端ノードでは無効です。", MessageType.Warning); + EditorGUILayout.HelpBox("末端ノードではAngleLimitは無視されます。", MessageType.Info); } EditorGUILayout.PropertyField(m_angleLimitType); switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex) From 5b0f15f9a54c2e37eef9a4457bc7c85ca36e2669 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 14:09:54 +0900 Subject: [PATCH 18/28] VRM10SpringBoneJointEditor.ShowSpringInfo to Vrm10InstanceSpringBone.GetEditInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共通ロジックとして昇格。.childCount==0 を info.IsLastTail で置き換えるべきところがあるぽい。 --- .../SpringBone/VRM10SpringBoneJointEditor.cs | 40 +++++++------- .../Vrm10Instance/Vrm10InstanceSpringBone.cs | 53 +++++++++++++++++++ 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs index 537ba365c..77ac620e8 100644 --- a/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs +++ b/Packages/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -63,10 +63,11 @@ namespace UniVRM10 /// spring 情報。readonly。mouse click による hierarchy 参照補助 /// EditorGUI.BeginDisabledGroup(true); - var isLastTail = ShowSpringInfo(); + var info = Vrm10InstanceSpringBone.GetEditInfo(m_target, m_root); + ShowSpringInfo(info); EditorGUI.EndDisabledGroup(); - if (isLastTail) + if (info.IsLastTail) { EditorGUILayout.HelpBox("末端 joint です。下記の設定は使用されません。", MessageType.Info); } @@ -99,7 +100,7 @@ namespace UniVRM10 EditorGUILayout.HelpBox("SpringBoneの角度制限はまだdraft仕様です。将来的に仕様が変更される可能性があります。\nThe angle limit feature for SpringBone is still in draft status. The specifications may change in the future.", MessageType.Warning); - if (isLastTail) + if (info.IsLastTail) { EditorGUILayout.HelpBox("末端ノードではAngleLimitは無視されます。", MessageType.Info); } @@ -144,52 +145,51 @@ namespace UniVRM10 /// - Springに関連付けられたColliderの情報を表示する /// /// 末端 - bool ShowSpringInfo() + static void ShowSpringInfo(Vrm10InstanceSpringBone.EditInfo info) { - if (m_root == null) + if (info.Root == null) { EditorGUILayout.HelpBox("no vrm-1.0", MessageType.Warning); - return false; + return; } - EditorGUILayout.ObjectField("Vrm-1.0", m_root, typeof(Vrm10Instance), true, null); + EditorGUILayout.ObjectField("Vrm-1.0", info.Root, typeof(Vrm10Instance), true, null); - var found = m_root.SpringBone.FindJoint(m_target); - if (!found.HasValue) + if (info.Spring == null) { EditorGUILayout.HelpBox("This joint not belongs any spring", MessageType.Warning); - return false; + return; } - var (spring, i, _) = found.Value; - m_showJoints = EditorGUILayout.Foldout(m_showJoints, $"Springs[{i}]({spring.Name})"); + // var (spring, i, _) = found.Value; + m_showJoints = EditorGUILayout.Foldout(m_showJoints, $"Springs[{info.SpringIndex}]({info.Spring.Name})"); int? jointIndex = default; // joints - for (int j = 0; j < spring.Joints.Count; ++j) + for (int j = 0; j < info.Spring.Joints.Count; ++j) { - var joint = spring.Joints[j]; + var joint = info.Spring.Joints[j]; if (m_showJoints) { var label = $"Joints[{j}]"; - if (joint == m_target) + if (joint == info.Target) { label += "★"; } EditorGUILayout.ObjectField(label, joint, typeof(VRM10SpringBoneJoint), true, null); } - if (joint == m_target) + if (joint == info.Target) { jointIndex = j; } } m_showColliders = EditorGUILayout.Foldout(m_showColliders, "ColliderGroups"); - if (m_showColliders && found.HasValue) + if (m_showColliders) { // collider groups - for (int j = 0; j < spring.ColliderGroups.Count; ++j) + for (int j = 0; j < info.Spring.ColliderGroups.Count; ++j) { - var group = spring.ColliderGroups[j]; + var group = info.Spring.ColliderGroups[j]; EditorGUILayout.LabelField($"ColliderGroups[{j}]({group.Name})"); for (int k = 0; k < group.Colliders.Count; ++k) { @@ -199,8 +199,6 @@ namespace UniVRM10 } } } - - return jointIndex == (spring.Joints.Count - 1); } /// diff --git a/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs b/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs index f47a972c3..1501e8465 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs @@ -89,5 +89,58 @@ namespace UniVRM10 } return default; } + + public struct EditInfo + { + public VRM10SpringBoneJoint Target; + public Vrm10Instance Root; + public Spring Spring; + public int SpringIndex; + public int JointIndex; + public bool IsLastTail; + } + + /// + /// Return SprintBone EditInfo. + /// Do not call on runtime play for performance. + /// + /// On Editor may null. + /// GetComponentInParent cache. + /// + public static EditInfo GetEditInfo(VRM10SpringBoneJoint target, Vrm10Instance root) + { + EditInfo info = default; + if (target == null) + { + return info; + } + info.Target = target; + + if (root == null) + { + root = target.GetComponentInParent(); + } + if (root == null) + { + return info; + } + info.Root = root; + + var found = root.SpringBone.FindJoint(target); + if (!found.HasValue) + { + return info; + } + (info.Spring, info.SpringIndex, info.JointIndex) = found.Value; + + + // ヒエラルキーの末端ではなく、Springの末端である + if (info.Spring.Joints.Count > 0 && info.Spring.Joints[info.Spring.Joints.Count - 1] == target) + { + info.IsLastTail = true; + } + + return info; + } } } From e4f0983ef6e0dc9179ef09c9b879f8fdc85357a6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2026 09:34:48 +0900 Subject: [PATCH 19/28] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs index 61cdfc2b3..86dfe8264 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs @@ -16,12 +16,12 @@ namespace UniGLTF.SpringBoneJobs // tailDirのpitch・yawを計算する float pitch; - if (tailDir.y <= -1.0 + Anglelimit.SINGULARITY_EPSILON) + if (tailDir.y <= -1.0f + Anglelimit.SINGULARITY_EPSILON) { // tailDirがy軸負方向の場合、Z軸正方向側の境界を選択するため、pitchをπとする pitch = math.PI; } - else if (math.abs(tailDir.x) <= 1.0f - Anglelimit.SINGULARITY_EPSILON) + else if (math.abs(tailDir.x) >= 1.0f - Anglelimit.SINGULARITY_EPSILON) { // tailDirがx軸正方向または負方向の場合、pitchを0とする pitch = 0.0f; From a7df1186976967f31e065ce9f01e35786e5cd584 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2026 09:35:13 +0900 Subject: [PATCH 20/28] Update Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs Co-authored-by: 0b5vr <0b5vr@0b5vr.com> --- .../UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs index 7a39c62ca..a67ca4a26 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs @@ -6,7 +6,7 @@ namespace UniGLTF.SpringBoneJobs { public static class Anglelimit { - public static readonly float SINGULARITY_EPSILON = MathF.Sqrt(float.Epsilon); + public static readonly float SINGULARITY_EPSILON = 1e-8f; public static float3 Apply( in BlittableJointImmutable logic, From d99eeb5244b0b782e15e5c172ec48e343644a391 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 18 Sep 2026 13:08:57 +0900 Subject: [PATCH 21/28] add copyLmimit arg --- .../SpringBone/VRM10SpringBoneJoint.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs index d6a7949d7..ef9192c7d 100644 --- a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs +++ b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -26,15 +26,27 @@ namespace UniVRM10 [SerializeField] public float m_jointRadius = 0.02f; + /// + /// VRMC_springBone_limit + /// [SerializeField] public UniGLTF.SpringBoneJobs.AnglelimitTypes m_anglelimitType; + /// + /// VRMC_springBone_limit + /// [SerializeField] public Quaternion m_limitSpaceOffset = Quaternion.identity; + /// + /// VRMC_springBone_limit + /// [SerializeField, Range(0, Mathf.PI)] public float m_pitch = Mathf.PI; + /// + /// VRMC_springBone_limit + /// [SerializeField, Range(0, Mathf.PI / 2)] public float m_yaw = 0; @@ -59,7 +71,7 @@ namespace UniVRM10 } } - void AddJointRecursive(Transform t, VRM10SpringBoneJoint src) + void AddJointRecursive(Transform t, VRM10SpringBoneJoint src, bool copyLmimit) { var joint = t.gameObject.GetOrAddComponent(); @@ -70,10 +82,19 @@ namespace UniVRM10 joint.m_dragForce = src.m_dragForce; joint.m_jointRadius = src.m_jointRadius; + if (copyLmimit) + { + joint.m_anglelimitType = src.m_anglelimitType; + joint.m_limitSpaceOffset = src.m_limitSpaceOffset; + joint.m_yaw = src.m_yaw; + joint.m_pitch = src.m_pitch; + } + + if (t.childCount > 0) { // only first child - AddJointRecursive(t.GetChild(0), src); + AddJointRecursive(t.GetChild(0), src, copyLmimit); } } @@ -106,7 +127,7 @@ namespace UniVRM10 return; } - AddJointRecursive(transform.GetChild(0), this); + AddJointRecursive(transform.GetChild(0), this, true); // updater root foreach (var spring in root.SpringBone.Springs) From 15102b0f4e3efb32b76a6a9598acf06308828d3a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:17:37 +0900 Subject: [PATCH 22/28] early out --- .../Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs index a67ca4a26..e3b47c205 100644 --- a/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs +++ b/Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs @@ -16,6 +16,12 @@ namespace UniGLTF.SpringBoneJobs in float3 nextTail ) { + if (joint.anglelimitType == AnglelimitTypes.None) + { + // do nothing + return nextTail; + } + var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation); var tailDir = math.mul( math.inverse(angleSpaceToWorld), @@ -25,8 +31,7 @@ namespace UniGLTF.SpringBoneJobs switch (joint.anglelimitType) { case AnglelimitTypes.None: - // do nothing - return nextTail; + throw new Exception("not reach here"); case AnglelimitTypes.Cone: From 833d5a4bf6cabbdec09a594226607f00275cf9ed Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:21:22 +0900 Subject: [PATCH 23/28] 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 24/28] 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) From b324c5708779b081a3b65519574ee72813298276 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:24:23 +0900 Subject: [PATCH 25/28] Update Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs Co-authored-by: 0b5vr <0b5vr@0b5vr.com> --- .../VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs index ef9192c7d..87576bdb5 100644 --- a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs +++ b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -71,7 +71,7 @@ namespace UniVRM10 } } - void AddJointRecursive(Transform t, VRM10SpringBoneJoint src, bool copyLmimit) + void AddJointRecursive(Transform t, VRM10SpringBoneJoint src, bool copyLimit) { var joint = t.gameObject.GetOrAddComponent(); From 88ce0250a42a67f0e73511204bf2531876b57211 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:24:33 +0900 Subject: [PATCH 26/28] Update Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs Co-authored-by: 0b5vr <0b5vr@0b5vr.com> --- .../VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs index 87576bdb5..d731b81c7 100644 --- a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs +++ b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -82,7 +82,7 @@ namespace UniVRM10 joint.m_dragForce = src.m_dragForce; joint.m_jointRadius = src.m_jointRadius; - if (copyLmimit) + if (copyLimit) { joint.m_anglelimitType = src.m_anglelimitType; joint.m_limitSpaceOffset = src.m_limitSpaceOffset; From 1b96b037b0910ccac7b3f5b8b15c0a0757743702 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:24:41 +0900 Subject: [PATCH 27/28] Update Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs Co-authored-by: 0b5vr <0b5vr@0b5vr.com> --- .../VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs index d731b81c7..3a4e9f4c2 100644 --- a/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs +++ b/Packages/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -94,7 +94,7 @@ namespace UniVRM10 if (t.childCount > 0) { // only first child - AddJointRecursive(t.GetChild(0), src, copyLmimit); + AddJointRecursive(t.GetChild(0), src, copyLimit); } } From 7ddffa60a5f6a80f6796854f46a7adc5fdc313c4 Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Thu, 24 Sep 2026 17:49:07 +0900 Subject: [PATCH 28/28] Update Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs --- .../Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs b/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs index 1501e8465..16ef83465 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Instance/Vrm10InstanceSpringBone.cs @@ -101,7 +101,7 @@ namespace UniVRM10 } /// - /// Return SprintBone EditInfo. + /// Return SpringBone EditInfo. /// Do not call on runtime play for performance. /// /// On Editor may null.