diff --git a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs b/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
deleted file mode 100644
index a893ecbe7..000000000
--- a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-using UnityEditor;
-using UnityEngine;
-
-namespace UniVRM10
-{
- [CustomPropertyDrawer(typeof(VRM10RotationOffset))]
- public class IngredientDrawer : PropertyDrawer
- {
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
- {
- return 16f + 18f;
- }
-
- // Draw the property inside the given rect
- void DrawEuler(Rect position, SerializedProperty property)
- {
- Vector3 euler = property.quaternionValue.eulerAngles;
- euler = EditorGUI.Vector3Field(position, "Offset", euler);
- property.quaternionValue = Quaternion.Euler(euler);
- }
-
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- DrawEuler(position, property.FindPropertyRelative(nameof(VRM10RotationOffset.Rotation)));
- }
- }
-}
diff --git a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta b/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
deleted file mode 100644
index 2f04a1587..000000000
--- a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 615a7cbd2c3cd5d42ab2719d6e74c1b8
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
index cdb0ada3f..e395506bf 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
@@ -15,9 +15,38 @@ namespace UniVRM10
[Range(0, 10.0f)]
public float Weight = 1.0f;
+ Quaternion _srcRestLocalQuatInverse;
+ Quaternion _dstRestLocalQuat;
+
+ void Awake()
+ {
+ if (Source == null)
+ {
+ this.enabled = false;
+ return;
+ }
+
+ _srcRestLocalQuatInverse = Quaternion.Inverse(Source.localRotation);
+ _dstRestLocalQuat = transform.localRotation;
+ }
+
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation-2
+ ///
+ /// srcDeltaQuat = srcRestQuat.inverse * srcQuat
+ /// targetQuat = Quaternion.slerp(
+ /// dstRestQuat,
+ /// dstRestQuat * srcDeltaQuat,
+ /// weight
+ /// )
+ ///
public override void Process()
{
- throw new System.NotImplementedException();
+ if (Source == null) return;
+
+ // local coords
+ var srcDeltaLocalQuat = _srcRestLocalQuatInverse * Source.localRotation;
+ transform.localRotation = Quaternion.SlerpUnclamped(_dstRestLocalQuat, _dstRestLocalQuat * srcDeltaLocalQuat, Weight);
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs
deleted file mode 100644
index a6382b5f1..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using UnityEngine;
-
-namespace UniVRM10
-{
- [Serializable]
- public struct VRM10RotationOffset
- {
- [SerializeField]
- public Quaternion Rotation;
-
- public static VRM10RotationOffset Identity => new VRM10RotationOffset
- {
- Rotation = Quaternion.identity,
- };
- }
-}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs.meta
deleted file mode 100644
index 4fc95a462..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 5b8a5228a8756d64684e8dca601ccafc
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs
index 87d7405f7..433693389 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs
@@ -1,4 +1,6 @@
-using UnityEngine;
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
+using UnityEngine;
namespace UniVRM10
{
@@ -16,11 +18,61 @@ namespace UniVRM10
public float Weight = 1.0f;
[SerializeField]
- public UniGLTF.Extensions.VRMC_node_constraint.AimAxis AimAxis;
+ public AimAxis AimAxis;
+ Vector3 GetAxisVector()
+ {
+ switch (AimAxis)
+ {
+ case AimAxis.PositiveX: return Vector3.right;
+ case AimAxis.NegativeX: return Vector3.left;
+ case AimAxis.PositiveY: return Vector3.up;
+ case AimAxis.NegativeY: return Vector3.down;
+ case AimAxis.PositiveZ: return Vector3.forward;
+ case AimAxis.NegativeZ: return Vector3.back;
+ default: throw new NotImplementedException();
+ }
+ }
+
+ Quaternion _dstRestLocalQuat;
+
+ void Awake()
+ {
+ if (Source == null)
+ {
+ this.enabled = false;
+ return;
+ }
+
+ _dstRestLocalQuat = transform.localRotation;
+ }
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation-1
+ ///
+ /// fromVec = aimAxis.applyQuaternion( dstParentWorldQuat * dstRestQuat )
+ /// toVec = ( srcWorldPos - dstWorldPos ).normalized
+ /// fromToQuat = Quaternion.fromToRotation( fromVec, toVec )
+ /// targetQuat = Quaternion.slerp(
+ /// dstRestQuat,
+ /// dstParentWorldQuat.inverse * fromToQuat * dstParentWorldQuat * dstRestQuat,
+ /// weight
+ /// )
+ ///
public override void Process()
{
- throw new System.NotImplementedException();
+ if (Source == null) return;
+
+ // world coords
+ var dstParentWorldQuat = transform.parent != null ? transform.parent.rotation : Quaternion.identity;
+ var fromVec = (dstParentWorldQuat * _dstRestLocalQuat) * GetAxisVector();
+ var toVec = (Source.position - transform.position).normalized;
+ var fromToQuat = Quaternion.FromToRotation(fromVec, toVec);
+
+ transform.rotation = Quaternion.SlerpUnclamped(
+ _dstRestLocalQuat,
+ Quaternion.Inverse(dstParentWorldQuat) * fromToQuat * dstParentWorldQuat * _dstRestLocalQuat,
+ Weight
+ );
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs
index 199d14a7b..cc75b75e8 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs
@@ -1,4 +1,6 @@
-using UnityEngine;
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
+using UnityEngine;
namespace UniVRM10
{
@@ -16,11 +18,65 @@ namespace UniVRM10
public float Weight = 1.0f;
[SerializeField]
- public UniGLTF.Extensions.VRMC_node_constraint.RollAxis RollAxis;
+ public RollAxis RollAxis;
+ Vector3 GetRollVector()
+ {
+ switch (RollAxis)
+ {
+ case RollAxis.X: return Vector3.right;
+ case RollAxis.Y: return Vector3.up;
+ case RollAxis.Z: return Vector3.forward;
+ default: throw new NotImplementedException();
+ }
+ }
+ Quaternion _srcRestLocalQuat;
+ Quaternion _dstRestLocalQuat;
+
+ void Awake()
+ {
+ if (Source == null)
+ {
+ this.enabled = false;
+ return;
+ }
+
+ _srcRestLocalQuat = Source.localRotation;
+ _dstRestLocalQuat = transform.localRotation;
+ }
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation
+ ///
+ /// deltaSrcQuat = srcRestQuat.inverse * srcQuat
+ /// deltaSrcQuatInParent = srcRestQuat * deltaSrcQuat * srcRestQuat.inverse // source to parent
+ /// deltaSrcQuatInDst = dstRestQuat.inverse * deltaSrcQuatInWorld * dstRestQuat // parent to destination
+ ///
+ /// toVec = rollAxis.applyQuaternion( deltaSrcQuatInDst )
+ /// fromToQuat = Quaternion.fromToRotation( rollAxis, toVec )
+ ///
+ /// targetQuat = Quaternion.slerp(
+ /// dstRestQuat,
+ /// dstRestQuat * fromToQuat.inverse * deltaSrcQuatInDst,
+ /// weight
+ /// )
+ ///
public override void Process()
{
- throw new System.NotImplementedException();
+ if (Source == null) return;
+
+ var deltaSrcQuat = Quaternion.Inverse(_srcRestLocalQuat) * Source.localRotation;
+ var deltaSrcQuatInParent = _srcRestLocalQuat * deltaSrcQuat * Quaternion.Inverse(_srcRestLocalQuat); // source to parent
+ var deltaSrcQuatInDst = Quaternion.Inverse(_dstRestLocalQuat) * deltaSrcQuatInParent * _dstRestLocalQuat; // parent to destination
+
+ var rollAxis = GetRollVector();
+ var toVec = deltaSrcQuatInDst * rollAxis;
+ var fromToQuat = Quaternion.FromToRotation(rollAxis, toVec);
+
+ transform.localRotation = Quaternion.SlerpUnclamped(
+ _dstRestLocalQuat,
+ _dstRestLocalQuat * Quaternion.Inverse(fromToQuat) * deltaSrcQuatInDst,
+ Weight
+ );
}
}
}