Singularity/Library/PackageCache/com.unity.2d.animation@7.0.10/Editor/SkinningModule/SkinningCache/BoneCache.cs
2024-05-06 11:45:45 -07:00

318 lines
8.5 KiB
C#

using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
[Serializable]
internal struct Pose
{
public Vector3 position;
public Quaternion rotation;
public Matrix4x4 matrix => Matrix4x4.TRS(position, rotation, Vector3.one);
public static Pose Create(Vector3 p, Quaternion r)
{
var pose = new Pose()
{
position = p,
rotation = r
};
return pose;
}
public override bool Equals(object other)
{
return other is Pose && this == (Pose)other;
}
public override int GetHashCode()
{
return position.GetHashCode() ^ rotation.GetHashCode();
}
public static bool operator==(Pose p1, Pose p2)
{
return p1.position == p2.position && p1.rotation == p2.rotation;
}
public static bool operator!=(Pose p1, Pose p2)
{
return !(p1 == p2);
}
}
[Serializable]
internal struct BonePose
{
public Pose pose;
public float length;
public static BonePose Create(Pose p, float l)
{
var pose = new BonePose()
{
pose = p,
length = l
};
return pose;
}
public override bool Equals(object other)
{
return other is BonePose && this == (BonePose)other;
}
public override int GetHashCode()
{
return pose.GetHashCode() ^ length.GetHashCode();
}
public static bool operator==(BonePose p1, BonePose p2)
{
return p1.pose == p2.pose && Mathf.Abs(p1.length - p2.length) < Mathf.Epsilon;
}
public static bool operator!=(BonePose p1, BonePose p2)
{
return !(p1 == p2);
}
}
internal class BoneCache : TransformCache
{
[SerializeField]
Color32 m_BindPoseColor;
[SerializeField]
Pose m_BindPose;
[SerializeField]
BonePose m_DefaultPose;
[SerializeField]
BoneCache m_ChainedChild;
[SerializeField]
float m_Depth;
[SerializeField]
float m_LocalLength = 1f;
[SerializeField]
bool m_IsVisible = true;
[SerializeField]
string m_Guid;
public bool NotInDefaultPose()
{
return localPosition != m_DefaultPose.pose.position
|| localRotation != m_DefaultPose.pose.rotation
|| Mathf.Abs(localLength - m_DefaultPose.length) > Mathf.Epsilon;
}
public bool isVisible
{
get => m_IsVisible;
set => m_IsVisible = value;
}
public Color bindPoseColor
{
get => m_BindPoseColor;
set => m_BindPoseColor = value;
}
public virtual BoneCache parentBone => parent as BoneCache;
public SkeletonCache skeleton
{
get
{
var parentSkeleton = parent as SkeletonCache;
if (parentSkeleton != null)
return parentSkeleton;
return parentBone != null ? parentBone.skeleton : null;
}
}
public virtual BoneCache chainedChild
{
get
{
if (m_ChainedChild != null && m_ChainedChild.parentBone == this)
return m_ChainedChild;
return null;
}
set
{
if (m_ChainedChild != value)
{
if (value == null || value.parentBone == this)
{
m_ChainedChild = value;
if(m_ChainedChild != null)
OrientToChainedChild(false);
}
}
}
}
Vector3 localEndPosition => Vector3.right * localLength;
public Vector3 endPosition
{
get => localToWorldMatrix.MultiplyPoint3x4(localEndPosition);
set
{
if (chainedChild != null)
return;
var direction = value - position;
right = direction;
length = direction.magnitude;
}
}
public BonePose localPose
{
get => BonePose.Create(Pose.Create(localPosition, localRotation), localLength);
set
{
localPosition = value.pose.position;
localRotation = value.pose.rotation;
localLength = value.length;
}
}
public BonePose worldPose
{
get => BonePose.Create(Pose.Create(position, rotation), length);
set
{
position = value.pose.position;
rotation = value.pose.rotation;
length = value.length;
}
}
public Pose bindPose => m_BindPose;
public string guid
{
get => m_Guid;
set => m_Guid = value;
}
public float depth
{
get => m_Depth;
set => m_Depth = value;
}
public float localLength
{
get => m_LocalLength;
set => m_LocalLength = Mathf.Max(0f, value);
}
public float length
{
get => localToWorldMatrix.MultiplyVector(localEndPosition).magnitude;
set => m_LocalLength = worldToLocalMatrix.MultiplyVector(right * Mathf.Max(0f, value)).magnitude;
}
internal Pose[] GetChildrenWoldPose()
{
return Array.ConvertAll(children, c => Pose.Create(c.position, c.rotation));
}
internal void SetChildrenWorldPose(Pose[] worldPoses)
{
var childrenArray = children;
Debug.Assert(childrenArray.Length == worldPoses.Length);
for (var i = 0; i < childrenArray.Length; ++i)
{
var child = childrenArray[i];
var pose= worldPoses[i];
child.position = pose.position;
child.rotation = pose.rotation;
}
}
internal override void OnDestroy()
{
base.OnDestroy();
m_ChainedChild = null;
}
public new void SetParent(TransformCache newParent, bool worldPositionStays = true)
{
if (parentBone != null && parentBone.chainedChild == this)
parentBone.chainedChild = null;
base.SetParent(newParent, worldPositionStays);
if (parentBone != null && parentBone.chainedChild == null && (parentBone.endPosition - position).sqrMagnitude < 0.001f)
parentBone.chainedChild = this;
}
public void OrientToChainedChild(bool freezeChildren)
{
Debug.Assert(chainedChild != null);
var childPosition = chainedChild.position;
var childRotation = chainedChild.rotation;
Pose[] childrenWorldPose = null;
if (freezeChildren)
childrenWorldPose = GetChildrenWoldPose();
right = childPosition - position;
if (freezeChildren)
{
SetChildrenWorldPose(childrenWorldPose);
}
else
{
chainedChild.position = childPosition;
chainedChild.rotation = childRotation;
}
length = (childPosition - position).magnitude;
}
public void SetDefaultPose()
{
m_DefaultPose = localPose;
if (IsUnscaled())
m_BindPose = worldPose.pose;
else
throw new Exception("BindPose cannot be set under global scale");
}
public void RestoreDefaultPose()
{
localPose = m_DefaultPose;
}
bool IsUnscaled()
{
var currentTransform = this as TransformCache;
while (currentTransform != null)
{
var scale = currentTransform.localScale;
var isUnscaled = Mathf.Approximately(scale.x, 1f) && Mathf.Approximately(scale.y, 1f) && Mathf.Approximately(scale.z, 1f);
if (!isUnscaled)
return false;
currentTransform = currentTransform.parent;
}
return true;
}
}
}