131 lines
3.0 KiB
C#
131 lines
3.0 KiB
C#
using UnityEngine;
|
|
|
|
namespace RootMotion.FinalIK
|
|
{
|
|
public abstract class RotationLimit : MonoBehaviour
|
|
{
|
|
public Vector3 axis = Vector3.forward;
|
|
|
|
[HideInInspector]
|
|
public Quaternion defaultLocalRotation;
|
|
|
|
private bool initiated;
|
|
|
|
private bool applicationQuit;
|
|
|
|
private bool defaultLocalRotationSet;
|
|
|
|
public Vector3 secondaryAxis => new Vector3(axis.y, axis.z, axis.x);
|
|
|
|
public Vector3 crossAxis => Vector3.Cross(axis, secondaryAxis);
|
|
|
|
public bool defaultLocalRotationOverride { get; private set; }
|
|
|
|
public void SetDefaultLocalRotation()
|
|
{
|
|
defaultLocalRotation = base.transform.localRotation;
|
|
defaultLocalRotationSet = true;
|
|
defaultLocalRotationOverride = false;
|
|
}
|
|
|
|
public void SetDefaultLocalRotation(Quaternion localRotation)
|
|
{
|
|
defaultLocalRotation = localRotation;
|
|
defaultLocalRotationSet = true;
|
|
defaultLocalRotationOverride = true;
|
|
}
|
|
|
|
public Quaternion GetLimitedLocalRotation(Quaternion localRotation, out bool changed)
|
|
{
|
|
if (!initiated)
|
|
{
|
|
Awake();
|
|
}
|
|
Quaternion quaternion = Quaternion.Inverse(defaultLocalRotation) * localRotation;
|
|
Quaternion q = LimitRotation(quaternion);
|
|
q = Quaternion.Normalize(q);
|
|
changed = q != quaternion;
|
|
if (!changed)
|
|
{
|
|
return localRotation;
|
|
}
|
|
return defaultLocalRotation * q;
|
|
}
|
|
|
|
public bool Apply()
|
|
{
|
|
bool changed = false;
|
|
base.transform.localRotation = GetLimitedLocalRotation(base.transform.localRotation, out changed);
|
|
return changed;
|
|
}
|
|
|
|
public void Disable()
|
|
{
|
|
if (initiated)
|
|
{
|
|
base.enabled = false;
|
|
return;
|
|
}
|
|
Awake();
|
|
base.enabled = false;
|
|
}
|
|
|
|
protected abstract Quaternion LimitRotation(Quaternion rotation);
|
|
|
|
private void Awake()
|
|
{
|
|
if (!defaultLocalRotationSet)
|
|
{
|
|
SetDefaultLocalRotation();
|
|
}
|
|
if (axis == Vector3.zero)
|
|
{
|
|
Debug.LogError("Axis is Vector3.zero.");
|
|
}
|
|
initiated = true;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
Apply();
|
|
}
|
|
|
|
public void LogWarning(string message)
|
|
{
|
|
Warning.Log(message, base.transform);
|
|
}
|
|
|
|
protected static Quaternion Limit1DOF(Quaternion rotation, Vector3 axis)
|
|
{
|
|
return Quaternion.FromToRotation(rotation * axis, axis) * rotation;
|
|
}
|
|
|
|
protected static Quaternion LimitTwist(Quaternion rotation, Vector3 axis, Vector3 orthoAxis, float twistLimit)
|
|
{
|
|
twistLimit = Mathf.Clamp(twistLimit, 0f, 180f);
|
|
if (twistLimit >= 180f)
|
|
{
|
|
return rotation;
|
|
}
|
|
Vector3 normal = rotation * axis;
|
|
Vector3 tangent = orthoAxis;
|
|
Vector3.OrthoNormalize(ref normal, ref tangent);
|
|
Vector3 tangent2 = rotation * orthoAxis;
|
|
Vector3.OrthoNormalize(ref normal, ref tangent2);
|
|
Quaternion quaternion = Quaternion.FromToRotation(tangent2, tangent) * rotation;
|
|
if (twistLimit <= 0f)
|
|
{
|
|
return quaternion;
|
|
}
|
|
return Quaternion.RotateTowards(quaternion, rotation, twistLimit);
|
|
}
|
|
|
|
protected static float GetOrthogonalAngle(Vector3 v1, Vector3 v2, Vector3 normal)
|
|
{
|
|
Vector3.OrthoNormalize(ref normal, ref v1);
|
|
Vector3.OrthoNormalize(ref normal, ref v2);
|
|
return Vector3.Angle(v1, v2);
|
|
}
|
|
}
|
|
}
|