Files
PixelJumperHero/Library/PackageCache/com.unity.2d.animation@6.0.1/Editor/SkinningModule/SkinningCache/TransformCache.cs
2021-06-13 10:28:03 +02:00

288 lines
7.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class TransformCache : SkinningObject, IEnumerable<TransformCache>
{
[SerializeField]
private TransformCache m_Parent;
[SerializeField]
private List<TransformCache> m_Children = new List<TransformCache>();
[SerializeField]
private Vector3 m_LocalPosition;
[SerializeField]
private Quaternion m_LocalRotation = Quaternion.identity;
[SerializeField]
private Vector3 m_LocalScale = Vector3.one;
[SerializeField]
private Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity;
public TransformCache parent
{
get { return m_Parent; }
}
public TransformCache[] children
{
get { return m_Children.ToArray(); }
}
internal virtual int siblingIndex
{
get { return GetSiblingIndex(); }
set { SetSiblingIndex(value); }
}
public int ChildCount
{
get { return m_Children.Count; }
}
public Vector3 localPosition
{
get { return m_LocalPosition; }
set
{
m_LocalPosition = value;
Update();
}
}
public Quaternion localRotation
{
get { return m_LocalRotation; }
set
{
m_LocalRotation = MathUtility.NormalizeQuaternion(value);
Update();
}
}
public Vector3 localScale
{
get { return m_LocalScale; }
set
{
m_LocalScale = value;
Update();
}
}
public Vector3 position
{
get { return parentMatrix.MultiplyPoint3x4(localPosition); }
set { localPosition = parentMatrix.inverse.MultiplyPoint3x4(value); }
}
public Quaternion rotation
{
get { return GetGlobalRotation(); }
set { SetGlobalRotation(value); }
}
public Vector3 right
{
get { return localToWorldMatrix.MultiplyVector(Vector3.right).normalized; }
set { MatchDirection(Vector3.right, value); }
}
public Vector3 up
{
get { return localToWorldMatrix.MultiplyVector(Vector3.up).normalized; }
set { MatchDirection(Vector3.up, value); }
}
public Vector3 forward
{
get { return localToWorldMatrix.MultiplyVector(Vector3.forward).normalized; }
set { MatchDirection(Vector3.forward, value); }
}
public Matrix4x4 localToWorldMatrix
{
get { return m_LocalToWorldMatrix; }
}
public Matrix4x4 worldToLocalMatrix
{
get { return localToWorldMatrix.inverse; }
}
private Matrix4x4 parentMatrix
{
get
{
var parentMatrix = Matrix4x4.identity;
if (parent != null)
parentMatrix = parent.localToWorldMatrix;
return parentMatrix;
}
}
internal override void OnDestroy()
{
if (parent != null)
parent.RemoveChild(this);
m_Parent = null;
m_Children.Clear();
}
private void Update()
{
m_LocalToWorldMatrix = parentMatrix * Matrix4x4.TRS(localPosition, localRotation, localScale);
foreach (var child in m_Children)
child.Update();
}
private void AddChild(TransformCache transform)
{
m_Children.Add(transform);
}
private void InsertChildAt(int index, TransformCache transform)
{
m_Children.Insert(index, transform);
}
private void RemoveChild(TransformCache transform)
{
m_Children.Remove(transform);
}
private void RemoveChildAt(int index)
{
m_Children.RemoveAt(index);
}
private int GetSiblingIndex()
{
if (parent == null)
return -1;
return parent.m_Children.IndexOf(this);
}
private void SetSiblingIndex(int index)
{
if (parent != null)
{
var currentIndex = parent.m_Children.IndexOf(this);
var indexToRemove = index < currentIndex ? currentIndex + 1 : currentIndex;
parent.InsertChildAt(index, this);
parent.RemoveChildAt(indexToRemove);
}
}
public void SetParent(TransformCache newParent)
{
SetParent(newParent, true);
}
public void SetParent(TransformCache newParent, bool worldPositionStays)
{
if (m_Parent == newParent)
return;
var oldPosition = position;
var oldRotation = rotation;
if (m_Parent != null)
m_Parent.RemoveChild(this);
m_Parent = newParent;
if (m_Parent != null)
m_Parent.AddChild(this);
if (worldPositionStays)
{
position = oldPosition;
rotation = oldRotation;
}
else
{
Update();
}
}
private Quaternion GetGlobalRotation()
{
var globalRotation = localRotation;
var currentParent = parent;
while (currentParent != null)
{
globalRotation = ScaleMulQuat(currentParent.localScale, globalRotation);
globalRotation = currentParent.localRotation * globalRotation;
currentParent = currentParent.parent;
}
return globalRotation;
}
private void SetGlobalRotation(Quaternion r)
{
if (parent != null)
r = parent.InverseTransformRotation(r);
localRotation = r;
}
private Quaternion InverseTransformRotation(Quaternion r)
{
if (parent != null)
r = parent.InverseTransformRotation(r);
r = Quaternion.Inverse(localRotation) * r;
r = ScaleMulQuat(localScale, r);
return r;
}
private Quaternion ScaleMulQuat(Vector3 scale, Quaternion q)
{
var s = new Vector3(Chgsign(1f, scale.x), Chgsign(1f, scale.y), Chgsign(1f, scale.z));
q.x = Chgsign(q.x, s.y * s.z);
q.y = Chgsign(q.y, s.x * s.z);
q.z = Chgsign(q.z, s.x * s.y);
return q;
}
private float Chgsign(float x, float y)
{
return y < 0f ? -x : x;
}
private void MatchDirection(Vector3 localDirection, Vector3 worldDirection)
{
var direction = worldToLocalMatrix.MultiplyVector(worldDirection);
direction = Matrix4x4.TRS(Vector3.zero, localRotation, localScale).MultiplyVector(direction);
var scaledLocalDirection = Vector3.Scale(localDirection, localScale);
var deltaRotation = Quaternion.identity;
if (scaledLocalDirection.sqrMagnitude > 0f)
{
var axis = Vector3.Cross(scaledLocalDirection, direction);
var angle = Vector3.SignedAngle(scaledLocalDirection, direction, axis);
deltaRotation = Quaternion.AngleAxis(angle, axis);
}
localRotation = deltaRotation;
}
IEnumerator<TransformCache> IEnumerable<TransformCache>.GetEnumerator()
{
return m_Children.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)m_Children.GetEnumerator();
}
}
}