PoseUtils.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using UnityEngine;
  2. namespace Rokid.UXR.Interaction {
  3. /// Tools for working with Unity Poses
  4. /// </summary>
  5. public static class PoseUtils
  6. {
  7. /// <summary>
  8. /// Assigns a Pose to a given transform.
  9. /// </summary>
  10. /// <param name="transform"> The transform to which apply the pose.</param>
  11. /// <param name="pose">The desired pose.</param>
  12. /// <param name="space">If the pose should be applied to the local position/rotation or world position/rotation.</param>
  13. public static void SetPose(this Transform transform, in Pose pose, Space space = Space.World)
  14. {
  15. if (space == Space.World)
  16. {
  17. transform.SetPositionAndRotation(pose.position, pose.rotation);
  18. }
  19. else
  20. {
  21. transform.localRotation = pose.rotation;
  22. transform.localPosition = pose.position;
  23. }
  24. }
  25. /// <summary>
  26. /// Extract the position/rotation of a given transform.
  27. /// </summary>
  28. /// <param name="transform">The transform from which to extract the pose.</param>
  29. /// <param name="space">If the desired position/rotation is the world or local one.</param>
  30. /// <returns>A Pose containing the position/rotation of the transform.</returns>
  31. public static Pose GetPose(this Transform transform, Space space = Space.World)
  32. {
  33. if (space == Space.World)
  34. {
  35. return new Pose(transform.position, transform.rotation);
  36. }
  37. else
  38. {
  39. return new Pose(transform.localPosition, transform.localRotation);
  40. }
  41. }
  42. /// <summary>
  43. /// Compose two poses, applying the first to the second one.
  44. /// </summary>
  45. /// <param name="a">First pose to compose.</param>
  46. /// <param name="b">Pose to compose over the first one.</param>
  47. /// <param name="result">A Pose with the two operands applied.</param>
  48. public static void Multiply(in Pose a, in Pose b, ref Pose result)
  49. {
  50. result.position = a.position + a.rotation * b.position;
  51. result.rotation = a.rotation * b.rotation;
  52. }
  53. public static Pose Multiply(in Pose a, in Pose b)
  54. {
  55. Pose result = new Pose();
  56. Multiply(a, b, ref result);
  57. return result;
  58. }
  59. /// <summary>
  60. /// Compose two poses, applying the provided one on top of the caller.
  61. /// </summary>
  62. /// <param name="a">Pose to compose upon.</param>
  63. /// <param name="b">Pose to compose over the first one.</param>
  64. public static void Premultiply(this ref Pose a, in Pose b)
  65. {
  66. Multiply(a, b, ref a);
  67. }
  68. /// <summary>
  69. /// Compose two poses, applying the caller on top of the provided pose.
  70. /// </summary>
  71. /// <param name="a">Pose to compose upon.</param>
  72. /// <param name="b">Pose to compose over the first one.</param>
  73. public static void Postmultiply(this ref Pose a, in Pose b)
  74. {
  75. Multiply(b, a, ref a);
  76. }
  77. /// <summary>
  78. /// Moves the calling pose towards a target one using interpolation
  79. /// </summary>
  80. /// <param name="from">Original pose to interpolate from</param>
  81. /// <param name="to">Target pose for the interpolation.</param>
  82. /// <param name="t">Interpolation factor, normalized but will not be clamped.</param>
  83. public static void Lerp(this ref Pose from, in Pose to, float t)
  84. {
  85. Lerp(from, to, t, ref from);
  86. }
  87. /// <summary>
  88. /// Interpolation between two poses.
  89. /// </summary>
  90. /// <param name="from">From pose.</param>
  91. /// <param name="to">To pose.</param>
  92. /// <param name="t">Interpolation factor, normalized but will not be clamped.</param>
  93. /// <param name="result">A Pose between a and b</param>
  94. public static void Lerp(in Pose from, in Pose to, float t, ref Pose result)
  95. {
  96. result.position = Vector3.LerpUnclamped(from.position, to.position, t);
  97. result.rotation = Quaternion.SlerpUnclamped(from.rotation, to.rotation, t);
  98. }
  99. public static void Inverse(in Pose a, ref Pose result)
  100. {
  101. result.rotation = Quaternion.Inverse(a.rotation);
  102. result.position = result.rotation * -a.position;
  103. }
  104. public static void Invert(this ref Pose a)
  105. {
  106. Inverse(a, ref a);
  107. }
  108. public static void CopyFrom(this ref Pose to, in Pose from)
  109. {
  110. to.position = from.position;
  111. to.rotation = from.rotation;
  112. }
  113. /// <summary>
  114. /// Get the position/rotation difference between two transforms.
  115. /// </summary>
  116. /// <param name="from">The base transform.</param>
  117. /// <param name="to">The target transform.</param>
  118. /// <returns>A Pose indicating the position/rotation change</returns>
  119. public static Pose Delta(this Transform from, Transform to)
  120. {
  121. return Delta(from.position, from.rotation, to.position, to.rotation);
  122. }
  123. /// <summary>
  124. /// Get the position/rotation difference between a transform and a pose.
  125. /// </summary>
  126. /// <param name="from">The base transform.</param>
  127. /// <param name="to">The target pose.</param>
  128. /// <returns>A Pose indicating the delta.</returns>
  129. public static Pose Delta(this Transform from, in Pose to)
  130. {
  131. return Delta(from.position, from.rotation, to.position, to.rotation);
  132. }
  133. public static void Delta(this Transform from, in Pose to, ref Pose result)
  134. {
  135. Delta(from.position, from.rotation, to.position, to.rotation, ref result);
  136. }
  137. /// <summary>
  138. /// Get the position/rotation difference between two poses.
  139. /// </summary>
  140. /// <param name="from">The base pose.</param>
  141. /// <param name="to">The target pose.</param>
  142. /// <returns>A Pose indicating the delta.</returns>
  143. public static Pose Delta(in Pose from, in Pose to)
  144. {
  145. return Delta(from.position, from.rotation, to.position, to.rotation);
  146. }
  147. /// <summary>
  148. /// Get the position/rotation difference between two poses, indicated with separated positions and rotations.
  149. /// </summary>
  150. /// <param name="fromPosition">The base position.</param>
  151. /// <param name="fromRotation">The base rotation.</param>
  152. /// <param name="toPosition">The target position.</param>
  153. /// <param name="toRotation">The target rotation.</param>
  154. /// <returns>A Pose indicating the delta.</returns>
  155. private static Pose Delta(Vector3 fromPosition, Quaternion fromRotation, Vector3 toPosition, Quaternion toRotation)
  156. {
  157. Pose result = new Pose();
  158. Delta(fromPosition, fromRotation, toPosition, toRotation, ref result);
  159. return result;
  160. }
  161. private static void Delta(Vector3 fromPosition, Quaternion fromRotation, Vector3 toPosition, Quaternion toRotation, ref Pose result)
  162. {
  163. Quaternion inverseFromRot = Quaternion.Inverse(fromRotation);
  164. result.position = inverseFromRot * (toPosition - fromPosition);
  165. result.rotation = inverseFromRot * toRotation;
  166. }
  167. /// <summary>
  168. /// Get the world position/rotation of a relative position.
  169. /// </summary>
  170. /// <param name="reference">The transform in which the offset is local.</param>
  171. /// <param name="offset">The offset from the reference.</param>
  172. /// <returns>A Pose in world units.</returns>
  173. public static Pose GlobalPose(this Transform reference, in Pose offset)
  174. {
  175. return new Pose(
  176. reference.position + reference.rotation * offset.position,
  177. reference.rotation * offset.rotation);
  178. }
  179. /// <summary>
  180. /// Rotate a pose around an axis.
  181. /// </summary>
  182. /// <param name="pose">The pose to mirror.</param>
  183. /// <param name="normal">The direction of the mirror.</param>
  184. /// <param name="tangent">The tangent of the mirror.</param>
  185. /// <returns>A mirrored pose.</returns>
  186. public static Pose MirrorPoseRotation(this in Pose pose, Vector3 normal, Vector3 tangent)
  187. {
  188. Pose mirrorPose = pose;
  189. Vector3 forward = pose.rotation * -Vector3.forward;
  190. Vector3 projectedForward = Vector3.ProjectOnPlane(forward, normal);
  191. float angleForward = Vector3.SignedAngle(projectedForward, tangent, normal);
  192. Vector3 mirrorForward = Quaternion.AngleAxis(2 * angleForward, normal) * forward;
  193. Vector3 up = pose.rotation * -Vector3.up;
  194. Vector3 projectedUp = Vector3.ProjectOnPlane(up, normal);
  195. float angleUp = Vector3.SignedAngle(projectedUp, tangent, normal);
  196. Vector3 mirrorUp = Quaternion.AngleAxis(2 * angleUp, normal) * up;
  197. mirrorPose.rotation = Quaternion.LookRotation(mirrorForward, mirrorUp);
  198. return mirrorPose;
  199. }
  200. }
  201. }