diff --git a/Assets/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs b/Assets/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs index 2b24129b7..2824f4e51 100644 --- a/Assets/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs +++ b/Assets/VRM10/Editor/Components/SpringBone/VRM10SpringBoneJointEditor.cs @@ -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(); } @@ -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; } diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs index d1e41e39d..d2ebf619f 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -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; } } diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 1cad2eb9b..51d2ba108 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -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, } } }; diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 2c285f069..2f4c25cf3 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -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); } }