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); } } }