TransformCache.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace UnityEditor.U2D.Animation
  5. {
  6. internal class TransformCache : SkinningObject, IEnumerable<TransformCache>
  7. {
  8. [SerializeField]
  9. private TransformCache m_Parent;
  10. [SerializeField]
  11. private List<TransformCache> m_Children = new List<TransformCache>();
  12. [SerializeField]
  13. private Vector3 m_LocalPosition;
  14. [SerializeField]
  15. private Quaternion m_LocalRotation = Quaternion.identity;
  16. [SerializeField]
  17. private Vector3 m_LocalScale = Vector3.one;
  18. [SerializeField]
  19. private Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity;
  20. public TransformCache parent
  21. {
  22. get { return m_Parent; }
  23. }
  24. public TransformCache[] children
  25. {
  26. get { return m_Children.ToArray(); }
  27. }
  28. internal virtual int siblingIndex
  29. {
  30. get { return GetSiblingIndex(); }
  31. set { SetSiblingIndex(value); }
  32. }
  33. public int ChildCount
  34. {
  35. get { return m_Children.Count; }
  36. }
  37. public Vector3 localPosition
  38. {
  39. get { return m_LocalPosition; }
  40. set
  41. {
  42. m_LocalPosition = value;
  43. Update();
  44. }
  45. }
  46. public Quaternion localRotation
  47. {
  48. get { return m_LocalRotation; }
  49. set
  50. {
  51. m_LocalRotation = MathUtility.NormalizeQuaternion(value);
  52. Update();
  53. }
  54. }
  55. public Vector3 localScale
  56. {
  57. get { return m_LocalScale; }
  58. set
  59. {
  60. m_LocalScale = value;
  61. Update();
  62. }
  63. }
  64. public Vector3 position
  65. {
  66. get { return parentMatrix.MultiplyPoint3x4(localPosition); }
  67. set { localPosition = parentMatrix.inverse.MultiplyPoint3x4(value); }
  68. }
  69. public Quaternion rotation
  70. {
  71. get { return GetGlobalRotation(); }
  72. set { SetGlobalRotation(value); }
  73. }
  74. public Vector3 right
  75. {
  76. get { return localToWorldMatrix.MultiplyVector(Vector3.right).normalized; }
  77. set { MatchDirection(Vector3.right, value); }
  78. }
  79. public Vector3 up
  80. {
  81. get { return localToWorldMatrix.MultiplyVector(Vector3.up).normalized; }
  82. set { MatchDirection(Vector3.up, value); }
  83. }
  84. public Vector3 forward
  85. {
  86. get { return localToWorldMatrix.MultiplyVector(Vector3.forward).normalized; }
  87. set { MatchDirection(Vector3.forward, value); }
  88. }
  89. public Matrix4x4 localToWorldMatrix
  90. {
  91. get { return m_LocalToWorldMatrix; }
  92. }
  93. public Matrix4x4 worldToLocalMatrix
  94. {
  95. get { return localToWorldMatrix.inverse; }
  96. }
  97. private Matrix4x4 parentMatrix
  98. {
  99. get
  100. {
  101. var parentMatrix = Matrix4x4.identity;
  102. if (parent != null)
  103. parentMatrix = parent.localToWorldMatrix;
  104. return parentMatrix;
  105. }
  106. }
  107. internal override void OnDestroy()
  108. {
  109. if (parent != null)
  110. parent.RemoveChild(this);
  111. m_Parent = null;
  112. m_Children.Clear();
  113. }
  114. private void Update()
  115. {
  116. m_LocalToWorldMatrix = parentMatrix * Matrix4x4.TRS(localPosition, localRotation, localScale);
  117. foreach (var child in m_Children)
  118. child.Update();
  119. }
  120. private void AddChild(TransformCache transform)
  121. {
  122. m_Children.Add(transform);
  123. }
  124. private void InsertChildAt(int index, TransformCache transform)
  125. {
  126. m_Children.Insert(index, transform);
  127. }
  128. private void RemoveChild(TransformCache transform)
  129. {
  130. m_Children.Remove(transform);
  131. }
  132. private void RemoveChildAt(int index)
  133. {
  134. m_Children.RemoveAt(index);
  135. }
  136. private int GetSiblingIndex()
  137. {
  138. if (parent == null)
  139. return -1;
  140. return parent.m_Children.IndexOf(this);
  141. }
  142. private void SetSiblingIndex(int index)
  143. {
  144. if (parent != null)
  145. {
  146. var currentIndex = parent.m_Children.IndexOf(this);
  147. var indexToRemove = index < currentIndex ? currentIndex + 1 : currentIndex;
  148. parent.InsertChildAt(index, this);
  149. parent.RemoveChildAt(indexToRemove);
  150. }
  151. }
  152. public void SetParent(TransformCache newParent)
  153. {
  154. SetParent(newParent, true);
  155. }
  156. public void SetParent(TransformCache newParent, bool worldPositionStays)
  157. {
  158. if (m_Parent == newParent)
  159. return;
  160. var oldPosition = position;
  161. var oldRotation = rotation;
  162. if (m_Parent != null)
  163. m_Parent.RemoveChild(this);
  164. m_Parent = newParent;
  165. if (m_Parent != null)
  166. m_Parent.AddChild(this);
  167. if (worldPositionStays)
  168. {
  169. position = oldPosition;
  170. rotation = oldRotation;
  171. }
  172. else
  173. {
  174. Update();
  175. }
  176. }
  177. private Quaternion GetGlobalRotation()
  178. {
  179. var globalRotation = localRotation;
  180. var currentParent = parent;
  181. while (currentParent != null)
  182. {
  183. globalRotation = ScaleMulQuat(currentParent.localScale, globalRotation);
  184. globalRotation = currentParent.localRotation * globalRotation;
  185. currentParent = currentParent.parent;
  186. }
  187. return globalRotation;
  188. }
  189. private void SetGlobalRotation(Quaternion r)
  190. {
  191. if (parent != null)
  192. r = parent.InverseTransformRotation(r);
  193. localRotation = r;
  194. }
  195. private Quaternion InverseTransformRotation(Quaternion r)
  196. {
  197. if (parent != null)
  198. r = parent.InverseTransformRotation(r);
  199. r = Quaternion.Inverse(localRotation) * r;
  200. r = ScaleMulQuat(localScale, r);
  201. return r;
  202. }
  203. private Quaternion ScaleMulQuat(Vector3 scale, Quaternion q)
  204. {
  205. var s = new Vector3(Chgsign(1f, scale.x), Chgsign(1f, scale.y), Chgsign(1f, scale.z));
  206. q.x = Chgsign(q.x, s.y * s.z);
  207. q.y = Chgsign(q.y, s.x * s.z);
  208. q.z = Chgsign(q.z, s.x * s.y);
  209. return q;
  210. }
  211. private float Chgsign(float x, float y)
  212. {
  213. return y < 0f ? -x : x;
  214. }
  215. private void MatchDirection(Vector3 localDirection, Vector3 worldDirection)
  216. {
  217. var direction = worldToLocalMatrix.MultiplyVector(worldDirection);
  218. direction = Matrix4x4.TRS(Vector3.zero, localRotation, localScale).MultiplyVector(direction);
  219. var scaledLocalDirection = Vector3.Scale(localDirection, localScale);
  220. var deltaRotation = Quaternion.identity;
  221. if (scaledLocalDirection.sqrMagnitude > 0f)
  222. {
  223. var axis = Vector3.Cross(scaledLocalDirection, direction);
  224. var angle = Vector3.SignedAngle(scaledLocalDirection, direction, axis);
  225. deltaRotation = Quaternion.AngleAxis(angle, axis);
  226. }
  227. localRotation = deltaRotation;
  228. }
  229. IEnumerator<TransformCache> IEnumerable<TransformCache>.GetEnumerator()
  230. {
  231. return m_Children.GetEnumerator();
  232. }
  233. IEnumerator IEnumerable.GetEnumerator()
  234. {
  235. return (IEnumerator)m_Children.GetEnumerator();
  236. }
  237. }
  238. }