From 75ef36b0766d1ab82c1be36f87bdf42d31dc1558 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 20 Aug 2026 14:15:09 +0900 Subject: [PATCH 01/10] 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/10] 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/10] 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/10] 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/10] 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 9b8886da968972687b2bb337b1fd68e4889a8786 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 3 Sep 2026 09:57:03 +0900 Subject: [PATCH 06/10] 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 07/10] =?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 e4f0983ef6e0dc9179ef09c9b879f8fdc85357a6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 11 Sep 2026 09:34:48 +0900 Subject: [PATCH 08/10] 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 09/10] 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 15102b0f4e3efb32b76a6a9598acf06308828d3a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 24 Sep 2026 17:17:37 +0900 Subject: [PATCH 10/10] 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: