diff --git a/Assets/VRM10/Editor/Components/Constraint.meta b/Assets/VRM10/Editor/Components/Constraint.meta
deleted file mode 100644
index 2a1fd51d0..000000000
--- a/Assets/VRM10/Editor/Components/Constraint.meta
+++ /dev/null
@@ -1,8 +0,0 @@
-fileFormatVersion: 2
-guid: 7b369ee7eb21d1047bb03e139faa7eda
-folderAsset: yes
-DefaultImporter:
- externalObjects: {}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs b/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs
deleted file mode 100644
index 1365ea074..000000000
--- a/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using UnityEditor;
-using UnityEngine;
-
-namespace UniVRM10
-{
- public static class TRExtensions
- {
- public static void Draw(this TR tr, float size)
- {
- Handles.matrix = tr.TRS(size);
-
- // Handles.CubeHandleCap(0, Vector3.zero, Quaternion.identity, size, EventType.Repaint);
- Handles.color = Color.red;
- Handles.DrawLine(Vector3.zero, Vector3.right);
- Handles.color = Color.green;
- Handles.DrawLine(Vector3.zero, Vector3.up);
- Handles.color = Color.blue;
- Handles.DrawLine(Vector3.zero, Vector3.forward);
-
- Handles.color = Color.white;
- // xy
- Handles.DrawLine(Vector3.right + Vector3.up, Vector3.right);
- Handles.DrawLine(Vector3.right + Vector3.up, Vector3.up);
- // yz
- Handles.DrawLine(Vector3.up + Vector3.forward, Vector3.forward);
- Handles.DrawLine(Vector3.up + Vector3.forward, Vector3.up);
- // zx
- Handles.DrawLine(Vector3.forward + Vector3.right, Vector3.forward);
- Handles.DrawLine(Vector3.forward + Vector3.right, Vector3.right);
- }
- }
-}
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs
deleted file mode 100644
index fcd5e8c6b..000000000
--- a/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-using System.Text;
-using UnityEditor;
-using UnityEngine;
-
-namespace UniVRM10
-{
- public abstract class VRM10PositionRotationConstraintEditorBase : Editor
- {
- VRM10RotationPositionConstraintBase m_target;
-
- void OnEnable()
- {
- m_target = (VRM10RotationPositionConstraintBase)target;
- }
-
- static GUIStyle s_style;
- static GUIStyle Style
- {
- get
- {
- if (s_style == null)
- {
- s_style = new GUIStyle("box");
- }
- return s_style;
- }
- }
-
- ///
- /// Euler各を +- 180 にクランプする
- ///
- ///
- ///
- static Vector3 Clamp180(Vector3 v)
- {
- var x = v.x;
- while (x < -180) x += 360;
- while (x > 180) x -= 360;
- var y = v.y;
- while (y < -180) y += 360;
- while (y > 180) y -= 360;
- var z = v.z;
- while (z < -180) z += 360;
- while (z > 180) z -= 360;
- return new Vector3(x, y, z);
- }
-
- public void OnSceneGUI()
- {
- if (m_target.Source == null)
- {
- return;
- }
-
- // source offset
- if (!Application.isPlaying)
- {
- EditorGUI.BeginChangeCheck();
- Quaternion offset = Handles.RotationHandle(m_target.SourceOffset, m_target.Source.position);
- if (EditorGUI.EndChangeCheck())
- {
- Undo.RecordObject(m_target.GetComponent(), "source offset");
- m_target.SourceOffset = offset;
- }
- }
-
- // dest offset
- if (!Application.isPlaying)
- {
- EditorGUI.BeginChangeCheck();
- Quaternion offset = Handles.RotationHandle(m_target.DestinationOffset, m_target.GetComponent().transform.position);
- if (EditorGUI.EndChangeCheck())
- {
- Undo.RecordObject(m_target.GetComponent(), "dest offset");
- m_target.DestinationOffset = offset;
- }
- }
-
- // this to target line
- Handles.color = Color.yellow;
- Handles.DrawLine(m_target.Source.position, m_target.GetComponent().transform.position);
-
- var delta = Clamp180(m_target.Delta);
-
- // show source
- {
- var sb = new StringBuilder();
- sb.AppendLine();
- sb.AppendLine();
- sb.AppendLine($"{delta.x:0.00}");
- sb.AppendLine($"{delta.y:0.00}");
- sb.Append($"{delta.z:0.00}");
- Handles.Label(m_target.Source.position, sb.ToString(), Style);
- }
-
- // show dst
- {
- var sb = new StringBuilder();
- sb.AppendLine(m_target.Axes.HasFlag(AxisMask.X) ? $"{delta.x:0.00}" : "----");
- sb.AppendLine(m_target.Axes.HasFlag(AxisMask.Y) ? $"{delta.y:0.00}" : "----");
- sb.Append(m_target.Axes.HasFlag(AxisMask.Z) ? $"{delta.z:0.00}" : "----");
- Handles.Label(m_target.GetComponent().transform.position, sb.ToString(), Style);
- }
-
- m_target.GetSourceCoords().Draw(0.2f);
- if (Application.isPlaying)
- {
- Handles.matrix = m_target.GetSourceCurrent().TRS(0.05f);
- Handles.color = Color.yellow;
- Handles.DrawWireCube(Vector3.zero, Vector3.one);
- }
-
- m_target.GetDstCoords().Draw(0.2f);
- if (Application.isPlaying)
- {
- Handles.matrix = m_target.GetDstCurrent().TRS(0.05f);
- Handles.color = Color.yellow;
- Handles.DrawWireCube(Vector3.zero, Vector3.one);
- }
- }
- }
-}
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs
deleted file mode 100644
index 0b8140aec..000000000
--- a/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using UnityEditor;
-
-namespace UniVRM10
-{
- [CustomEditor(typeof(VRM10RotationConstraint))]
- public class VRM10RotationConstraintEditor : VRM10PositionRotationConstraintEditorBase
- {
- }
-}
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs.meta b/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs.meta
deleted file mode 100644
index ada1c4062..000000000
--- a/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: cd4ca141215a42c45a0036791f2f8a4d
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/VRM10/Editor/Components/VRM10Window.cs b/Assets/VRM10/Editor/Components/VRM10Window.cs
index 3612409eb..507ed3067 100644
--- a/Assets/VRM10/Editor/Components/VRM10Window.cs
+++ b/Assets/VRM10/Editor/Components/VRM10Window.cs
@@ -71,7 +71,7 @@ namespace UniVRM10
Transform m_head;
- public VRM10Constraint[] m_constraints;
+ public IVrm10Constraint[] m_constraints;
ScrollView m_scrollView = new ScrollView();
@@ -177,7 +177,7 @@ namespace UniVRM10
{
if (m_constraints == null)
{
- m_constraints = Root.GetComponentsInChildren();
+ m_constraints = Root.GetComponentsInChildren();
}
}
@@ -187,7 +187,7 @@ namespace UniVRM10
{
foreach (var c in m_constraints)
{
- EditorGUILayout.ObjectField(c, typeof(VRM10Constraint), true);
+ EditorGUILayout.ObjectField(c.GameObject, typeof(MonoBehaviour), true);
}
}
}
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/Runtime/Components/Constraint/IVrm10Constraint.cs b/Assets/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs
new file mode 100644
index 000000000..366003317
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs
@@ -0,0 +1,11 @@
+using UnityEngine;
+
+namespace UniVRM10
+{
+ public interface IVrm10Constraint
+ {
+ void Process();
+
+ GameObject GameObject { get; }
+ }
+}
diff --git a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta
similarity index 83%
rename from Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
rename to Assets/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta
index 2f04a1587..e14d79e8d 100644
--- a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
+++ b/Assets/VRM10/Runtime/Components/Constraint/IVrm10Constraint.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 615a7cbd2c3cd5d42ab2719d6e74c1b8
+guid: c859e278c34a69b438db39275ce25556
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs
deleted file mode 100644
index 8b91193e9..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System;
-using UniGLTF.Extensions.VRMC_node_constraint;
-using UnityEngine;
-
-namespace UniVRM10
-{
- public abstract class VRM10Constraint : MonoBehaviour
- {
- [SerializeField]
- [Range(0, 10.0f)]
- public float Weight = 1.0f;
-
- [SerializeField]
- public Transform ModelRoot = default;
-
- protected virtual void Reset()
- {
- var current = transform;
- while (true)
- {
- current = current.parent;
- if (current.parent == null)
- {
- // root
- break;
- }
- if (current.GetComponent() != null)
- {
- // model root
- break;
- }
- }
- ModelRoot = current;
- }
-
- #region Source
- public abstract Transform Source { get; set; }
-
- public ConstraintSource m_src;
-
- protected TR SourceInitialCoords()
- {
- if (m_src == null)
- {
- return TR.FromWorld(Source);
- }
- else
- {
- return TR.FromParent(Source) * m_src.LocalInitial;
- }
- }
- #endregion
-
- #region Destination
- protected ConstraintDestination m_dst;
-
- protected TR DestinationInitialCoords()
- {
- if (m_dst == null)
- {
- return TR.FromWorld(transform);
- }
- else
- {
- return TR.FromParent(transform) * m_dst.LocalInitial;
- }
- }
- #endregion
-
- public void Process()
- {
- if (Source == null)
- {
- enabled = false;
- return;
- }
-
- if (m_src == null)
- {
- m_src = new ConstraintSource(Source, ModelRoot);
- }
- if (m_dst == null)
- {
- m_dst = new ConstraintDestination(transform, ModelRoot);
- }
-
- OnProcess();
- }
-
- public abstract void OnProcess();
- }
-}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs.meta
deleted file mode 100644
index 37ffe7564..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: ded8c4db12c688b46814cf0bf925cacf
-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
deleted file mode 100644
index ba762d967..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using UniGLTF.Extensions.VRMC_node_constraint;
-using UnityEngine;
-
-namespace UniVRM10
-{
- ///
- /// 対象の初期回転と現在回転の差分(delta)を、自身の初期回転と自身の初期回転にdeltaを乗算したものに対してWeightでSlerpする。
- ///
- [DisallowMultipleComponent]
- public class VRM10RotationConstraint : VRM10RotationPositionConstraintBase
- {
- public override Vector3 Delta => Axes.Mask(Quaternion.Slerp(Quaternion.identity, m_delta.Rotation, Weight).eulerAngles);
-
- public override TR GetSourceCurrent()
- {
- var coords = GetSourceCoords();
- if (m_src == null)
- {
- return coords;
- }
- return coords * new TR(m_delta.Rotation);
- }
-
- public override TR GetDstCurrent()
- {
- var coords = GetDstCoords();
- if (m_src == null)
- {
- return coords;
- }
- return coords * new TR(m_delta.Rotation);
- }
-
- protected override void ApplyDelta()
- {
- m_dst.ApplyLocal(m_dst.LocalInitial * new TR(DestinationOffset) * new TR(Quaternion.Euler(Delta)));
- }
- }
-}
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/VRM10RotationPositionConstraintBase.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs
deleted file mode 100644
index 7c4cf74e8..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using System;
-using UniGLTF.Extensions.VRMC_node_constraint;
-using UnityEngine;
-
-namespace UniVRM10
-{
- public abstract class VRM10RotationPositionConstraintBase : VRM10Constraint
- {
- [SerializeField]
- [EnumFlags]
- AxisMask m_axes = AxisMask.X | AxisMask.Y | AxisMask.Z;
- public AxisMask Axes
- {
- get => m_axes;
- set => m_axes = value;
- }
-
- #region Source
- [Header("Source")]
- [SerializeField]
- Transform m_source = default;
- public override Transform Source
- {
- get => m_source;
- set => m_source = value;
- }
-
-
- [SerializeField]
- VRM10RotationOffset m_sourceOffset = VRM10RotationOffset.Identity;
-
- public Quaternion SourceOffset
- {
- get => m_sourceOffset.Rotation;
- set => m_sourceOffset.Rotation = value;
- }
- #endregion
-
-
- #region Destination
- [Header("Destination")]
- [SerializeField]
- public VRM10RotationOffset m_destinationOffset = VRM10RotationOffset.Identity;
-
- public Quaternion DestinationOffset
- {
- get => m_destinationOffset.Rotation;
- set => m_destinationOffset.Rotation = value;
- }
- #endregion
-
- public TR GetSourceCoords()
- {
- if (Source == null)
- {
- throw new ConstraintException(ConstraintException.ExceptionTypes.NoSource);
- }
-
- var init = SourceInitialCoords();
- return new TR(init.Rotation * SourceOffset, init.Translation);
- }
-
- public abstract TR GetSourceCurrent();
-
- public TR GetDstCoords()
- {
- var init = DestinationInitialCoords();
- return new TR(init.Rotation * DestinationOffset, init.Translation);
- }
-
- public abstract TR GetDstCurrent();
-
- ///
- /// Editorで設定値の変更を反映するために、クリアする
- ///
- void OnValidate()
- {
- // Debug.Log("Validate");
- if (m_src != null && m_src.ModelRoot != ModelRoot)
- {
- m_src = null;
- }
- if (m_dst != null && m_dst.ModelRoot != ModelRoot)
- {
- m_dst = null;
- }
- }
-
- public Component GetComponent()
- {
- return this;
- }
-
- protected TR m_delta;
- public abstract Vector3 Delta { get; }
-
- protected abstract void ApplyDelta();
-
- public override void OnProcess()
- {
- m_delta = m_src.Delta(SourceOffset);
- ApplyDelta();
- }
- }
-}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta
deleted file mode 100644
index bac4e2e09..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 07919df684c7a4c47a9492a2de417f66
-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
new file mode 100644
index 000000000..c1ba95896
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs
@@ -0,0 +1,80 @@
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.aimConstraint.schema.json
+ ///
+ [DisallowMultipleComponent]
+ public class Vrm10AimConstraint : MonoBehaviour, IVrm10Constraint
+ {
+ public GameObject GameObject => gameObject;
+
+ [SerializeField]
+ public Transform Source = default;
+
+ [SerializeField]
+ [Range(0, 10.0f)]
+ public float Weight = 1.0f;
+
+ [SerializeField]
+ 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 void Process()
+ {
+ 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/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta
similarity index 83%
rename from Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs.meta
rename to Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta
index c162c586c..205e03dc4 100644
--- a/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs.meta
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 46c1f13688fee134aa37a39a72433217
+guid: 37b0507e4ae49724898ca17cc3db6f1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs
new file mode 100644
index 000000000..292757d73
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs
@@ -0,0 +1,84 @@
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.rollConstraint.schema.json
+ ///
+ [DisallowMultipleComponent]
+ public class Vrm10RollConstraint : MonoBehaviour, IVrm10Constraint
+ {
+ public GameObject GameObject => gameObject;
+
+ [SerializeField]
+ public Transform Source = default;
+
+ [SerializeField]
+ [Range(0, 10.0f)]
+ public float Weight = 1.0f;
+
+ [SerializeField]
+ 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 void Process()
+ {
+ 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
+ );
+ }
+ }
+}
diff --git a/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta
similarity index 83%
rename from Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta
rename to Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta
index d86fabc8d..4c6dc5979 100644
--- a/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RollConstraint.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: f2d422c6e760aca49841f8acf44c0434
+guid: 1e864293edac89b40b9f79c23e7aa547
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs
new file mode 100644
index 000000000..5fb3a915a
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs
@@ -0,0 +1,54 @@
+using UnityEngine;
+
+namespace UniVRM10
+{
+ ///
+ /// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.rotationConstraint.schema.json
+ ///
+ [DisallowMultipleComponent]
+ public class Vrm10RotationConstraint : MonoBehaviour, IVrm10Constraint
+ {
+ public GameObject GameObject => gameObject;
+
+ [SerializeField]
+ public Transform Source = default;
+
+ [SerializeField]
+ [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 void Process()
+ {
+ 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/VRM10RotationConstraint.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs.meta
similarity index 100%
rename from Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs.meta
rename to Assets/VRM10/Runtime/Components/Constraint/Vrm10RotationConstraint.cs.meta
diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
index 7bcad98b1..1f18f0e81 100644
--- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
+++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs
@@ -12,7 +12,7 @@ namespace UniVRM10
public class Vrm10Runtime : IDisposable
{
private readonly Vrm10Instance m_target;
- private readonly VRM10Constraint[] m_constraints;
+ private readonly IVrm10Constraint[] m_constraints;
private readonly Transform m_head;
private readonly FastSpringBoneService m_fastSpringBoneService;
@@ -39,7 +39,7 @@ namespace UniVRM10
if (m_constraints == null)
{
- m_constraints = target.GetComponentsInChildren();
+ m_constraints = target.GetComponentsInChildren();
}
if (!Application.isPlaying)
diff --git a/Assets/VRM10/Runtime/Format/Constraints/Deserializer.g.cs b/Assets/VRM10/Runtime/Format/Constraints/Deserializer.g.cs
index 0788569ea..c68ee4494 100644
--- a/Assets/VRM10/Runtime/Format/Constraints/Deserializer.g.cs
+++ b/Assets/VRM10/Runtime/Format/Constraints/Deserializer.g.cs
@@ -79,6 +79,16 @@ public static Constraint Deserialize_Constraint(JsonNode parsed)
continue;
}
+ if(key=="roll"){
+ value.Roll = __constraint_Deserialize_Roll(kv.Value);
+ continue;
+ }
+
+ if(key=="aim"){
+ value.Aim = __constraint_Deserialize_Aim(kv.Value);
+ continue;
+ }
+
if(key=="rotation"){
value.Rotation = __constraint_Deserialize_Rotation(kv.Value);
continue;
@@ -88,6 +98,90 @@ public static Constraint Deserialize_Constraint(JsonNode parsed)
return value;
}
+public static RollConstraint __constraint_Deserialize_Roll(JsonNode parsed)
+{
+ var value = new RollConstraint();
+
+ foreach(var kv in parsed.ObjectItems())
+ {
+ var key = kv.Key.GetString();
+
+ if(key=="extensions"){
+ value.Extensions = new glTFExtensionImport(kv.Value);
+ continue;
+ }
+
+ if(key=="extras"){
+ value.Extras = new glTFExtensionImport(kv.Value);
+ continue;
+ }
+
+ if(key=="name"){
+ value.Name = kv.Value.GetString();
+ continue;
+ }
+
+ if(key=="source"){
+ value.Source = kv.Value.GetInt32();
+ continue;
+ }
+
+ if(key=="rollAxis"){
+ value.RollAxis = (RollAxis)Enum.Parse(typeof(RollAxis), kv.Value.GetString(), true);
+ continue;
+ }
+
+ if(key=="weight"){
+ value.Weight = kv.Value.GetSingle();
+ continue;
+ }
+
+ }
+ return value;
+}
+
+public static AimConstraint __constraint_Deserialize_Aim(JsonNode parsed)
+{
+ var value = new AimConstraint();
+
+ foreach(var kv in parsed.ObjectItems())
+ {
+ var key = kv.Key.GetString();
+
+ if(key=="extensions"){
+ value.Extensions = new glTFExtensionImport(kv.Value);
+ continue;
+ }
+
+ if(key=="extras"){
+ value.Extras = new glTFExtensionImport(kv.Value);
+ continue;
+ }
+
+ if(key=="name"){
+ value.Name = kv.Value.GetString();
+ continue;
+ }
+
+ if(key=="source"){
+ value.Source = kv.Value.GetInt32();
+ continue;
+ }
+
+ if(key=="aimAxis"){
+ value.AimAxis = (AimAxis)Enum.Parse(typeof(AimAxis), kv.Value.GetString(), true);
+ continue;
+ }
+
+ if(key=="weight"){
+ value.Weight = kv.Value.GetSingle();
+ continue;
+ }
+
+ }
+ return value;
+}
+
public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode parsed)
{
var value = new RotationConstraint();
@@ -116,11 +210,6 @@ public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode pars
continue;
}
- if(key=="axes"){
- value.Axes = __constraint__rotation_Deserialize_Axes(kv.Value);
- continue;
- }
-
if(key=="weight"){
value.Weight = kv.Value.GetSingle();
continue;
@@ -130,16 +219,5 @@ public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode pars
return value;
}
-public static bool[] __constraint__rotation_Deserialize_Axes(JsonNode parsed)
-{
- var value = new bool[parsed.GetArrayCount()];
- int i=0;
- foreach(var x in parsed.ArrayItems())
- {
- value[i++] = x.GetBoolean();
- }
- return value;
-}
-
} // GltfDeserializer
} // UniGLTF
diff --git a/Assets/VRM10/Runtime/Format/Constraints/Format.g.cs b/Assets/VRM10/Runtime/Format/Constraints/Format.g.cs
index 3f54d5ead..d9981025f 100644
--- a/Assets/VRM10/Runtime/Format/Constraints/Format.g.cs
+++ b/Assets/VRM10/Runtime/Format/Constraints/Format.g.cs
@@ -6,6 +6,67 @@ using System.Collections.Generic;
namespace UniGLTF.Extensions.VRMC_node_constraint
{
+ public enum RollAxis
+ {
+ X,
+ Y,
+ Z,
+
+ }
+
+ public class RollConstraint
+ {
+ // Dictionary object with extension-specific objects.
+ public object Extensions;
+
+ // Application-specific data.
+ public object Extras;
+
+ // The user-defined name of this object.
+ public string Name;
+
+ // The index of the node constrains the node.
+ public int? Source;
+
+ // The roll axis of the constraint.
+ public RollAxis RollAxis;
+
+ // The weight of the constraint.
+ public float? Weight;
+ }
+
+ public enum AimAxis
+ {
+ PositiveX,
+ NegativeX,
+ PositiveY,
+ NegativeY,
+ PositiveZ,
+ NegativeZ,
+
+ }
+
+ public class AimConstraint
+ {
+ // Dictionary object with extension-specific objects.
+ public object Extensions;
+
+ // Application-specific data.
+ public object Extras;
+
+ // The user-defined name of this object.
+ public string Name;
+
+ // The index of the node constrains the node.
+ public int? Source;
+
+ // The aim axis of the constraint.
+ public AimAxis AimAxis;
+
+ // The weight of the constraint.
+ public float? Weight;
+ }
+
public class RotationConstraint
{
// Dictionary object with extension-specific objects.
@@ -20,9 +81,6 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
// The index of the node constrains the node.
public int? Source;
- // Axes be constrained by this constraint, in X-Y-Z order.
- public bool[] Axes;
-
// The weight of the constraint.
public float? Weight;
}
@@ -35,6 +93,12 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
// Application-specific data.
public object Extras;
+ // A constraint that transfers a rotation around one axis of a source.
+ public RollConstraint Roll;
+
+ // A constraint that makes it look at a source object.
+ public AimConstraint Aim;
+
// A constraint that links the rotation with a source.
public RotationConstraint Rotation;
}
@@ -52,7 +116,7 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
// Specification version of VRMC_node_constraint
public string SpecVersion;
- // Contains position, rotation, or aim
+ // Contains roll, aim, or rotation
public Constraint Constraint;
}
}
diff --git a/Assets/VRM10/Runtime/Format/Constraints/Serializer.g.cs b/Assets/VRM10/Runtime/Format/Constraints/Serializer.g.cs
index 4a88b27fb..0828fd008 100644
--- a/Assets/VRM10/Runtime/Format/Constraints/Serializer.g.cs
+++ b/Assets/VRM10/Runtime/Format/Constraints/Serializer.g.cs
@@ -71,6 +71,16 @@ public static void Serialize_Constraint(JsonFormatter f, Constraint value)
(value.Extras as glTFExtension).Serialize(f);
}
+ if(value.Roll!=null){
+ f.Key("roll");
+ __constraint_Serialize_Roll(f, value.Roll);
+ }
+
+ if(value.Aim!=null){
+ f.Key("aim");
+ __constraint_Serialize_Aim(f, value.Aim);
+ }
+
if(value.Rotation!=null){
f.Key("rotation");
__constraint_Serialize_Rotation(f, value.Rotation);
@@ -79,6 +89,82 @@ public static void Serialize_Constraint(JsonFormatter f, Constraint value)
f.EndMap();
}
+public static void __constraint_Serialize_Roll(JsonFormatter f, RollConstraint value)
+{
+ f.BeginMap();
+
+
+ if(value.Extensions!=null){
+ f.Key("extensions");
+ (value.Extensions as glTFExtension).Serialize(f);
+ }
+
+ if(value.Extras!=null){
+ f.Key("extras");
+ (value.Extras as glTFExtension).Serialize(f);
+ }
+
+ if(!string.IsNullOrEmpty(value.Name)){
+ f.Key("name");
+ f.Value(value.Name);
+ }
+
+ if(value.Source.HasValue){
+ f.Key("source");
+ f.Value(value.Source.GetValueOrDefault());
+ }
+
+ if(true){
+ f.Key("rollAxis");
+ f.Value(value.RollAxis.ToString());
+ }
+
+ if(value.Weight.HasValue){
+ f.Key("weight");
+ f.Value(value.Weight.GetValueOrDefault());
+ }
+
+ f.EndMap();
+}
+
+public static void __constraint_Serialize_Aim(JsonFormatter f, AimConstraint value)
+{
+ f.BeginMap();
+
+
+ if(value.Extensions!=null){
+ f.Key("extensions");
+ (value.Extensions as glTFExtension).Serialize(f);
+ }
+
+ if(value.Extras!=null){
+ f.Key("extras");
+ (value.Extras as glTFExtension).Serialize(f);
+ }
+
+ if(!string.IsNullOrEmpty(value.Name)){
+ f.Key("name");
+ f.Value(value.Name);
+ }
+
+ if(value.Source.HasValue){
+ f.Key("source");
+ f.Value(value.Source.GetValueOrDefault());
+ }
+
+ if(true){
+ f.Key("aimAxis");
+ f.Value(value.AimAxis.ToString());
+ }
+
+ if(value.Weight.HasValue){
+ f.Key("weight");
+ f.Value(value.Weight.GetValueOrDefault());
+ }
+
+ f.EndMap();
+}
+
public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationConstraint value)
{
f.BeginMap();
@@ -104,11 +190,6 @@ public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationCons
f.Value(value.Source.GetValueOrDefault());
}
- if(value.Axes!=null&&value.Axes.Count()>=3){
- f.Key("axes");
- __constraint__rotation_Serialize_Axes(f, value.Axes);
- }
-
if(value.Weight.HasValue){
f.Key("weight");
f.Value(value.Weight.GetValueOrDefault());
@@ -117,17 +198,5 @@ public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationCons
f.EndMap();
}
-public static void __constraint__rotation_Serialize_Axes(JsonFormatter f, bool[] value)
-{
- f.BeginList();
-
- foreach(var item in value)
- {
- f.Value(item);
-
- }
- f.EndList();
-}
-
} // class
} // namespace
diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
index fb47fc8a7..aace371d0 100644
--- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
+++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
@@ -401,14 +401,43 @@ namespace UniVRM10
static void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter, List nodes)
{
- var constraints = vrmController.GetComponentsInChildren();
+ var constraints = vrmController.GetComponentsInChildren();
foreach (var constraint in constraints)
{
- UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint vrmConstraint = default;
+ var vrmConstraint = new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint
+ {
+ SpecVersion = NODE_CONSTRAINT_SPEC_VERSION,
+ Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint
+ {
+ },
+ };
+
switch (constraint)
{
- case VRM10RotationConstraint rotationConstraint:
- vrmConstraint = ExportRotationConstraint(rotationConstraint, model, converter);
+ case Vrm10AimConstraint aimConstraint:
+ vrmConstraint.Constraint.Aim = new UniGLTF.Extensions.VRMC_node_constraint.AimConstraint
+ {
+ Source = model.Nodes.IndexOf(converter.Nodes[aimConstraint.Source.gameObject]),
+ Weight = aimConstraint.Weight,
+ AimAxis = aimConstraint.AimAxis,
+ };
+ break;
+
+ case Vrm10RollConstraint rollConstraint:
+ vrmConstraint.Constraint.Roll = new UniGLTF.Extensions.VRMC_node_constraint.RollConstraint
+ {
+ Source = model.Nodes.IndexOf(converter.Nodes[rollConstraint.Source.gameObject]),
+ Weight = rollConstraint.Weight,
+ RollAxis = rollConstraint.RollAxis,
+ };
+ break;
+
+ case Vrm10RotationConstraint rotationConstraint:
+ vrmConstraint.Constraint.Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint
+ {
+ Source = model.Nodes.IndexOf(converter.Nodes[rotationConstraint.Source.gameObject]),
+ Weight = rotationConstraint.Weight,
+ };
break;
default:
@@ -416,7 +445,7 @@ namespace UniVRM10
}
// serialize to gltfNode
- var node = converter.Nodes[constraint.gameObject];
+ var node = converter.Nodes[constraint.GameObject];
var nodeIndex = model.Nodes.IndexOf(node);
var gltfNode = nodes[nodeIndex];
UniGLTF.Extensions.VRMC_node_constraint.GltfSerializer.SerializeTo(ref gltfNode.extensions, vrmConstraint);
@@ -433,22 +462,6 @@ namespace UniVRM10
};
}
- static UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint ExportRotationConstraint(VRM10RotationConstraint c, Model model, ModelExporter converter)
- {
- return new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint
- {
- SpecVersion = NODE_CONSTRAINT_SPEC_VERSION,
- Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint
- {
- Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint
- {
- Source = model.Nodes.IndexOf(converter.Nodes[c.Source.gameObject]),
- Axes = ToArray(c.Axes),
- Weight = c.Weight,
- },
- },
- };
- }
static UniGLTF.Extensions.VRMC_vrm.MeshAnnotation ExportMeshAnnotation(RendererFirstPersonFlags flags, Transform root, Func getIndex)
{
diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
index aa78c595e..355b1fc47 100644
--- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
+++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
@@ -652,6 +652,17 @@ namespace UniVRM10
return v;
}
+ ///
+ /// https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_node_constraint-1.0_draft
+ ///
+ /// * roll
+ /// * aim
+ /// * rotaton
+ ///
+ ///
+ ///
+ ///
+ ///
async Task LoadConstraintAsync(IAwaitCaller awaitCaller, Vrm10Instance controller)
{
for (int i = 0; i < Data.GLTF.nodes.Count; ++i)
@@ -661,14 +672,32 @@ namespace UniVRM10
{
var constraint = ext.Constraint;
var node = Nodes[i];
- if (constraint.Rotation != null)
+ if (constraint.Roll != null)
{
- var r = constraint.Rotation;
- var rotationConstraint = node.gameObject.AddComponent();
- rotationConstraint.Source = Nodes[r.Source.Value];
- rotationConstraint.Axes = ConstraintAxes(r.Axes);
- rotationConstraint.Weight = r.Weight.Value;
- rotationConstraint.ModelRoot = Root.transform;
+ var roll = constraint.Roll;
+ var component = node.gameObject.AddComponent();
+ component.Source = Nodes[roll.Source.Value];
+ component.Weight = roll.Weight.Value;
+ component.RollAxis = roll.RollAxis;
+ }
+ else if (constraint.Aim != null)
+ {
+ var aim = constraint.Aim;
+ var component = node.gameObject.AddComponent();
+ component.Source = Nodes[aim.Source.Value];
+ component.Weight = aim.Weight.Value;
+ component.AimAxis = aim.AimAxis;
+ }
+ else if (constraint.Rotation != null)
+ {
+ var rotation = constraint.Rotation;
+ var component = node.gameObject.AddComponent();
+ component.Source = Nodes[rotation.Source.Value];
+ component.Weight = rotation.Weight.Value;
+ }
+ else
+ {
+ throw new NotImplementedException();
}
}
}
diff --git a/vrm-specification b/vrm-specification
index 084c4fd3a..e93a3a077 160000
--- a/vrm-specification
+++ b/vrm-specification
@@ -1 +1 @@
-Subproject commit 084c4fd3a19f4a94b854c35661151c23d526d26a
+Subproject commit e93a3a0776660e38bbced4c8219217c21f743628