您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
106 行
3.6 KiB
106 行
3.6 KiB
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_beta/schema/VRMC_node_constraint.aimConstraint.schema.json
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class Vrm10AimConstraint : MonoBehaviour, IVrm10Constraint
|
|
{
|
|
public GameObject ConstraintTarget => gameObject;
|
|
|
|
[SerializeField]
|
|
public Transform Source = default;
|
|
|
|
[SerializeField]
|
|
[Range(0, 1.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 Start()
|
|
{
|
|
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_beta/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>
|
|
void IVrm10Constraint.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.localRotation = Quaternion.SlerpUnclamped(
|
|
_dstRestLocalQuat,
|
|
Quaternion.Inverse(dstParentWorldQuat) * fromToQuat * dstParentWorldQuat * _dstRestLocalQuat,
|
|
Weight
|
|
);
|
|
}
|
|
|
|
public void OnDrawGizmosSelected()
|
|
{
|
|
if (Source == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Gizmos.color = Color.magenta;
|
|
Gizmos.DrawLine(transform.position, Source.position);
|
|
Gizmos.DrawSphere(Source.position, 0.01f);
|
|
|
|
Gizmos.matrix = transform.localToWorldMatrix;
|
|
var len = 0.1f;
|
|
switch (AimAxis)
|
|
{
|
|
case AimAxis.PositiveX:
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawLine(Vector3.zero, Vector3.right * len);
|
|
break;
|
|
case AimAxis.NegativeX:
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawLine(Vector3.zero, Vector3.left * len);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|