diff --git a/Assets/VRM10/Editor/Components/Constraint.meta b/Assets/VRM10/Editor/Components/Constraint.meta
new file mode 100644
index 000000000..2a1fd51d0
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint.meta
@@ -0,0 +1,8 @@
+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
new file mode 100644
index 000000000..1365ea074
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs
@@ -0,0 +1,32 @@
+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/Runtime/Components/Constraint/TRS.cs.meta b/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta
similarity index 83%
rename from Assets/VRM10/Runtime/Components/Constraint/TRS.cs.meta
rename to Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta
index 8d5e46b4b..d86fabc8d 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/TRS.cs.meta
+++ b/Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: b00df4c7268fefe42a16416935bbceb5
+guid: f2d422c6e760aca49841f8acf44c0434
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs
new file mode 100644
index 000000000..17d2c13e1
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs
@@ -0,0 +1,88 @@
+using System.Text;
+using UnityEditor;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ [CustomEditor(typeof(VRM10AimConstraint))]
+ public class VRM10AimConstraintEditor : Editor
+ {
+ VRM10AimConstraint m_target;
+
+ void OnEnable()
+ {
+ m_target = (VRM10AimConstraint)target;
+ }
+
+ static GUIStyle s_style;
+ static GUIStyle Style
+ {
+ get
+ {
+ if (s_style == null)
+ {
+ s_style = new GUIStyle("box");
+ }
+ return s_style;
+ }
+ }
+
+ static void DrawAimUp(Quaternion rot, Vector3 pos, Color c)
+ {
+ Handles.matrix = Matrix4x4.identity;
+ Handles.color = c;
+ // aim
+ var aim = pos + rot * Vector3.forward * 0.3f;
+ Handles.DrawLine(pos, aim);
+ Handles.Label(aim, "aim");
+ // up
+ var up = pos + rot * Vector3.up * 0.3f;
+ Handles.DrawLine(pos, up);
+ Handles.Label(up, "up");
+ }
+
+ public void OnSceneGUI()
+ {
+ if (m_target.Source == null)
+ {
+ return;
+ }
+
+ // this to target line
+ Handles.color = Color.yellow;
+ Handles.DrawLine(m_target.Source.position, m_target.transform.position);
+
+ var pos = m_target.transform.position;
+
+ var pr = m_target.ParentRotation;
+
+ if (m_target.Logic == null)
+ {
+ EditorGUI.BeginChangeCheck();
+ TR.FromWorld(m_target.transform).Draw(0.2f);
+
+ Handles.matrix = Matrix4x4.identity;
+ var rot = Handles.RotationHandle(pr * m_target.DestinationOffset, pos);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(m_target, "Rotated RotateAt Point");
+ m_target.DestinationOffset = Quaternion.Inverse(pr) * rot;
+ }
+
+ DrawAimUp(rot, pos, Color.yellow);
+ }
+ else
+ {
+ var init = m_target.ParentRotation * m_target.Logic.InitialLocalRotation;
+ DrawAimUp(init * m_target.DestinationOffset, m_target.transform.position, Color.yellow);
+ new TR(init, m_target.transform.position).Draw(0.2f);
+ DrawAimUp(init * m_target.DestinationOffset * m_target.Delta, m_target.transform.position, Color.magenta);
+
+ var sb = new StringBuilder();
+ sb.AppendLine($"yaw: {m_target.Yaw:0.}");
+ sb.AppendLine($"pitch: {m_target.Pitch:0.}");
+ Handles.Label(m_target.transform.position, sb.ToString(), Style);
+ }
+ }
+ }
+}
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs.meta b/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs.meta
new file mode 100644
index 000000000..324632787
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10AimConstraintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 53c7ae04ba8deea40acc6439a2fe11cd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs
new file mode 100644
index 000000000..78e9653c5
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs
@@ -0,0 +1,11 @@
+using System.Text;
+using UnityEditor;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ [CustomEditor(typeof(VRM10PositionConstraint))]
+ public class VRM10PositionConstraintEditor : VRM10PositionRotationConstraintEditorBase
+ {
+ }
+}
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs.meta b/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs.meta
new file mode 100644
index 000000000..7abff9c34
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10PositionConstraintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d4c6d6f5f37e41e47bd02bdf1dbda864
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs
new file mode 100644
index 000000000..99ee8fbd6
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs
@@ -0,0 +1,124 @@
+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.GetSource() == null)
+ {
+ return;
+ }
+
+ // source offset
+ if (!Application.isPlaying)
+ {
+ EditorGUI.BeginChangeCheck();
+ Quaternion offset = Handles.RotationHandle(m_target.SourceOffset, m_target.GetSource().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.GetSource().position, m_target.GetComponent().transform.position);
+
+ var delta = Clamp180(m_target.Delta);
+
+ // show source
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine();
+ sb.AppendLine();
+ sb.AppendLine($"source: {m_target.SourceCoordinate}");
+ sb.AppendLine($"{delta.x:0.00}");
+ sb.AppendLine($"{delta.y:0.00}");
+ sb.Append($"{delta.z:0.00}");
+ Handles.Label(m_target.GetSource().position, sb.ToString(), Style);
+ }
+
+ // show dst
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine($"constraint: {m_target.DestinationCoordinate}");
+ sb.AppendLine(m_target.FreezeAxes.HasFlag(AxisMask.X) ? $"freeze" : $"{delta.x:0.00}");
+ sb.AppendLine(m_target.FreezeAxes.HasFlag(AxisMask.Y) ? $"freeze" : $"{delta.y:0.00}");
+ sb.Append(m_target.FreezeAxes.HasFlag(AxisMask.Z) ? $"freeze" : $"{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/VRM10PostionRotationConstraintEditorBase.cs.meta b/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs.meta
new file mode 100644
index 000000000..c162c586c
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10PostionRotationConstraintEditorBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 46c1f13688fee134aa37a39a72433217
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs b/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs
new file mode 100644
index 000000000..870cb2f28
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs
@@ -0,0 +1,11 @@
+using System.Text;
+using UnityEditor;
+using UnityEngine;
+
+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
new file mode 100644
index 000000000..ada1c4062
--- /dev/null
+++ b/Assets/VRM10/Editor/Components/Constraint/VRM10RotationConstraintEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cd4ca141215a42c45a0036791f2f8a4d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs b/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs
new file mode 100644
index 000000000..8f7ba6e5c
--- /dev/null
+++ b/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs
@@ -0,0 +1,64 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+
+namespace UniVRM10
+{
+ ///
+ /// Flag設定したEnumのインスペクター表示を変えるクラス
+ ///
+ [CustomPropertyDrawer(typeof(EnumFlagsAttribute))]
+ public sealed class EnumFlagsAttributeDrawer : PropertyDrawer
+ {
+ public override void OnGUI(
+ Rect position,
+ SerializedProperty prop,
+ GUIContent label
+ )
+ {
+ var buttonsIntValue = 0;
+ var enumLength = prop.enumNames.Length;
+ var labelWidth = EditorGUIUtility.labelWidth;
+ var buttonPressed = new bool[enumLength];
+ var buttonWidth = (position.width - labelWidth) / enumLength;
+
+ var labelPos = new Rect(
+ position.x,
+ position.y,
+ labelWidth,
+ position.height
+ );
+ EditorGUI.LabelField(labelPos, label);
+ EditorGUI.BeginChangeCheck();
+
+ for (int i = 0; i < enumLength; i++)
+ {
+ buttonPressed[i] = (prop.intValue & (1 << i)) == 1 << i;
+
+ var buttonPos = new Rect(
+ position.x + labelWidth + buttonWidth * i,
+ position.y,
+ buttonWidth,
+ position.height
+ );
+
+ buttonPressed[i] = GUI.Toggle(
+ buttonPos,
+ buttonPressed[i],
+ prop.enumNames[i],
+ "Button"
+ );
+
+ if (buttonPressed[i])
+ {
+ buttonsIntValue += 1 << i;
+ }
+ }
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ prop.intValue = buttonsIntValue;
+ }
+ }
+ }
+}
diff --git a/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta b/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta
new file mode 100644
index 000000000..3ea85c8eb
--- /dev/null
+++ b/Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 62a17679a0c7f7843beaa97ae4121d63
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs b/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
new file mode 100644
index 000000000..a893ecbe7
--- /dev/null
+++ b/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
@@ -0,0 +1,28 @@
+
+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
new file mode 100644
index 000000000..2f04a1587
--- /dev/null
+++ b/Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
@@ -0,0 +1,11 @@
+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/ConstRaintException.cs b/Assets/VRM10/Runtime/Components/Constraint/ConstRaintException.cs
new file mode 100644
index 000000000..5ec92109a
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/ConstRaintException.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace UniVRM10
+{
+ public class ConstraintException : Exception
+ {
+ public enum ExceptionTypes
+ {
+ NoSource,
+ NoModelWithModelSpace
+ }
+
+ public readonly ExceptionTypes Type;
+
+ public ConstraintException(ExceptionTypes type)
+ {
+ Type = type;
+ }
+ }
+}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta
new file mode 100644
index 000000000..afc5fb285
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/ConstRaintException.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 13be84b73aeb40641978e083c750590d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs b/Assets/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs
index 21cf3b0f2..10af3f818 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/ConstraintDestination.cs
@@ -1,83 +1,36 @@
-using System;
-using UniGLTF.Extensions.VRMC_node_constraint;
using UnityEngine;
namespace UniVRM10
{
- class ConstraintDestination
+ public class ConstraintDestination
{
- readonly Transform m_transform;
- readonly ObjectSpace m_coords;
+ public readonly Transform Destination;
+ public readonly TR ModelInitial;
+ public readonly TR LocalInitial;
+ public readonly Transform ModelRoot;
- readonly TRS m_initial;
-
- public ConstraintDestination(Transform t, ObjectSpace coords, Transform modelRoot = null)
+ public ConstraintDestination(Transform t, Transform modelRoot = null)
{
- m_transform = t;
- m_coords = coords;
+ Destination = t;
+ LocalInitial = TR.FromLocal(t);
- switch (m_coords)
+ if (modelRoot != null)
{
- // case ObjectSpace.World:
- // m_initial = TRS.GetWorld(t);
- // break;
-
- case ObjectSpace.local:
- m_initial = TRS.GetLocal(t);
- break;
-
- case ObjectSpace.model:
- m_initial = TRS.GetRelative(t, modelRoot.worldToLocalMatrix);
- break;
-
- default:
- throw new NotImplementedException();
+ ModelRoot = modelRoot;
+ ModelInitial = TR.FromRelative(t, modelRoot);
}
}
- public void ApplyTranslation(Vector3 delta, float weight, Transform modelRoot = null)
+ public void ApplyLocal(TR tr)
{
- var value = m_initial.Translation + delta * weight;
- switch (m_coords)
- {
- // case DestinationCoordinates.World:
- // m_transform.position = value;
- // break;
-
- case ObjectSpace.local:
- m_transform.localPosition = value;
- break;
-
- case ObjectSpace.model:
- m_transform.position = modelRoot.localToWorldMatrix.MultiplyPoint(value);
- break;
-
- default:
- throw new NotImplementedException();
- }
+ Destination.localPosition = tr.Translation;
+ Destination.localRotation = tr.Rotation;
}
- public void ApplyRotation(Quaternion delta, float weight, Transform modelRoot = null)
+ public void ApplyModel(TR tr)
{
- // 0~1 で clamp しない slerp
- var value = Quaternion.LerpUnclamped(Quaternion.identity, delta, weight) * m_initial.Rotation;
- switch (m_coords)
- {
- // case DestinationCoordinates.World:
- // m_transform.rotation = value;
- // break;
-
- case ObjectSpace.local:
- m_transform.localRotation = value;
- break;
-
- case ObjectSpace.model:
- m_transform.rotation = modelRoot.rotation * value;
- break;
-
- default:
- throw new NotImplementedException();
- }
+ Destination.position = tr.Translation;
+ Destination.rotation = tr.Rotation;
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/ConstraintSource.cs b/Assets/VRM10/Runtime/Components/Constraint/ConstraintSource.cs
index a199b2de4..3b0fa4a79 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/ConstraintSource.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/ConstraintSource.cs
@@ -4,74 +4,37 @@ using UniGLTF.Extensions.VRMC_node_constraint;
namespace UniVRM10
{
- class ConstraintSource
+ public class ConstraintSource
{
- readonly Transform m_modelRoot;
+ public readonly Transform ModelRoot;
+ readonly Transform Source;
- readonly Transform m_transform;
+ public readonly TR ModelInitial;
- readonly ObjectSpace m_coords;
+ public readonly TR LocalInitial;
- readonly TRS m_initial;
-
- public Vector3 TranslationDelta
+ public TR Delta(ObjectSpace coords, Quaternion sourceRotationOffset)
{
- get
- {
- switch (m_coords)
- {
- // case ObjectSpace.World: return m_transform.position - m_initial.Translation;
- case ObjectSpace.local: return m_transform.localPosition - m_initial.Translation;
- case ObjectSpace.model: return m_modelRoot.worldToLocalMatrix.MultiplyPoint(m_transform.position) - m_initial.Translation;
- default: throw new NotImplementedException();
- }
- }
- }
-
- public Quaternion RotationDelta
- {
- get
- {
- switch (m_coords)
- {
- // 右からかけるか、左からかけるか、それが問題なのだ
- // case SourceCoordinates.World: return m_transform.rotation * Quaternion.Inverse(m_initial.Rotation);
- case ObjectSpace.local: return m_transform.localRotation * Quaternion.Inverse(m_initial.Rotation);
- case ObjectSpace.model: return m_transform.rotation * Quaternion.Inverse(m_modelRoot.rotation) * Quaternion.Inverse(m_initial.Rotation);
- default: throw new NotImplementedException();
- }
- }
- }
-
- public ConstraintSource(Transform t, ObjectSpace coords, Transform modelRoot = null)
- {
- m_transform = t;
- m_coords = coords;
-
switch (coords)
{
- // case SourceCoordinates.World:
- // m_initial = TRS.GetWorld(t);
- // break;
+ // case SourceCoordinates.World: return m_transform.rotation * Quaternion.Inverse(m_initial.Rotation);
+ case ObjectSpace.local: return TR.FromLocal(Source) * (LocalInitial * new TR(sourceRotationOffset)).Inverse();
+ case ObjectSpace.model: return TR.FromWorld(Source) * (TR.FromWorld(ModelRoot) * ModelInitial * new TR(sourceRotationOffset)).Inverse();
+ default: throw new NotImplementedException();
+ }
+ }
- case ObjectSpace.local:
- m_initial = TRS.GetLocal(t);
- break;
+ public ConstraintSource(Transform t, Transform modelRoot = null)
+ {
+ {
+ Source = t;
+ LocalInitial = TR.FromLocal(t);
+ }
- case ObjectSpace.model:
- {
- var world = TRS.GetWorld(t);
- m_modelRoot = modelRoot;
- m_initial = new TRS
- {
- Translation = modelRoot.worldToLocalMatrix.MultiplyPoint(world.Translation),
- Rotation = world.Rotation * Quaternion.Inverse(m_modelRoot.rotation),
- };
- }
- break;
-
- default:
- throw new NotImplementedException();
+ if (modelRoot != null)
+ {
+ ModelRoot = modelRoot;
+ ModelInitial = TR.FromLocal(t);
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/TR.cs b/Assets/VRM10/Runtime/Components/Constraint/TR.cs
new file mode 100644
index 000000000..de7bfa81a
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/TR.cs
@@ -0,0 +1,62 @@
+using UnityEngine;
+
+namespace UniVRM10
+{
+ public struct TR
+ {
+ public Quaternion Rotation;
+ public Vector3 Translation;
+
+ public static TR Identity => new TR(Quaternion.identity, Vector3.zero);
+
+ public static TR FromWorld(Transform t) => new TR(t.rotation, t.position);
+
+ public static TR FromParent(Transform t) => t.parent != null ? FromWorld(t.parent) : TR.Identity;
+
+ public static TR FromLocal(Transform t) => new TR(t.localRotation, t.localPosition);
+
+ public static TR FromRelative(Transform t, Transform from)
+ {
+ var toRelative = from.worldToLocalMatrix;
+ return new TR(toRelative.rotation * t.rotation, toRelative.MultiplyPoint(t.position));
+ }
+
+ public TR(Quaternion r, Vector3 t)
+ {
+ Rotation = r;
+ Translation = t;
+ }
+
+ public TR(Quaternion r) : this(r, Vector3.zero)
+ {
+ }
+
+ public TR(Vector3 t) : this(Quaternion.identity, t)
+ {
+ }
+
+ public Matrix4x4 TRS(float s) => Matrix4x4.TRS(Translation, Rotation, new Vector3(s, s, s));
+
+
+ ///
+ /// R1|T1 R2|T2 x R1R2|R1T2+T1 x
+ /// --+-- --+-- y => ----+------- y
+ /// 0| 1 0| 1 z 0| 1 z
+ ///
+ ///
+ ///
+ ///
+ public static TR operator *(TR a, TR b) => new TR(a.Rotation * b.Rotation, a.Rotation * b.Translation + a.Translation);
+
+ ///
+ /// R|0 1|T R|RT
+ /// -+- -+- => -+--
+ /// 0|1 0|1 0| 1
+ ///
+ public TR Inverse()
+ {
+ var inv = Quaternion.Inverse(Rotation);
+ return new TR(inv, inv * -Translation);
+ }
+ }
+}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/TR.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/TR.cs.meta
new file mode 100644
index 000000000..b5f7a2033
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/TR.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6ddd45ffb38279b488938471919fc089
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/Components/Constraint/TRS.cs b/Assets/VRM10/Runtime/Components/Constraint/TRS.cs
deleted file mode 100644
index fffdf7c55..000000000
--- a/Assets/VRM10/Runtime/Components/Constraint/TRS.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using UnityEngine;
-
-namespace UniVRM10
-{
- struct TRS
- {
- public Vector3 Translation;
- public Quaternion Rotation;
- public Vector3 Scale;
-
- public static TRS GetWorld(Transform t)
- {
- return new TRS
- {
- Translation = t.position,
- Rotation = t.rotation,
- Scale = t.lossyScale,
- };
- }
-
- public static TRS GetLocal(Transform t)
- {
- return new TRS
- {
- Translation = t.localPosition,
- Rotation = t.localRotation,
- Scale = t.localScale,
- };
- }
-
- public static TRS GetRelative(Transform t, Matrix4x4 toRelative)
- {
- return new TRS
- {
- Translation = toRelative.MultiplyPoint(t.position),
- Rotation = toRelative.rotation * t.rotation,
- Scale = toRelative.MultiplyVector(t.lossyScale),
- };
- }
- }
-}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10AimConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10AimConstraint.cs
index eba3d3f5b..2d7d22413 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10AimConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10AimConstraint.cs
@@ -20,108 +20,33 @@ namespace UniVRM10
[Range(0, 10.0f)]
public float Weight = 1.0f;
- ///
- /// Forward
- ///
- [SerializeField]
- public Vector3 AimVector = Vector3.forward;
+ public Quaternion ParentRotation => transform.parent == null ? Quaternion.identity : transform.parent.rotation;
[SerializeField]
- public Vector3 UpVector = Vector3.up;
+ public Quaternion DestinationOffset = Quaternion.identity;
- [SerializeField]
- public Vector3 RightVector;
-
- Quaternion m_selfInitial;
- Matrix4x4 m_coords;
+ public class AimLogic
+ {
+ public readonly Quaternion InitialLocalRotation;
+ public AimLogic(Quaternion initialLocalRotation)
+ {
+ InitialLocalRotation = initialLocalRotation;
+ }
+ }
+ public AimLogic Logic { get; private set; }
void Start()
{
if (Source == null)
{
+ enabled = false;
return;
}
- m_selfInitial = transform.rotation;
-
- // 正規直交座標を作る
- // Y x Z => X
- AimVector.Normalize();
- UpVector.Normalize();
- RightVector = Vector3.Cross(UpVector, AimVector).normalized;
- // 直交するように再計算
- UpVector = Vector3.Cross(AimVector, RightVector).normalized;
- m_coords = new Matrix4x4(
- new Vector4(RightVector.x, RightVector.y, RightVector.z, 0),
- new Vector4(UpVector.x, UpVector.y, UpVector.z, 0),
- new Vector4(AimVector.x, AimVector.y, AimVector.z, 0),
- new Vector4(0, 0, 0, 1)
- );
- }
-
- static (float, int, float, int) CalcYawPitch(Matrix4x4 m, Vector3 target)
- {
- var zaxis = Vector3.Project(target, m.GetColumn(2));
- var yaxis = Vector3.Project(target, m.GetColumn(1));
- var xaxis = Vector3.Project(target, m.GetColumn(0));
-
- var xDot = Vector3.Dot(xaxis, m.GetColumn(0)) > 0;
- var yDot = Vector3.Dot(yaxis, m.GetColumn(1)) > 0;
- var zDot = Vector3.Dot(zaxis, m.GetColumn(2)) > 0;
-
- // xz
- var yaw = (float)System.Math.Atan2(xaxis.magnitude, zaxis.magnitude) * Mathf.Rad2Deg;
- var yawQuadrant = -1;
- if (xDot && zDot)
+ if (Logic == null)
{
- // 1st(0-90)
- yawQuadrant = 0;
+ Logic = new AimLogic(transform.localRotation);
}
- else if (xDot && !zDot)
- {
- // 2nd(90-180)
- yawQuadrant = 1;
- }
- else if (!xDot && !zDot)
- {
- // 3rd
- yawQuadrant = 2;
- }
- else if (!xDot && zDot)
- {
- // 4th
- yawQuadrant = 3;
- }
- else
- {
- throw new NotImplementedException();
- }
-
- // xy
- var pitch = (float)System.Math.Atan2(yaxis.magnitude, (xaxis + zaxis).magnitude) * Mathf.Rad2Deg;
- var pitchQuadrant = -1;
- if (yDot && zDot)
- {
- // 1st
- pitchQuadrant = 0;
- }
- else if (yDot & !zDot)
- {
- // 2nd
- pitchQuadrant = 1;
- }
- else if (!yDot & !zDot)
- {
- // 3rd
- pitchQuadrant = 2;
- }
- else if (!yDot & zDot)
- {
- // 4th
- pitchQuadrant = 3;
- }
-
- return (yaw, yawQuadrant, pitch, pitchQuadrant);
}
///
@@ -130,45 +55,21 @@ namespace UniVRM10
///
public override void Process()
{
- if (Source == null)
+ if (Logic == null)
{
return;
}
- var localPosition = transform.worldToLocalMatrix.MultiplyPoint(Source.position);
- // var (yaw, pitch) = CalcYawPitch(m_coords, localPosition);
+ var zAxis = (Source.position - transform.position).normalized;
+ var xAxis = Vector3.Cross(Vector3.up, zAxis);
+ var yAxis = Vector3.Cross(zAxis, xAxis);
+ var m = new Matrix4x4(xAxis, yAxis, zAxis, new Vector4(0, 0, 0, 1));
+ Delta = Quaternion.Inverse(ParentRotation * Logic.InitialLocalRotation * DestinationOffset) * m.rotation;
+ transform.rotation = ParentRotation * Logic.InitialLocalRotation * Delta;
}
- void OnDrawGizmos()
- {
- if (Source == null)
- {
- return;
- }
-
- var localPosition = transform.worldToLocalMatrix.MultiplyPoint(Source.position);
- var (yaw, yaw_, pitch, pitch_) = CalcYawPitch(m_coords, localPosition);
- switch (yaw_)
- {
- case 0: break;
- case 1: yaw = 180 - yaw; break;
- case 2: yaw = 180 + yaw; break;
- case 3: yaw = 360 - yaw; break;
- }
- switch (pitch_)
- {
- case 0: pitch = -pitch; break;
- case 1: pitch = -pitch; break;
- case 2: break;
- case 3: break;
- }
- // Debug.Log($"{yaw}({yaw_}), {pitch}({pitch_})");
- // var rot = Quaternion.Euler(pitch, yaw, 0);
- var rot = Quaternion.AngleAxis(yaw, Vector3.up) * Quaternion.AngleAxis(pitch, Vector3.right);
- var p = rot * Vector3.forward;
-
- Gizmos.matrix = transform.localToWorldMatrix;
- Gizmos.DrawLine(Vector3.zero, p * 5);
- }
+ public float Yaw;
+ public float Pitch;
+ public Quaternion Delta;
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs
index 6ff82479a..fe63c3d35 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10Constraint.cs
@@ -1,12 +1,11 @@
+using System;
using UnityEngine;
namespace UniVRM10
{
public abstract class VRM10Constraint : MonoBehaviour
{
- public virtual void Process()
- {
+ public abstract void Process();
- }
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10PositionConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10PositionConstraint.cs
index 103cbb535..12d9f82ba 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10PositionConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10PositionConstraint.cs
@@ -1,4 +1,5 @@
-using UniGLTF.Extensions.VRMC_node_constraint;
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
using UnityEngine;
namespace UniVRM10
@@ -7,70 +8,45 @@ namespace UniVRM10
/// 対象の初期位置と現在位置の差分(delta)を、自身の初期位置に対してWeightを乗算して加算する。
///
[DisallowMultipleComponent]
- public class VRM10PositionConstraint : VRM10Constraint
+ public class VRM10PositionConstraint : VRM10RotationPositionConstraintBase
{
- [SerializeField]
- public Transform Source = default;
+ public override Vector3 Delta => FreezeAxes.Freeze(m_delta.Translation) * Weight;
- [SerializeField]
- public ObjectSpace SourceCoordinate = default;
-
- [SerializeField]
- public ObjectSpace DestinationCoordinate = default;
-
- [SerializeField]
- public AxisMask FreezeAxes = default;
-
- [SerializeField]
- [Range(0, 10.0f)]
- public float Weight = 1.0f;
-
- [SerializeField]
- public Transform ModelRoot = default;
-
- ConstraintSource m_src;
-
- ConstraintDestination m_dst;
-
- ///
- /// Editorで設定値の変更を反映するために、クリアする
- ///
- void OnValidate()
+ public override TR GetSourceCurrent()
{
- // Debug.Log("Validate");
- m_src = null;
- m_dst = null;
- }
-
- void Reset()
- {
- var current = transform;
- while (current.parent != null)
- {
- current = current.parent;
- }
- ModelRoot = current;
- }
-
- public override void Process()
- {
- if (Source == null)
- {
- enabled = false;
- return;
- }
-
+ var coords = GetSourceCoords();
if (m_src == null)
{
- m_src = new ConstraintSource(Source, SourceCoordinate, ModelRoot);
- }
- if (m_dst == null)
- {
- m_dst = new ConstraintDestination(transform, DestinationCoordinate, ModelRoot);
+ return coords;
}
+ return coords * new TR(Delta);
+ }
- var delta = FreezeAxes.Freeze(m_src.TranslationDelta);
- m_dst.ApplyTranslation(delta, Weight, ModelRoot);
+ public override TR GetDstCurrent()
+ {
+ var coords = GetDstCoords();
+ if (m_src == null)
+ {
+ return coords;
+ }
+ return coords * new TR(Delta);
+ }
+
+ protected override void ApplyDelta()
+ {
+ switch (DestinationCoordinate)
+ {
+ case ObjectSpace.local:
+ m_dst.ApplyLocal(m_dst.LocalInitial * new TR(DestinationOffset) * new TR(Delta));
+ break;
+
+ case ObjectSpace.model:
+ m_dst.ApplyModel(DestinationInitialCoords * new TR(DestinationOffset) * new TR(Delta));
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
index 0263fbbec..31b1c509b 100644
--- a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationConstraint.cs
@@ -1,86 +1,52 @@
-using UniGLTF.Extensions.VRMC_node_constraint;
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
using UnityEngine;
-
namespace UniVRM10
{
///
/// 対象の初期回転と現在回転の差分(delta)を、自身の初期回転と自身の初期回転にdeltaを乗算したものに対してWeightでSlerpする。
///
[DisallowMultipleComponent]
- public class VRM10RotationConstraint : VRM10Constraint
+ public class VRM10RotationConstraint : VRM10RotationPositionConstraintBase
{
- [SerializeField]
- public Transform Source = default;
+ public override Vector3 Delta => FreezeAxes.Freeze(Quaternion.Slerp(Quaternion.identity, m_delta.Rotation, Weight).eulerAngles);
- [SerializeField]
- public ObjectSpace SourceCoordinate = default;
-
- [SerializeField]
- public ObjectSpace DestinationCoordinate = default;
-
- [SerializeField]
- public AxisMask FreezeAxes = default;
-
- [SerializeField]
- [Range(0, 10.0f)]
- public float Weight = 1.0f;
-
- [SerializeField]
- public Transform ModelRoot = default;
-
- ConstraintSource m_src;
-
- ConstraintDestination m_dst;
-
- ///
- /// Editorで設定値の変更を反映するために、クリアする
- ///
- void OnValidate()
+ public override TR GetSourceCurrent()
{
- // Debug.Log("Validate");
- m_src = null;
- m_dst = null;
- }
-
- void Reset()
- {
- var current = transform;
- while (current.parent != null)
- {
- current = current.parent;
- }
- ModelRoot = current;
- }
-
- ///
- /// SourceのUpdateよりも先か後かはその時による。
- /// 厳密に制御するのは無理。
- ///
- public override void Process()
- {
- if (Source == null)
- {
- enabled = false;
- return;
- }
-
+ var coords = GetSourceCoords();
if (m_src == null)
{
- m_src = new ConstraintSource(Source, SourceCoordinate, ModelRoot);
- }
- if (m_dst == null)
- {
- m_dst = new ConstraintDestination(transform, DestinationCoordinate, ModelRoot);
+ return coords;
}
+ return coords * new TR(m_delta.Rotation);
+ }
- // 軸制限をしたオイラー角
- var delta = m_src.RotationDelta;
- var fleezed = FreezeAxes.Freeze(delta.eulerAngles);
- var rotation = Quaternion.Euler(fleezed);
- // Debug.Log($"{delta} => {rotation}");
- // オイラー角を再度Quaternionへ。weight を加味してSlerpする
- m_dst.ApplyRotation(rotation, Weight, ModelRoot);
+ public override TR GetDstCurrent()
+ {
+ var coords = GetDstCoords();
+ if (m_src == null)
+ {
+ return coords;
+ }
+ return coords * new TR(m_delta.Rotation);
+ }
+
+ protected override void ApplyDelta()
+ {
+ switch (DestinationCoordinate)
+ {
+ case ObjectSpace.local:
+ m_dst.ApplyLocal(m_dst.LocalInitial * new TR(DestinationOffset) * new TR(Quaternion.Euler(Delta)));
+ break;
+
+ case ObjectSpace.model:
+ m_dst.ApplyModel(DestinationInitialCoords * new TR(DestinationOffset) * new TR(Quaternion.Euler(Delta)));
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
}
}
}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs
new file mode 100644
index 000000000..a6382b5f1
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs
@@ -0,0 +1,17 @@
+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
new file mode 100644
index 000000000..4fc95a462
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationOffset.cs.meta
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 000000000..d3875e93a
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs
@@ -0,0 +1,248 @@
+using System;
+using UniGLTF.Extensions.VRMC_node_constraint;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ public abstract class VRM10RotationPositionConstraintBase : VRM10Constraint
+ {
+ [SerializeField]
+ [EnumFlags]
+ AxisMask m_freezeAxes = default;
+ public AxisMask FreezeAxes
+ {
+ get => m_freezeAxes;
+ set => m_freezeAxes = value;
+ }
+
+ [SerializeField]
+ [Range(0, 10.0f)]
+ public float Weight = 1.0f;
+
+ [SerializeField]
+ public Transform ModelRoot = default;
+
+ #region Source
+ [Header("Source")]
+ [SerializeField]
+ public Transform Source = default;
+
+ public Transform GetSource() => Source;
+
+ [SerializeField]
+ ObjectSpace m_sourceCoordinate = default;
+ public ObjectSpace SourceCoordinate
+ {
+ get => m_sourceCoordinate;
+ set => m_sourceCoordinate = 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]
+ ObjectSpace m_destinationCoordinate = default;
+ public ObjectSpace DestinationCoordinate
+ {
+ get => m_destinationCoordinate;
+ set => m_destinationCoordinate = value;
+ }
+
+ [SerializeField]
+ public VRM10RotationOffset m_destinationOffset = VRM10RotationOffset.Identity;
+
+ public Quaternion DestinationOffset
+ {
+ get => m_destinationOffset.Rotation;
+ set => m_destinationOffset.Rotation = value;
+ }
+ #endregion
+
+ protected ConstraintSource m_src;
+
+ TR SourceModelCoords
+ {
+ get
+ {
+ if (m_src == null)
+ {
+ return TR.FromWorld(ModelRoot);
+ }
+ else
+ {
+ return TR.FromParent(ModelRoot) * m_src.ModelInitial;
+ }
+ }
+ }
+
+ TR SourceInitialCoords
+ {
+ get
+ {
+ if (m_src == null)
+ {
+ return TR.FromWorld(Source);
+ }
+ else
+ {
+ return TR.FromParent(Source) * m_src.LocalInitial;
+ }
+ }
+ }
+
+ public TR GetSourceCoords()
+ {
+ if (Source == null)
+ {
+ throw new ConstraintException(ConstraintException.ExceptionTypes.NoSource);
+ }
+
+ switch (SourceCoordinate)
+ {
+ case ObjectSpace.model:
+ {
+ if (ModelRoot == null)
+ {
+ throw new ConstraintException(ConstraintException.ExceptionTypes.NoModelWithModelSpace);
+ }
+ return new TR(SourceModelCoords.Rotation * SourceOffset, SourceInitialCoords.Translation);
+ }
+
+ case ObjectSpace.local:
+ {
+ return new TR(SourceInitialCoords.Rotation * SourceOffset, SourceInitialCoords.Translation);
+ }
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ public abstract TR GetSourceCurrent();
+
+ protected ConstraintDestination m_dst;
+
+ TR DestinationModelCoords
+ {
+ get
+ {
+ if (m_dst == null)
+ {
+ return TR.FromWorld(ModelRoot);
+ }
+ else
+ {
+ return TR.FromParent(ModelRoot) * m_dst.ModelInitial;
+ }
+ }
+ }
+
+ public TR DestinationInitialCoords
+ {
+ get
+ {
+ if (m_dst == null)
+ {
+ return TR.FromWorld(transform);
+ }
+ else
+ {
+ return TR.FromParent(transform) * m_dst.LocalInitial;
+ }
+ }
+ }
+
+ public TR GetDstCoords()
+ {
+ switch (DestinationCoordinate)
+ {
+ case ObjectSpace.model:
+ {
+ if (ModelRoot == null)
+ {
+ throw new ConstraintException(ConstraintException.ExceptionTypes.NoModelWithModelSpace);
+ }
+ return new TR(DestinationModelCoords.Rotation * DestinationOffset, DestinationInitialCoords.Translation);
+ }
+
+ case ObjectSpace.local:
+ {
+ return new TR(DestinationInitialCoords.Rotation * DestinationOffset, DestinationInitialCoords.Translation);
+ }
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ 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;
+ }
+ }
+
+ void Reset()
+ {
+ var current = transform;
+ while (current.parent != null)
+ {
+ current = current.parent;
+ }
+ ModelRoot = current;
+ }
+
+ public Component GetComponent()
+ {
+ return this;
+ }
+
+ protected TR m_delta;
+ public abstract Vector3 Delta { get; }
+
+ protected abstract void ApplyDelta();
+
+ public override 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);
+ }
+
+ m_delta = m_src.Delta(SourceCoordinate, SourceOffset);
+ ApplyDelta();
+ }
+ }
+}
diff --git a/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta
new file mode 100644
index 000000000..bac4e2e09
--- /dev/null
+++ b/Assets/VRM10/Runtime/Components/Constraint/VRM10RotationPositionConstraintBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 07919df684c7a4c47a9492a2de417f66
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs b/Assets/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs
index 0cd2da454..0271eedf5 100644
--- a/Assets/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs
+++ b/Assets/VRM10/Runtime/Components/LookAt/Matrix4x4Extensions.cs
@@ -6,6 +6,62 @@ namespace UniVRM10
{
public static class Matrix4x4Extensions
{
+ ///
+ /// from AimConstraint
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static (float Yaw, float Pitch) CalcYawPitch(this Matrix4x4 m, Vector3 target)
+ {
+ var localPosition = m.inverse.MultiplyPoint(target);
+
+ var zaxis = Vector3.Project(localPosition, Vector3.forward);
+ var yaxis = Vector3.Project(localPosition, Vector3.up);
+ var xaxis = Vector3.Project(localPosition, Vector3.right);
+
+ var xDot = Vector3.Dot(xaxis, Vector3.right) > 0;
+ var yDot = Vector3.Dot(yaxis, Vector3.up) > 0;
+ var zDot = Vector3.Dot(zaxis, Vector3.forward) > 0;
+
+ // x z plane
+ var yaw = (float)Math.Atan2(xaxis.magnitude, zaxis.magnitude) * Mathf.Rad2Deg;
+ if (xDot && zDot)
+ {
+ // 1st(0-90)
+
+ }
+ else if (xDot && !zDot)
+ {
+ // 2nd(90-180)
+ yaw = 180 - yaw;
+ }
+ else if (!xDot && !zDot)
+ {
+ // 3rd
+ yaw = -180 + yaw;
+ }
+ else if (!xDot && zDot)
+ {
+ // 4th
+ yaw = -yaw;
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+
+ // x+y z plane
+ var pitch = (float)Math.Atan2(yaxis.magnitude, (xaxis + zaxis).magnitude) * Mathf.Rad2Deg;
+ if (yDot)
+ {
+ pitch = -pitch;
+ }
+
+ return (yaw, pitch);
+ }
+
public static void CalcYawPitch(this Matrix4x4 m, Vector3 target, out float yaw, out float pitch)
{
var zaxis = Vector3.Project(target, m.GetColumn(2));
diff --git a/Assets/VRM10/Runtime/EnumFlagsAttribute.cs b/Assets/VRM10/Runtime/EnumFlagsAttribute.cs
new file mode 100644
index 000000000..698ab6e2c
--- /dev/null
+++ b/Assets/VRM10/Runtime/EnumFlagsAttribute.cs
@@ -0,0 +1,8 @@
+using System;
+using UnityEngine;
+
+namespace UniVRM10
+{
+ [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
+ public sealed class EnumFlagsAttribute : PropertyAttribute { }
+}
diff --git a/Assets/VRM10/Runtime/EnumFlagsAttribute.cs.meta b/Assets/VRM10/Runtime/EnumFlagsAttribute.cs.meta
new file mode 100644
index 000000000..3f89217c9
--- /dev/null
+++ b/Assets/VRM10/Runtime/EnumFlagsAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5f3c3f9559a399143816d5eab6f0b4ee
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
index da0c5b722..eda93c2f9 100644
--- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
+++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs
@@ -444,8 +444,8 @@ namespace UniVRM10
Aim = new UniGLTF.Extensions.VRMC_node_constraint.AimConstraint
{
Source = model.Nodes.IndexOf(converter.Nodes[c.Source.gameObject]),
- AimVector = ReverseX(c.AimVector),
- UpVector = ReverseX(c.UpVector),
+ // AimVector = ReverseX(c.AimVector),
+ // UpVector = ReverseX(c.UpVector),
Weight = c.Weight,
},
},
diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
index 53768eaba..b90ec6a4f 100644
--- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
+++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs
@@ -501,8 +501,8 @@ namespace UniVRM10
var a = constraint.Aim;
var aimConstraint = node.gameObject.AddComponent();
aimConstraint.Source = Nodes[a.Source.Value];
- aimConstraint.AimVector = Vector3InvertX(a.AimVector);
- aimConstraint.UpVector = Vector3InvertX(a.UpVector);
+ // aimConstraint.AimVector = Vector3InvertX(a.AimVector);
+ // aimConstraint.UpVector = Vector3InvertX(a.UpVector);
}
}
}