spherical は phi が x 軸(hingeと同じ)。theta が z 軸

This commit is contained in:
ousttrue
2025-09-16 20:11:32 +09:00
parent 618478f1ea
commit 59ec82b183
4 changed files with 64 additions and 48 deletions

View File

@@ -1,6 +1,7 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;
namespace UniVRM10
{
@@ -38,9 +39,9 @@ namespace UniVRM10
m_dragForceProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_dragForce));
m_jointRadiusProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_jointRadius));
m_angleLimitType = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_anglelimitType));
m_angleLimitRotation = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitRotation));
m_angleLimitAngle1 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitAngle1));
m_angleLimitAngle2 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitAngle2));
m_angleLimitRotation = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_limitSpaceOffset));
m_angleLimitAngle1 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_phi));
m_angleLimitAngle2 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_theta));
m_root = m_target.GetComponentInParent<Vrm10Instance>();
}
@@ -212,11 +213,11 @@ namespace UniVRM10
{
Handles.matrix = limitSpace;
EditorGUI.BeginChangeCheck();
Quaternion rot = Handles.RotationHandle(m_target.m_angleLimitRotation, Vector3.zero);
Quaternion rot = Handles.RotationHandle(m_target.m_limitSpaceOffset, Vector3.zero);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "m_angleLimitRotation");
m_target.m_angleLimitRotation = rot;
m_target.m_limitSpaceOffset = rot;
return true;
}
else
@@ -240,6 +241,23 @@ namespace UniVRM10
}
}
static void DrawSpace(Matrix4x4 limitSpace, float size)
{
float half = size * 0.5f;
Handles.matrix = limitSpace;
Handles.color = Color.red;
var x = Vector3.right * half;
Handles.DrawLine(x, -x);
Handles.color = Color.green;
Handles.DrawLine(Vector3.zero, Vector3.up * size);
Handles.color = Color.blue;
var y = Vector3.forward * half;
Handles.DrawLine(-y, y);
Handles.color = new Color(1, 1, 1, 0.1f);
Handles.DrawSolidDisc(Vector3.zero, Vector3.up, half);
}
void OnSceneGUI()
{
if (m_root == null)
@@ -292,24 +310,20 @@ namespace UniVRM10
}
}
limitRotation = limitRotation * m_target.m_angleLimitRotation;
limitRotation = limitRotation * m_target.m_limitSpaceOffset;
var limitSpace = Matrix4x4.TRS(head.position, limitRotation, Vector3.one);
Handles.matrix = limitSpace;
Handles.color = Color.red;
Handles.DrawLine(Vector3.zero, Vector3.right * limit_tail_pos.magnitude);
Handles.color = Color.green;
Handles.DrawLine(Vector3.zero, Vector3.up * limit_tail_pos.magnitude);
DrawSpace(limitSpace, limit_tail_pos.magnitude);
switch (m_target.m_anglelimitType)
{
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone:
{
var s = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f);
var c = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f);
var s = Mathf.Sin(m_target.m_phi * 0.5f);
var c = Mathf.Cos(m_target.m_phi * 0.5f);
Handles.color = Color.cyan;
var r = Mathf.Tan(m_target.m_angleLimitAngle1 * 0.5f) * limit_tail_pos.magnitude * c;
var r = Mathf.Tan(m_target.m_phi * 0.5f) * limit_tail_pos.magnitude * c;
Handles.DrawWireDisc(limit_tail_pos * c, Vector3.up, r, 1);
// o head
// r /
@@ -326,13 +340,13 @@ namespace UniVRM10
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge:
{
var s = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f);
var c = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f);
var s = Mathf.Sin(m_target.m_phi * 0.5f);
var c = Mathf.Cos(m_target.m_phi * 0.5f);
Handles.color = Color.cyan;
Handles.DrawWireArc(Vector3.zero, Vector3.left,
new Vector3(0, c, s) * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
m_target.m_phi * Mathf.Rad2Deg,
limit_tail_pos.magnitude
);
// yz plane
@@ -350,18 +364,18 @@ namespace UniVRM10
{
Handles.color = Color.cyan;
var ts = Mathf.Sin(m_target.m_angleLimitAngle1 * 0.5f); // theta sin
var tc = Mathf.Cos(m_target.m_angleLimitAngle1 * 0.5f); // theta cos
var ps = Mathf.Sin(m_target.m_angleLimitAngle2 * 0.5f); // phi sin
var pc = Mathf.Cos(m_target.m_angleLimitAngle2 * 0.5f); // phi cos
var ts = Mathf.Sin(m_target.m_phi * 0.5f); // theta sin
var tc = Mathf.Cos(m_target.m_phi * 0.5f); // theta cos
var ps = Mathf.Sin(m_target.m_theta * 0.5f); // phi sin
var pc = Mathf.Cos(m_target.m_theta * 0.5f); // phi cos
// y = tc * pc
// ^ z = tc * ps
// |/
// +-> x = ts
var x = ts;
var y = tc * pc;
var z = tc * ps;
var x = ps;
var y = pc * tc;
var z = pc * ts;
// z
// ^
@@ -381,14 +395,15 @@ namespace UniVRM10
// ab / cd
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(a, b).normalized,
a * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
Vector3.Angle(a, b),
limit_tail_pos.magnitude
);
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(c, d).normalized,
c * limit_tail_pos.magnitude,
m_target.m_angleLimitAngle1 * Mathf.Rad2Deg,
Vector3.Angle(c, d),
limit_tail_pos.magnitude
);
Handles.Label(Vector3.Slerp(a, b, 0.5f) * limit_tail_pos.magnitude, $"theta: {m_target.m_theta * Mathf.Rad2Deg:F0}°");
// bc / da
Handles.DrawWireArc(Vector3.zero, Vector3.Cross(b, c).normalized,
@@ -401,6 +416,7 @@ namespace UniVRM10
Vector3.Angle(d, a),
limit_tail_pos.magnitude
);
Handles.Label(Vector3.Slerp(b, c, 0.5f) * limit_tail_pos.magnitude, $"phi: {m_target.m_phi * Mathf.Rad2Deg:F0}°");
break;
}

View File

@@ -30,13 +30,13 @@ namespace UniVRM10
public UniGLTF.SpringBoneJobs.AnglelimitTypes m_anglelimitType;
[SerializeField]
public Quaternion m_angleLimitRotation = Quaternion.identity;
public Quaternion m_limitSpaceOffset = Quaternion.identity;
[SerializeField, Range(0, Mathf.PI)]
public float m_angleLimitAngle1 = Mathf.PI;
public float m_phi = Mathf.PI;
[SerializeField, Range(0, Mathf.PI)]
public float m_angleLimitAngle2 = Mathf.PI;
public float m_theta = Mathf.PI;
public BlittableJointMutable Blittable => new BlittableJointMutable(
stiffnessForce: m_stiffnessForce,
@@ -46,16 +46,16 @@ namespace UniVRM10
radius: m_jointRadius,
// v0.129.4
angleLimitType: (float)m_anglelimitType,
angleLimit1: m_angleLimitAngle1,
angleLimit2: m_angleLimitAngle2,
angleLimitOffset: m_angleLimitRotation
angleLimit1: m_phi,
angleLimit2: m_theta,
angleLimitOffset: m_limitSpaceOffset
);
void OnValidate()
{
if (m_angleLimitRotation == default)
if (m_limitSpaceOffset == default)
{
m_angleLimitRotation = Quaternion.identity;
m_limitSpaceOffset = Quaternion.identity;
}
}

View File

@@ -461,8 +461,8 @@ namespace UniVRM10
{
Cone = new UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit
{
Rotation = ReverseX(y.m_angleLimitRotation),
Angle = y.m_angleLimitAngle1,
Rotation = ReverseX(y.m_limitSpaceOffset),
Angle = y.m_theta,
}
}
};
@@ -479,8 +479,8 @@ namespace UniVRM10
{
Hinge = new UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit
{
Rotation = ReverseX(y.m_angleLimitRotation),
Angle = y.m_angleLimitAngle1,
Rotation = ReverseX(y.m_limitSpaceOffset),
Angle = y.m_theta,
}
}
};
@@ -497,9 +497,9 @@ namespace UniVRM10
{
Spherical = new UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit
{
Rotation = ReverseX(y.m_angleLimitRotation),
Theta = y.m_angleLimitAngle1,
Phi = y.m_angleLimitAngle2,
Rotation = ReverseX(y.m_limitSpaceOffset),
Theta = y.m_theta,
Phi = y.m_theta,
}
}
};

View File

@@ -635,21 +635,21 @@ namespace UniVRM10
if (extensionSpringBoneLimit.Limit.Cone is UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit cone)
{
joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone;
joint.m_angleLimitRotation = QuaternionFromFloat4(cone.Rotation);
joint.m_angleLimitAngle1 = cone.Angle.GetValueOrDefault(Mathf.PI * 0.5f);
joint.m_limitSpaceOffset = QuaternionFromFloat4(cone.Rotation);
joint.m_theta = cone.Angle.GetValueOrDefault(Mathf.PI * 0.5f);
}
else if (extensionSpringBoneLimit.Limit.Hinge is UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit hinge)
{
joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge;
joint.m_angleLimitRotation = QuaternionFromFloat4(hinge.Rotation);
joint.m_angleLimitAngle1 = hinge.Angle.GetValueOrDefault(Mathf.PI * 0.5f);
joint.m_limitSpaceOffset = QuaternionFromFloat4(hinge.Rotation);
joint.m_theta = hinge.Angle.GetValueOrDefault(Mathf.PI * 0.5f);
}
else if (extensionSpringBoneLimit.Limit.Spherical is UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit spherical)
{
joint.m_anglelimitType = UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical;
joint.m_angleLimitRotation = QuaternionFromFloat4(spherical.Rotation);
joint.m_angleLimitAngle1 = spherical.Theta.GetValueOrDefault(Mathf.PI * 0.5f);
joint.m_angleLimitAngle2 = spherical.Phi.GetValueOrDefault(Mathf.PI * 0.5f);
joint.m_limitSpaceOffset = QuaternionFromFloat4(spherical.Rotation);
joint.m_theta = spherical.Theta.GetValueOrDefault(Mathf.PI * 0.5f);
joint.m_theta = spherical.Phi.GetValueOrDefault(Mathf.PI * 0.5f);
}
}