mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-04 16:58:25 -05:00
Merge branch 'master' of https://github.com/vrm-c/UniVRM into exportMtoon10
This commit is contained in:
commit
44145bc6ca
8
Assets/VRM10/Editor/Components/Constraint.meta
Normal file
8
Assets/VRM10/Editor/Components/Constraint.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7b369ee7eb21d1047bb03e139faa7eda
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
32
Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs
Normal file
32
Assets/VRM10/Editor/Components/Constraint/TRExtensions.cs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b00df4c7268fefe42a16416935bbceb5
|
||||
guid: f2d422c6e760aca49841f8acf44c0434
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 53c7ae04ba8deea40acc6439a2fe11cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[CustomEditor(typeof(VRM10PositionConstraint))]
|
||||
public class VRM10PositionConstraintEditor : VRM10PositionRotationConstraintEditorBase
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d4c6d6f5f37e41e47bd02bdf1dbda864
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Euler各を +- 180 にクランプする
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 46c1f13688fee134aa37a39a72433217
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[CustomEditor(typeof(VRM10RotationConstraint))]
|
||||
public class VRM10RotationConstraintEditor : VRM10PositionRotationConstraintEditorBase
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd4ca141215a42c45a0036791f2f8a4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
64
Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs
Normal file
64
Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag設定したEnumのインスペクター表示を変えるクラス
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta
Normal file
11
Assets/VRM10/Editor/EnumFlagAttributeDrawer.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62a17679a0c7f7843beaa97ae4121d63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
Normal file
28
Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs
Normal file
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
Normal file
11
Assets/VRM10/Editor/VRM10RotationOffsetDrawer.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 615a7cbd2c3cd5d42ab2719d6e74c1b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13be84b73aeb40641978e083c750590d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
Assets/VRM10/Runtime/Components/Constraint/TR.cs
Normal file
62
Assets/VRM10/Runtime/Components/Constraint/TR.cs
Normal file
|
|
@ -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));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// R1|T1 R2|T2 x R1R2|R1T2+T1 x
|
||||
/// --+-- --+-- y => ----+------- y
|
||||
/// 0| 1 0| 1 z 0| 1 z
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static TR operator *(TR a, TR b) => new TR(a.Rotation * b.Rotation, a.Rotation * b.Translation + a.Translation);
|
||||
|
||||
/// <summary>
|
||||
/// R|0 1|T R|RT
|
||||
/// -+- -+- => -+--
|
||||
/// 0|1 0|1 0| 1
|
||||
/// </summary>
|
||||
public TR Inverse()
|
||||
{
|
||||
var inv = Quaternion.Inverse(Rotation);
|
||||
return new TR(inv, inv * -Translation);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10/Runtime/Components/Constraint/TR.cs.meta
Normal file
11
Assets/VRM10/Runtime/Components/Constraint/TR.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6ddd45ffb38279b488938471919fc089
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,108 +20,33 @@ namespace UniVRM10
|
|||
[Range(0, 10.0f)]
|
||||
public float Weight = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Forward
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -130,45 +55,21 @@ namespace UniVRM10
|
|||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public abstract class VRM10Constraint : MonoBehaviour
|
||||
{
|
||||
public virtual void Process()
|
||||
{
|
||||
public abstract void Process();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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を乗算して加算する。
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Editorで設定値の変更を反映するために、クリアする
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,86 +1,52 @@
|
|||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// 対象の初期回転と現在回転の差分(delta)を、自身の初期回転と自身の初期回転にdeltaを乗算したものに対してWeightでSlerpする。
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Editorで設定値の変更を反映するために、クリアする
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SourceのUpdateよりも先か後かはその時による。
|
||||
/// 厳密に制御するのは無理。
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b8a5228a8756d64684e8dca601ccafc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Editorで設定値の変更を反映するために、クリアする
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07919df684c7a4c47a9492a2de417f66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -6,6 +6,62 @@ namespace UniVRM10
|
|||
{
|
||||
public static class Matrix4x4Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// from AimConstraint
|
||||
/// </summary>
|
||||
/// <param name="Yaw"></param>
|
||||
/// <param name="m"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
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));
|
||||
|
|
|
|||
8
Assets/VRM10/Runtime/EnumFlagsAttribute.cs
Normal file
8
Assets/VRM10/Runtime/EnumFlagsAttribute.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
|
||||
public sealed class EnumFlagsAttribute : PropertyAttribute { }
|
||||
}
|
||||
11
Assets/VRM10/Runtime/EnumFlagsAttribute.cs.meta
Normal file
11
Assets/VRM10/Runtime/EnumFlagsAttribute.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f3c3f9559a399143816d5eab6f0b4ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -501,8 +501,8 @@ namespace UniVRM10
|
|||
var a = constraint.Aim;
|
||||
var aimConstraint = node.gameObject.AddComponent<VRM10AimConstraint>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user