Files
2026-03-04 10:03:45 +08:00

117 lines
3.4 KiB
C#

using System;
using UnityEngine;
namespace RootMotion.FinalIK
{
public class TwistRelaxer : MonoBehaviour
{
public IK ik;
[Tooltip("If this is the forearm roll bone, the parent should be the forearm bone. If null, will be found automatically.")]
public Transform parent;
[Tooltip("If this is the forearm roll bone, the child should be the hand bone. If null, will attempt to find automatically. Assign the hand manually if the hand bone is not a child of the roll bone.")]
public Transform child;
[Tooltip("The weight of relaxing the twist of this Transform")]
[Range(0f, 1f)]
public float weight = 1f;
[Tooltip("If 0.5, this Transform will be twisted half way from parent to child. If 1, the twist angle will be locked to the child and will rotate with along with it.")]
[Range(0f, 1f)]
public float parentChildCrossfade = 0.5f;
[Tooltip("Rotation offset around the twist axis.")]
[Range(-180f, 180f)]
public float twistAngleOffset;
private Vector3 twistAxis = Vector3.right;
private Vector3 axis = Vector3.forward;
private Vector3 axisRelativeToParentDefault;
private Vector3 axisRelativeToChildDefault;
public void Relax()
{
if (!(weight <= 0f))
{
Quaternion rotation = base.transform.rotation;
Quaternion quaternion = Quaternion.AngleAxis(twistAngleOffset, rotation * twistAxis);
rotation = quaternion * rotation;
Vector3 a = quaternion * parent.rotation * axisRelativeToParentDefault;
Vector3 b = quaternion * child.rotation * axisRelativeToChildDefault;
Vector3 vector = Vector3.Slerp(a, b, parentChildCrossfade);
vector = Quaternion.Inverse(Quaternion.LookRotation(rotation * axis, rotation * twistAxis)) * vector;
float num = Mathf.Atan2(vector.x, vector.z) * 57.29578f;
Quaternion rotation2 = child.rotation;
base.transform.rotation = Quaternion.AngleAxis(num * weight, rotation * twistAxis) * rotation;
child.rotation = rotation2;
}
}
private void Start()
{
if (parent == null)
{
parent = base.transform.parent;
}
if (child == null)
{
if (base.transform.childCount == 0)
{
Transform[] componentsInChildren = parent.GetComponentsInChildren<Transform>();
for (int i = 1; i < componentsInChildren.Length; i++)
{
if (componentsInChildren[i] != base.transform)
{
child = componentsInChildren[i];
break;
}
}
}
else
{
child = base.transform.GetChild(0);
}
}
twistAxis = base.transform.InverseTransformDirection(child.position - base.transform.position);
axis = new Vector3(twistAxis.y, twistAxis.z, twistAxis.x);
Vector3 vector = base.transform.rotation * axis;
axisRelativeToParentDefault = Quaternion.Inverse(parent.rotation) * vector;
axisRelativeToChildDefault = Quaternion.Inverse(child.rotation) * vector;
if (ik != null)
{
IKSolver iKSolver = ik.GetIKSolver();
iKSolver.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(iKSolver.OnPostUpdate, new IKSolver.UpdateDelegate(OnPostUpdate));
}
}
private void OnPostUpdate()
{
if (ik != null)
{
Relax();
}
}
private void LateUpdate()
{
if (ik == null)
{
Relax();
}
}
private void OnDestroy()
{
if (ik != null)
{
IKSolver iKSolver = ik.GetIKSolver();
iKSolver.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(iKSolver.OnPostUpdate, new IKSolver.UpdateDelegate(OnPostUpdate));
}
}
}
}