mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-28 05:44:48 -05:00
Merge pull request #1607 from ousttrue/fix10/update_constraint_spec
Fix10/update constraint spec
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b369ee7eb21d1047bb03e139faa7eda
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,32 +0,0 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public static class TRExtensions
|
||||
{
|
||||
public static void Draw(this TR tr, float size)
|
||||
{
|
||||
Handles.matrix = tr.TRS(size);
|
||||
|
||||
// Handles.CubeHandleCap(0, Vector3.zero, Quaternion.identity, size, EventType.Repaint);
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(Vector3.zero, Vector3.right);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(Vector3.zero, Vector3.up);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(Vector3.zero, Vector3.forward);
|
||||
|
||||
Handles.color = Color.white;
|
||||
// xy
|
||||
Handles.DrawLine(Vector3.right + Vector3.up, Vector3.right);
|
||||
Handles.DrawLine(Vector3.right + Vector3.up, Vector3.up);
|
||||
// yz
|
||||
Handles.DrawLine(Vector3.up + Vector3.forward, Vector3.forward);
|
||||
Handles.DrawLine(Vector3.up + Vector3.forward, Vector3.up);
|
||||
// zx
|
||||
Handles.DrawLine(Vector3.forward + Vector3.right, Vector3.forward);
|
||||
Handles.DrawLine(Vector3.forward + Vector3.right, Vector3.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public abstract class VRM10PositionRotationConstraintEditorBase : Editor
|
||||
{
|
||||
VRM10RotationPositionConstraintBase m_target;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_target = (VRM10RotationPositionConstraintBase)target;
|
||||
}
|
||||
|
||||
static GUIStyle s_style;
|
||||
static GUIStyle Style
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_style == null)
|
||||
{
|
||||
s_style = new GUIStyle("box");
|
||||
}
|
||||
return s_style;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.Source == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// source offset
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Quaternion offset = Handles.RotationHandle(m_target.SourceOffset, m_target.Source.position);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_target.GetComponent(), "source offset");
|
||||
m_target.SourceOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
// dest offset
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Quaternion offset = Handles.RotationHandle(m_target.DestinationOffset, m_target.GetComponent().transform.position);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_target.GetComponent(), "dest offset");
|
||||
m_target.DestinationOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
// this to target line
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawLine(m_target.Source.position, m_target.GetComponent().transform.position);
|
||||
|
||||
var delta = Clamp180(m_target.Delta);
|
||||
|
||||
// show source
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"{delta.x:0.00}");
|
||||
sb.AppendLine($"{delta.y:0.00}");
|
||||
sb.Append($"{delta.z:0.00}");
|
||||
Handles.Label(m_target.Source.position, sb.ToString(), Style);
|
||||
}
|
||||
|
||||
// show dst
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(m_target.Axes.HasFlag(AxisMask.X) ? $"{delta.x:0.00}" : "----");
|
||||
sb.AppendLine(m_target.Axes.HasFlag(AxisMask.Y) ? $"{delta.y:0.00}" : "----");
|
||||
sb.Append(m_target.Axes.HasFlag(AxisMask.Z) ? $"{delta.z:0.00}" : "----");
|
||||
Handles.Label(m_target.GetComponent().transform.position, sb.ToString(), Style);
|
||||
}
|
||||
|
||||
m_target.GetSourceCoords().Draw(0.2f);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Handles.matrix = m_target.GetSourceCurrent().TRS(0.05f);
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawWireCube(Vector3.zero, Vector3.one);
|
||||
}
|
||||
|
||||
m_target.GetDstCoords().Draw(0.2f);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Handles.matrix = m_target.GetDstCurrent().TRS(0.05f);
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawWireCube(Vector3.zero, Vector3.one);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[CustomEditor(typeof(VRM10RotationConstraint))]
|
||||
public class VRM10RotationConstraintEditor : VRM10PositionRotationConstraintEditorBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd4ca141215a42c45a0036791f2f8a4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -71,7 +71,7 @@ namespace UniVRM10
|
||||
|
||||
Transform m_head;
|
||||
|
||||
public VRM10Constraint[] m_constraints;
|
||||
public IVrm10Constraint[] m_constraints;
|
||||
|
||||
ScrollView m_scrollView = new ScrollView();
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace UniVRM10
|
||||
{
|
||||
if (m_constraints == null)
|
||||
{
|
||||
m_constraints = Root.GetComponentsInChildren<VRM10Constraint>();
|
||||
m_constraints = Root.GetComponentsInChildren<IVrm10Constraint>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace UniVRM10
|
||||
{
|
||||
foreach (var c in m_constraints)
|
||||
{
|
||||
EditorGUILayout.ObjectField(c, typeof(VRM10Constraint), true);
|
||||
EditorGUILayout.ObjectField(c.GameObject, typeof(MonoBehaviour), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(VRM10RotationOffset))]
|
||||
public class IngredientDrawer : PropertyDrawer
|
||||
{
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return 16f + 18f;
|
||||
}
|
||||
|
||||
// Draw the property inside the given rect
|
||||
void DrawEuler(Rect position, SerializedProperty property)
|
||||
{
|
||||
Vector3 euler = property.quaternionValue.eulerAngles;
|
||||
euler = EditorGUI.Vector3Field(position, "Offset", euler);
|
||||
property.quaternionValue = Quaternion.Euler(euler);
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
DrawEuler(position, property.FindPropertyRelative(nameof(VRM10RotationOffset.Rotation)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public interface IVrm10Constraint
|
||||
{
|
||||
void Process();
|
||||
|
||||
GameObject GameObject { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 615a7cbd2c3cd5d42ab2719d6e74c1b8
|
||||
guid: c859e278c34a69b438db39275ce25556
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,92 +0,0 @@
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public abstract class VRM10Constraint : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
[Range(0, 10.0f)]
|
||||
public float Weight = 1.0f;
|
||||
|
||||
[SerializeField]
|
||||
public Transform ModelRoot = default;
|
||||
|
||||
protected virtual void Reset()
|
||||
{
|
||||
var current = transform;
|
||||
while (true)
|
||||
{
|
||||
current = current.parent;
|
||||
if (current.parent == null)
|
||||
{
|
||||
// root
|
||||
break;
|
||||
}
|
||||
if (current.GetComponent<Vrm10Instance>() != null)
|
||||
{
|
||||
// model root
|
||||
break;
|
||||
}
|
||||
}
|
||||
ModelRoot = current;
|
||||
}
|
||||
|
||||
#region Source
|
||||
public abstract Transform Source { get; set; }
|
||||
|
||||
public ConstraintSource m_src;
|
||||
|
||||
protected TR SourceInitialCoords()
|
||||
{
|
||||
if (m_src == null)
|
||||
{
|
||||
return TR.FromWorld(Source);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TR.FromParent(Source) * m_src.LocalInitial;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Destination
|
||||
protected ConstraintDestination m_dst;
|
||||
|
||||
protected TR DestinationInitialCoords()
|
||||
{
|
||||
if (m_dst == null)
|
||||
{
|
||||
return TR.FromWorld(transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TR.FromParent(transform) * m_dst.LocalInitial;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Process()
|
||||
{
|
||||
if (Source == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_src == null)
|
||||
{
|
||||
m_src = new ConstraintSource(Source, ModelRoot);
|
||||
}
|
||||
if (m_dst == null)
|
||||
{
|
||||
m_dst = new ConstraintDestination(transform, ModelRoot);
|
||||
}
|
||||
|
||||
OnProcess();
|
||||
}
|
||||
|
||||
public abstract void OnProcess();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ded8c4db12c688b46814cf0bf925cacf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// 対象の初期回転と現在回転の差分(delta)を、自身の初期回転と自身の初期回転にdeltaを乗算したものに対してWeightでSlerpする。
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class VRM10RotationConstraint : VRM10RotationPositionConstraintBase
|
||||
{
|
||||
public override Vector3 Delta => Axes.Mask(Quaternion.Slerp(Quaternion.identity, m_delta.Rotation, Weight).eulerAngles);
|
||||
|
||||
public override TR GetSourceCurrent()
|
||||
{
|
||||
var coords = GetSourceCoords();
|
||||
if (m_src == null)
|
||||
{
|
||||
return coords;
|
||||
}
|
||||
return coords * new TR(m_delta.Rotation);
|
||||
}
|
||||
|
||||
public override TR GetDstCurrent()
|
||||
{
|
||||
var coords = GetDstCoords();
|
||||
if (m_src == null)
|
||||
{
|
||||
return coords;
|
||||
}
|
||||
return coords * new TR(m_delta.Rotation);
|
||||
}
|
||||
|
||||
protected override void ApplyDelta()
|
||||
{
|
||||
m_dst.ApplyLocal(m_dst.LocalInitial * new TR(DestinationOffset) * new TR(Quaternion.Euler(Delta)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[Serializable]
|
||||
public struct VRM10RotationOffset
|
||||
{
|
||||
[SerializeField]
|
||||
public Quaternion Rotation;
|
||||
|
||||
public static VRM10RotationOffset Identity => new VRM10RotationOffset
|
||||
{
|
||||
Rotation = Quaternion.identity,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b8a5228a8756d64684e8dca601ccafc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,105 +0,0 @@
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public abstract class VRM10RotationPositionConstraintBase : VRM10Constraint
|
||||
{
|
||||
[SerializeField]
|
||||
[EnumFlags]
|
||||
AxisMask m_axes = AxisMask.X | AxisMask.Y | AxisMask.Z;
|
||||
public AxisMask Axes
|
||||
{
|
||||
get => m_axes;
|
||||
set => m_axes = value;
|
||||
}
|
||||
|
||||
#region Source
|
||||
[Header("Source")]
|
||||
[SerializeField]
|
||||
Transform m_source = default;
|
||||
public override Transform Source
|
||||
{
|
||||
get => m_source;
|
||||
set => m_source = value;
|
||||
}
|
||||
|
||||
|
||||
[SerializeField]
|
||||
VRM10RotationOffset m_sourceOffset = VRM10RotationOffset.Identity;
|
||||
|
||||
public Quaternion SourceOffset
|
||||
{
|
||||
get => m_sourceOffset.Rotation;
|
||||
set => m_sourceOffset.Rotation = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Destination
|
||||
[Header("Destination")]
|
||||
[SerializeField]
|
||||
public VRM10RotationOffset m_destinationOffset = VRM10RotationOffset.Identity;
|
||||
|
||||
public Quaternion DestinationOffset
|
||||
{
|
||||
get => m_destinationOffset.Rotation;
|
||||
set => m_destinationOffset.Rotation = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public TR GetSourceCoords()
|
||||
{
|
||||
if (Source == null)
|
||||
{
|
||||
throw new ConstraintException(ConstraintException.ExceptionTypes.NoSource);
|
||||
}
|
||||
|
||||
var init = SourceInitialCoords();
|
||||
return new TR(init.Rotation * SourceOffset, init.Translation);
|
||||
}
|
||||
|
||||
public abstract TR GetSourceCurrent();
|
||||
|
||||
public TR GetDstCoords()
|
||||
{
|
||||
var init = DestinationInitialCoords();
|
||||
return new TR(init.Rotation * DestinationOffset, init.Translation);
|
||||
}
|
||||
|
||||
public abstract TR GetDstCurrent();
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
public Component GetComponent()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
protected TR m_delta;
|
||||
public abstract Vector3 Delta { get; }
|
||||
|
||||
protected abstract void ApplyDelta();
|
||||
|
||||
public override void OnProcess()
|
||||
{
|
||||
m_delta = m_src.Delta(SourceOffset);
|
||||
ApplyDelta();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07919df684c7a4c47a9492a2de417f66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.aimConstraint.schema.json
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class Vrm10AimConstraint : MonoBehaviour, IVrm10Constraint
|
||||
{
|
||||
public GameObject GameObject => gameObject;
|
||||
|
||||
[SerializeField]
|
||||
public Transform Source = default;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0, 10.0f)]
|
||||
public float Weight = 1.0f;
|
||||
|
||||
[SerializeField]
|
||||
public AimAxis AimAxis;
|
||||
|
||||
Vector3 GetAxisVector()
|
||||
{
|
||||
switch (AimAxis)
|
||||
{
|
||||
case AimAxis.PositiveX: return Vector3.right;
|
||||
case AimAxis.NegativeX: return Vector3.left;
|
||||
case AimAxis.PositiveY: return Vector3.up;
|
||||
case AimAxis.NegativeY: return Vector3.down;
|
||||
case AimAxis.PositiveZ: return Vector3.forward;
|
||||
case AimAxis.NegativeZ: return Vector3.back;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion _dstRestLocalQuat;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Source == null)
|
||||
{
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_dstRestLocalQuat = transform.localRotation;
|
||||
}
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation-1
|
||||
///
|
||||
/// fromVec = aimAxis.applyQuaternion( dstParentWorldQuat * dstRestQuat )
|
||||
/// toVec = ( srcWorldPos - dstWorldPos ).normalized
|
||||
/// fromToQuat = Quaternion.fromToRotation( fromVec, toVec )
|
||||
/// targetQuat = Quaternion.slerp(
|
||||
/// dstRestQuat,
|
||||
/// dstParentWorldQuat.inverse * fromToQuat * dstParentWorldQuat * dstRestQuat,
|
||||
/// weight
|
||||
/// )
|
||||
/// </summary>
|
||||
public void Process()
|
||||
{
|
||||
if (Source == null) return;
|
||||
|
||||
// world coords
|
||||
var dstParentWorldQuat = transform.parent != null ? transform.parent.rotation : Quaternion.identity;
|
||||
var fromVec = (dstParentWorldQuat * _dstRestLocalQuat) * GetAxisVector();
|
||||
var toVec = (Source.position - transform.position).normalized;
|
||||
var fromToQuat = Quaternion.FromToRotation(fromVec, toVec);
|
||||
|
||||
transform.rotation = Quaternion.SlerpUnclamped(
|
||||
_dstRestLocalQuat,
|
||||
Quaternion.Inverse(dstParentWorldQuat) * fromToQuat * dstParentWorldQuat * _dstRestLocalQuat,
|
||||
Weight
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46c1f13688fee134aa37a39a72433217
|
||||
guid: 37b0507e4ae49724898ca17cc3db6f1a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using UniGLTF.Extensions.VRMC_node_constraint;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.rollConstraint.schema.json
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class Vrm10RollConstraint : MonoBehaviour, IVrm10Constraint
|
||||
{
|
||||
public GameObject GameObject => gameObject;
|
||||
|
||||
[SerializeField]
|
||||
public Transform Source = default;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0, 10.0f)]
|
||||
public float Weight = 1.0f;
|
||||
|
||||
[SerializeField]
|
||||
public RollAxis RollAxis;
|
||||
Vector3 GetRollVector()
|
||||
{
|
||||
switch (RollAxis)
|
||||
{
|
||||
case RollAxis.X: return Vector3.right;
|
||||
case RollAxis.Y: return Vector3.up;
|
||||
case RollAxis.Z: return Vector3.forward;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion _srcRestLocalQuat;
|
||||
Quaternion _dstRestLocalQuat;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Source == null)
|
||||
{
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_srcRestLocalQuat = Source.localRotation;
|
||||
_dstRestLocalQuat = transform.localRotation;
|
||||
}
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation
|
||||
///
|
||||
/// deltaSrcQuat = srcRestQuat.inverse * srcQuat
|
||||
/// deltaSrcQuatInParent = srcRestQuat * deltaSrcQuat * srcRestQuat.inverse // source to parent
|
||||
/// deltaSrcQuatInDst = dstRestQuat.inverse * deltaSrcQuatInWorld * dstRestQuat // parent to destination
|
||||
///
|
||||
/// toVec = rollAxis.applyQuaternion( deltaSrcQuatInDst )
|
||||
/// fromToQuat = Quaternion.fromToRotation( rollAxis, toVec )
|
||||
///
|
||||
/// targetQuat = Quaternion.slerp(
|
||||
/// dstRestQuat,
|
||||
/// dstRestQuat * fromToQuat.inverse * deltaSrcQuatInDst,
|
||||
/// weight
|
||||
/// )
|
||||
/// </summary>
|
||||
public void Process()
|
||||
{
|
||||
if (Source == null) return;
|
||||
|
||||
var deltaSrcQuat = Quaternion.Inverse(_srcRestLocalQuat) * Source.localRotation;
|
||||
var deltaSrcQuatInParent = _srcRestLocalQuat * deltaSrcQuat * Quaternion.Inverse(_srcRestLocalQuat); // source to parent
|
||||
var deltaSrcQuatInDst = Quaternion.Inverse(_dstRestLocalQuat) * deltaSrcQuatInParent * _dstRestLocalQuat; // parent to destination
|
||||
|
||||
var rollAxis = GetRollVector();
|
||||
var toVec = deltaSrcQuatInDst * rollAxis;
|
||||
var fromToQuat = Quaternion.FromToRotation(rollAxis, toVec);
|
||||
|
||||
transform.localRotation = Quaternion.SlerpUnclamped(
|
||||
_dstRestLocalQuat,
|
||||
_dstRestLocalQuat * Quaternion.Inverse(fromToQuat) * deltaSrcQuatInDst,
|
||||
Weight
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2d422c6e760aca49841f8acf44c0434
|
||||
guid: 1e864293edac89b40b9f79c23e7aa547
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/schema/VRMC_node_constraint.rotationConstraint.schema.json
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class Vrm10RotationConstraint : MonoBehaviour, IVrm10Constraint
|
||||
{
|
||||
public GameObject GameObject => gameObject;
|
||||
|
||||
[SerializeField]
|
||||
public Transform Source = default;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0, 10.0f)]
|
||||
public float Weight = 1.0f;
|
||||
|
||||
Quaternion _srcRestLocalQuatInverse;
|
||||
Quaternion _dstRestLocalQuat;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Source == null)
|
||||
{
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_srcRestLocalQuatInverse = Quaternion.Inverse(Source.localRotation);
|
||||
_dstRestLocalQuat = transform.localRotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_node_constraint-1.0_draft/README.ja.md#example-of-implementation-2
|
||||
///
|
||||
/// srcDeltaQuat = srcRestQuat.inverse * srcQuat
|
||||
/// targetQuat = Quaternion.slerp(
|
||||
/// dstRestQuat,
|
||||
/// dstRestQuat * srcDeltaQuat,
|
||||
/// weight
|
||||
/// )
|
||||
/// </summary>
|
||||
public void Process()
|
||||
{
|
||||
if (Source == null) return;
|
||||
|
||||
// local coords
|
||||
var srcDeltaLocalQuat = _srcRestLocalQuatInverse * Source.localRotation;
|
||||
transform.localRotation = Quaternion.SlerpUnclamped(_dstRestLocalQuat, _dstRestLocalQuat * srcDeltaLocalQuat, Weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace UniVRM10
|
||||
public class Vrm10Runtime : IDisposable
|
||||
{
|
||||
private readonly Vrm10Instance m_target;
|
||||
private readonly VRM10Constraint[] m_constraints;
|
||||
private readonly IVrm10Constraint[] m_constraints;
|
||||
private readonly Transform m_head;
|
||||
private readonly FastSpringBoneService m_fastSpringBoneService;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace UniVRM10
|
||||
|
||||
if (m_constraints == null)
|
||||
{
|
||||
m_constraints = target.GetComponentsInChildren<VRM10Constraint>();
|
||||
m_constraints = target.GetComponentsInChildren<IVrm10Constraint>();
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
|
||||
@@ -79,6 +79,16 @@ public static Constraint Deserialize_Constraint(JsonNode parsed)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="roll"){
|
||||
value.Roll = __constraint_Deserialize_Roll(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="aim"){
|
||||
value.Aim = __constraint_Deserialize_Aim(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="rotation"){
|
||||
value.Rotation = __constraint_Deserialize_Rotation(kv.Value);
|
||||
continue;
|
||||
@@ -88,6 +98,90 @@ public static Constraint Deserialize_Constraint(JsonNode parsed)
|
||||
return value;
|
||||
}
|
||||
|
||||
public static RollConstraint __constraint_Deserialize_Roll(JsonNode parsed)
|
||||
{
|
||||
var value = new RollConstraint();
|
||||
|
||||
foreach(var kv in parsed.ObjectItems())
|
||||
{
|
||||
var key = kv.Key.GetString();
|
||||
|
||||
if(key=="extensions"){
|
||||
value.Extensions = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="extras"){
|
||||
value.Extras = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="name"){
|
||||
value.Name = kv.Value.GetString();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="source"){
|
||||
value.Source = kv.Value.GetInt32();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="rollAxis"){
|
||||
value.RollAxis = (RollAxis)Enum.Parse(typeof(RollAxis), kv.Value.GetString(), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="weight"){
|
||||
value.Weight = kv.Value.GetSingle();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static AimConstraint __constraint_Deserialize_Aim(JsonNode parsed)
|
||||
{
|
||||
var value = new AimConstraint();
|
||||
|
||||
foreach(var kv in parsed.ObjectItems())
|
||||
{
|
||||
var key = kv.Key.GetString();
|
||||
|
||||
if(key=="extensions"){
|
||||
value.Extensions = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="extras"){
|
||||
value.Extras = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="name"){
|
||||
value.Name = kv.Value.GetString();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="source"){
|
||||
value.Source = kv.Value.GetInt32();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="aimAxis"){
|
||||
value.AimAxis = (AimAxis)Enum.Parse(typeof(AimAxis), kv.Value.GetString(), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="weight"){
|
||||
value.Weight = kv.Value.GetSingle();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode parsed)
|
||||
{
|
||||
var value = new RotationConstraint();
|
||||
@@ -116,11 +210,6 @@ public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode pars
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="axes"){
|
||||
value.Axes = __constraint__rotation_Deserialize_Axes(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="weight"){
|
||||
value.Weight = kv.Value.GetSingle();
|
||||
continue;
|
||||
@@ -130,16 +219,5 @@ public static RotationConstraint __constraint_Deserialize_Rotation(JsonNode pars
|
||||
return value;
|
||||
}
|
||||
|
||||
public static bool[] __constraint__rotation_Deserialize_Axes(JsonNode parsed)
|
||||
{
|
||||
var value = new bool[parsed.GetArrayCount()];
|
||||
int i=0;
|
||||
foreach(var x in parsed.ArrayItems())
|
||||
{
|
||||
value[i++] = x.GetBoolean();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // GltfDeserializer
|
||||
} // UniGLTF
|
||||
|
||||
@@ -6,6 +6,67 @@ using System.Collections.Generic;
|
||||
namespace UniGLTF.Extensions.VRMC_node_constraint
|
||||
{
|
||||
|
||||
public enum RollAxis
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
|
||||
}
|
||||
|
||||
public class RollConstraint
|
||||
{
|
||||
// Dictionary object with extension-specific objects.
|
||||
public object Extensions;
|
||||
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// The user-defined name of this object.
|
||||
public string Name;
|
||||
|
||||
// The index of the node constrains the node.
|
||||
public int? Source;
|
||||
|
||||
// The roll axis of the constraint.
|
||||
public RollAxis RollAxis;
|
||||
|
||||
// The weight of the constraint.
|
||||
public float? Weight;
|
||||
}
|
||||
|
||||
public enum AimAxis
|
||||
{
|
||||
PositiveX,
|
||||
NegativeX,
|
||||
PositiveY,
|
||||
NegativeY,
|
||||
PositiveZ,
|
||||
NegativeZ,
|
||||
|
||||
}
|
||||
|
||||
public class AimConstraint
|
||||
{
|
||||
// Dictionary object with extension-specific objects.
|
||||
public object Extensions;
|
||||
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// The user-defined name of this object.
|
||||
public string Name;
|
||||
|
||||
// The index of the node constrains the node.
|
||||
public int? Source;
|
||||
|
||||
// The aim axis of the constraint.
|
||||
public AimAxis AimAxis;
|
||||
|
||||
// The weight of the constraint.
|
||||
public float? Weight;
|
||||
}
|
||||
|
||||
public class RotationConstraint
|
||||
{
|
||||
// Dictionary object with extension-specific objects.
|
||||
@@ -20,9 +81,6 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
|
||||
// The index of the node constrains the node.
|
||||
public int? Source;
|
||||
|
||||
// Axes be constrained by this constraint, in X-Y-Z order.
|
||||
public bool[] Axes;
|
||||
|
||||
// The weight of the constraint.
|
||||
public float? Weight;
|
||||
}
|
||||
@@ -35,6 +93,12 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// A constraint that transfers a rotation around one axis of a source.
|
||||
public RollConstraint Roll;
|
||||
|
||||
// A constraint that makes it look at a source object.
|
||||
public AimConstraint Aim;
|
||||
|
||||
// A constraint that links the rotation with a source.
|
||||
public RotationConstraint Rotation;
|
||||
}
|
||||
@@ -52,7 +116,7 @@ namespace UniGLTF.Extensions.VRMC_node_constraint
|
||||
// Specification version of VRMC_node_constraint
|
||||
public string SpecVersion;
|
||||
|
||||
// Contains position, rotation, or aim
|
||||
// Contains roll, aim, or rotation
|
||||
public Constraint Constraint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,16 @@ public static void Serialize_Constraint(JsonFormatter f, Constraint value)
|
||||
(value.Extras as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Roll!=null){
|
||||
f.Key("roll");
|
||||
__constraint_Serialize_Roll(f, value.Roll);
|
||||
}
|
||||
|
||||
if(value.Aim!=null){
|
||||
f.Key("aim");
|
||||
__constraint_Serialize_Aim(f, value.Aim);
|
||||
}
|
||||
|
||||
if(value.Rotation!=null){
|
||||
f.Key("rotation");
|
||||
__constraint_Serialize_Rotation(f, value.Rotation);
|
||||
@@ -79,6 +89,82 @@ public static void Serialize_Constraint(JsonFormatter f, Constraint value)
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void __constraint_Serialize_Roll(JsonFormatter f, RollConstraint value)
|
||||
{
|
||||
f.BeginMap();
|
||||
|
||||
|
||||
if(value.Extensions!=null){
|
||||
f.Key("extensions");
|
||||
(value.Extensions as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Extras!=null){
|
||||
f.Key("extras");
|
||||
(value.Extras as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(value.Name)){
|
||||
f.Key("name");
|
||||
f.Value(value.Name);
|
||||
}
|
||||
|
||||
if(value.Source.HasValue){
|
||||
f.Key("source");
|
||||
f.Value(value.Source.GetValueOrDefault());
|
||||
}
|
||||
|
||||
if(true){
|
||||
f.Key("rollAxis");
|
||||
f.Value(value.RollAxis.ToString());
|
||||
}
|
||||
|
||||
if(value.Weight.HasValue){
|
||||
f.Key("weight");
|
||||
f.Value(value.Weight.GetValueOrDefault());
|
||||
}
|
||||
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void __constraint_Serialize_Aim(JsonFormatter f, AimConstraint value)
|
||||
{
|
||||
f.BeginMap();
|
||||
|
||||
|
||||
if(value.Extensions!=null){
|
||||
f.Key("extensions");
|
||||
(value.Extensions as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Extras!=null){
|
||||
f.Key("extras");
|
||||
(value.Extras as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(value.Name)){
|
||||
f.Key("name");
|
||||
f.Value(value.Name);
|
||||
}
|
||||
|
||||
if(value.Source.HasValue){
|
||||
f.Key("source");
|
||||
f.Value(value.Source.GetValueOrDefault());
|
||||
}
|
||||
|
||||
if(true){
|
||||
f.Key("aimAxis");
|
||||
f.Value(value.AimAxis.ToString());
|
||||
}
|
||||
|
||||
if(value.Weight.HasValue){
|
||||
f.Key("weight");
|
||||
f.Value(value.Weight.GetValueOrDefault());
|
||||
}
|
||||
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationConstraint value)
|
||||
{
|
||||
f.BeginMap();
|
||||
@@ -104,11 +190,6 @@ public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationCons
|
||||
f.Value(value.Source.GetValueOrDefault());
|
||||
}
|
||||
|
||||
if(value.Axes!=null&&value.Axes.Count()>=3){
|
||||
f.Key("axes");
|
||||
__constraint__rotation_Serialize_Axes(f, value.Axes);
|
||||
}
|
||||
|
||||
if(value.Weight.HasValue){
|
||||
f.Key("weight");
|
||||
f.Value(value.Weight.GetValueOrDefault());
|
||||
@@ -117,17 +198,5 @@ public static void __constraint_Serialize_Rotation(JsonFormatter f, RotationCons
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void __constraint__rotation_Serialize_Axes(JsonFormatter f, bool[] value)
|
||||
{
|
||||
f.BeginList();
|
||||
|
||||
foreach(var item in value)
|
||||
{
|
||||
f.Value(item);
|
||||
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
} // class
|
||||
} // namespace
|
||||
|
||||
@@ -401,14 +401,43 @@ namespace UniVRM10
|
||||
|
||||
static void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter, List<glTFNode> nodes)
|
||||
{
|
||||
var constraints = vrmController.GetComponentsInChildren<VRM10Constraint>();
|
||||
var constraints = vrmController.GetComponentsInChildren<IVrm10Constraint>();
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint vrmConstraint = default;
|
||||
var vrmConstraint = new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint
|
||||
{
|
||||
SpecVersion = NODE_CONSTRAINT_SPEC_VERSION,
|
||||
Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint
|
||||
{
|
||||
},
|
||||
};
|
||||
|
||||
switch (constraint)
|
||||
{
|
||||
case VRM10RotationConstraint rotationConstraint:
|
||||
vrmConstraint = ExportRotationConstraint(rotationConstraint, model, converter);
|
||||
case Vrm10AimConstraint aimConstraint:
|
||||
vrmConstraint.Constraint.Aim = new UniGLTF.Extensions.VRMC_node_constraint.AimConstraint
|
||||
{
|
||||
Source = model.Nodes.IndexOf(converter.Nodes[aimConstraint.Source.gameObject]),
|
||||
Weight = aimConstraint.Weight,
|
||||
AimAxis = aimConstraint.AimAxis,
|
||||
};
|
||||
break;
|
||||
|
||||
case Vrm10RollConstraint rollConstraint:
|
||||
vrmConstraint.Constraint.Roll = new UniGLTF.Extensions.VRMC_node_constraint.RollConstraint
|
||||
{
|
||||
Source = model.Nodes.IndexOf(converter.Nodes[rollConstraint.Source.gameObject]),
|
||||
Weight = rollConstraint.Weight,
|
||||
RollAxis = rollConstraint.RollAxis,
|
||||
};
|
||||
break;
|
||||
|
||||
case Vrm10RotationConstraint rotationConstraint:
|
||||
vrmConstraint.Constraint.Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint
|
||||
{
|
||||
Source = model.Nodes.IndexOf(converter.Nodes[rotationConstraint.Source.gameObject]),
|
||||
Weight = rotationConstraint.Weight,
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -416,7 +445,7 @@ namespace UniVRM10
|
||||
}
|
||||
|
||||
// serialize to gltfNode
|
||||
var node = converter.Nodes[constraint.gameObject];
|
||||
var node = converter.Nodes[constraint.GameObject];
|
||||
var nodeIndex = model.Nodes.IndexOf(node);
|
||||
var gltfNode = nodes[nodeIndex];
|
||||
UniGLTF.Extensions.VRMC_node_constraint.GltfSerializer.SerializeTo(ref gltfNode.extensions, vrmConstraint);
|
||||
@@ -433,22 +462,6 @@ namespace UniVRM10
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint ExportRotationConstraint(VRM10RotationConstraint c, Model model, ModelExporter converter)
|
||||
{
|
||||
return new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint
|
||||
{
|
||||
SpecVersion = NODE_CONSTRAINT_SPEC_VERSION,
|
||||
Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint
|
||||
{
|
||||
Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint
|
||||
{
|
||||
Source = model.Nodes.IndexOf(converter.Nodes[c.Source.gameObject]),
|
||||
Axes = ToArray(c.Axes),
|
||||
Weight = c.Weight,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_vrm.MeshAnnotation ExportMeshAnnotation(RendererFirstPersonFlags flags, Transform root, Func<Renderer, int> getIndex)
|
||||
{
|
||||
|
||||
@@ -652,6 +652,17 @@ namespace UniVRM10
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_node_constraint-1.0_draft
|
||||
///
|
||||
/// * roll
|
||||
/// * aim
|
||||
/// * rotaton
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="awaitCaller"></param>
|
||||
/// <param name="controller"></param>
|
||||
/// <returns></returns>
|
||||
async Task LoadConstraintAsync(IAwaitCaller awaitCaller, Vrm10Instance controller)
|
||||
{
|
||||
for (int i = 0; i < Data.GLTF.nodes.Count; ++i)
|
||||
@@ -661,14 +672,32 @@ namespace UniVRM10
|
||||
{
|
||||
var constraint = ext.Constraint;
|
||||
var node = Nodes[i];
|
||||
if (constraint.Rotation != null)
|
||||
if (constraint.Roll != null)
|
||||
{
|
||||
var r = constraint.Rotation;
|
||||
var rotationConstraint = node.gameObject.AddComponent<VRM10RotationConstraint>();
|
||||
rotationConstraint.Source = Nodes[r.Source.Value];
|
||||
rotationConstraint.Axes = ConstraintAxes(r.Axes);
|
||||
rotationConstraint.Weight = r.Weight.Value;
|
||||
rotationConstraint.ModelRoot = Root.transform;
|
||||
var roll = constraint.Roll;
|
||||
var component = node.gameObject.AddComponent<Vrm10RollConstraint>();
|
||||
component.Source = Nodes[roll.Source.Value];
|
||||
component.Weight = roll.Weight.Value;
|
||||
component.RollAxis = roll.RollAxis;
|
||||
}
|
||||
else if (constraint.Aim != null)
|
||||
{
|
||||
var aim = constraint.Aim;
|
||||
var component = node.gameObject.AddComponent<Vrm10AimConstraint>();
|
||||
component.Source = Nodes[aim.Source.Value];
|
||||
component.Weight = aim.Weight.Value;
|
||||
component.AimAxis = aim.AimAxis;
|
||||
}
|
||||
else if (constraint.Rotation != null)
|
||||
{
|
||||
var rotation = constraint.Rotation;
|
||||
var component = node.gameObject.AddComponent<Vrm10RotationConstraint>();
|
||||
component.Source = Nodes[rotation.Source.Value];
|
||||
component.Weight = rotation.Weight.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Submodule vrm-specification updated: 084c4fd3a1...e93a3a0776
Reference in New Issue
Block a user