Skip to content

[VRMC_springBone_limit] fix clamp - #2832

Open
ousttrue wants to merge 5 commits into
vrm-c:masterfrom
ousttrue:fix/spring_limit_clamp
Open

[VRMC_springBone_limit] fix clamp#2832
ousttrue wants to merge 5 commits into
vrm-c:masterfrom
ousttrue:fix/spring_limit_clamp

Conversation

@ousttrue

Copy link
Copy Markdown
Contributor

fixed #2827

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates UniVRM’s VRMC_springBone_limit handling to better match the specification by clamping parsed limit angles and adding/adjusting runtime angle-limit behavior (including singularity fallbacks) in the SpringBone job angle-limit implementations.

Changes:

  • Clamp imported Cone/Hinge angles to [0, π], and Spherical pitch/yaw to spec maxima during import.
  • Update runtime Anglelimit implementations (Cone/Hinge/Spherical) to clamp inputs and apply singularity-aware fallback directions.
  • Refactor Anglelimit.Apply to share common computations across limit types and tweak axis-rotation special-casing.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Packages/VRM10/Runtime/IO/Vrm10Importer.cs Clamp VRMC_springBone_limit values during import to spec bounds.
Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs Implement pitch/yaw clamping and singularity fallback handling for spherical limits.
Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitHinge.cs Add clamping and singularity fallback handling for hinge limits.
Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitCone.cs Add clamping and singularity fallback handling for cone limits.
Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/Anglelimit.cs Refactor shared computations and adjust axis-rotation singularity handling.
Suppressed comments (1)

Packages/UniGLTF/Runtime/SpringBoneJobs/Anglelimit/AnglelimitSpherical.cs:26

  • math.abs(tailDir.x) == 1.0f の完全一致判定は誤差で成立しづらく、±X 特異点フォールバックが効かないことがあります。しきい値比較にしてください。
            else if (math.abs(tailDir.x) == 1.0f)

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1 to +3
using System;
using Unity.Mathematics;
using UnityEngine;
if (math.abs(phi) > limitAnglePhi)
// tailDirのpitch・yawを計算する
float pitch;
if (tailDir.y == -1.0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +15 to 17
var projectedLengthSquared = tailDir.y * tailDir.y + tailDir.z * tailDir.z;
if (projectedLengthSquared == 0.0f)
{
Comment on lines +33 to +36
// tailDirがy軸負方向の場合、z軸正方向側を選択する
var zSign = (tailDir.z < 0.0f) ? -1.0f : 1.0f;
tailDir.y = cosLimitAngle;
tailDir.z = sinLimitAngle * zSign;
Comment on lines +20 to +23
var horizontalLengthSquared = 1.0f - tailDir.y * tailDir.y;

if (horizontalLengthSquared == 0.0)
{
Comment on lines +86 to +90
if (dot == -1.0)
{
return new quaternion(1f, 0f, 0f, 0f);
// headからtailに向かうベクトルがY-方向の場合、X軸周りに180度回転させた回転を設定する
return new quaternion(1, 0, 0, 0);
}
// tailDirがy軸負方向の場合、Z軸正方向側の境界を選択するため、pitchをπとする
pitch = math.PI;
}
else if (math.abs(tailDir.x) == 1.0f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAY] こちらもthree-vrmではEPSILONを入れた特異点処理としています。こちらは誤差付きで比較しなくてもそこまで問題にならないかも

https://github.com/pixiv/three-vrm/blob/f6a4d0f34360fda4bbba2c509d66a00da6cac557/packages/three-vrm-springbone/src/VRMSpringBoneLimitSpherical.ts#L41

{
pitch = math.atan2(tailDir.z, tailDir.y);
}
var yaw = math.asin(tailDir.x);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHOULD: tailDir.x の範囲が [-1.0, 1.0] の外に行くと、math.asinが NaN を返し得ます。おそらく、-1, 1でclampしたほうが良いです。

var cosAngle = math.cos(limitAngle);
if (tailDir.y < cosAngle)
var projectedLengthSquared = tailDir.y * tailDir.y + tailDir.z * tailDir.z;
if (projectedLengthSquared == 0.0f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tailDir.z *= ratio;
var horizontalLengthSquared = 1.0f - tailDir.y * tailDir.y;

if (horizontalLengthSquared == 0.0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHOULD: 誤差を考慮した比較を行ったほうが良さそうです。three-vrm側はこんな感じです:

https://github.com/pixiv/three-vrm/blob/f6a4d0f34360fda4bbba2c509d66a00da6cac557/packages/three-vrm-springbone/src/VRMSpringBoneLimitCone.ts#L41

@0b5vr

0b5vr commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

私からの指摘事項は、Copilotによる指摘と同じく、全体的に浮動小数点誤差周りの取扱に関するもののみです。それ以外は良いと思います!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[VRMC_springBone_limit] Runtime: angle clamp and singularity fallback

3 participants