V3Tools.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion {
  4. /// <summary>
  5. /// Helper methods for dealing with 3-dimensional vectors.
  6. /// </summary>
  7. public static class V3Tools {
  8. /// <summary>
  9. /// Returns yaw angle (-180 - 180) of 'forward' vector.
  10. /// </summary>
  11. public static float GetYaw(Vector3 forward)
  12. {
  13. return Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
  14. }
  15. /// <summary>
  16. /// Returns pitch angle (-90 - 90) of 'forward' vector.
  17. /// </summary>
  18. public static float GetPitch(Vector3 forward)
  19. {
  20. forward = forward.normalized; // Asin range -1 - 1
  21. return -Mathf.Asin(forward.y) * Mathf.Rad2Deg;
  22. }
  23. /// <summary>
  24. /// Returns bank angle (-180 - 180) of 'forward' and 'up' vectors.
  25. /// </summary>
  26. public static float GetBank(Vector3 forward, Vector3 up)
  27. {
  28. Quaternion q = Quaternion.Inverse(Quaternion.LookRotation(Vector3.up, forward));
  29. up = q * up;
  30. return Mathf.Atan2(up.x, up.z) * Mathf.Rad2Deg;
  31. }
  32. /// <summary>
  33. /// Returns yaw angle (-180 - 180) of 'forward' vector relative to rotation space defined by spaceForward and spaceUp axes.
  34. /// </summary>
  35. public static float GetYaw(Vector3 spaceForward, Vector3 spaceUp, Vector3 forward)
  36. {
  37. Quaternion space = Quaternion.Inverse(Quaternion.LookRotation(spaceForward, spaceUp));
  38. Vector3 dirLocal = space * forward;
  39. return Mathf.Atan2(dirLocal.x, dirLocal.z) * Mathf.Rad2Deg;
  40. }
  41. /// <summary>
  42. /// Returns pitch angle (-90 - 90) of 'forward' vector relative to rotation space defined by spaceForward and spaceUp axes.
  43. /// </summary>
  44. public static float GetPitch(Vector3 spaceForward, Vector3 spaceUp, Vector3 forward)
  45. {
  46. Quaternion space = Quaternion.Inverse(Quaternion.LookRotation(spaceForward, spaceUp));
  47. Vector3 dirLocal = space * forward;
  48. return -Mathf.Asin(dirLocal.y) * Mathf.Rad2Deg;
  49. }
  50. /// <summary>
  51. /// Returns bank angle (-180 - 180) of 'forward' and 'up' vectors relative to rotation space defined by spaceForward and spaceUp axes.
  52. /// </summary>
  53. public static float GetBank(Vector3 spaceForward, Vector3 spaceUp, Vector3 forward, Vector3 up)
  54. {
  55. Quaternion space = Quaternion.Inverse(Quaternion.LookRotation(spaceForward, spaceUp));
  56. forward = space * forward;
  57. up = space * up;
  58. Quaternion q = Quaternion.Inverse(Quaternion.LookRotation(spaceUp, forward));
  59. up = q * up;
  60. return Mathf.Atan2(up.x, up.z) * Mathf.Rad2Deg;
  61. }
  62. /// <summary>
  63. /// Optimized Vector3.Lerp
  64. /// </summary>
  65. public static Vector3 Lerp(Vector3 fromVector, Vector3 toVector, float weight) {
  66. if (weight <= 0f) return fromVector;
  67. if (weight >= 1f) return toVector;
  68. return Vector3.Lerp(fromVector, toVector, weight);
  69. }
  70. /// <summary>
  71. /// Optimized Vector3.Slerp
  72. /// </summary>
  73. public static Vector3 Slerp(Vector3 fromVector, Vector3 toVector, float weight) {
  74. if (weight <= 0f) return fromVector;
  75. if (weight >= 1f) return toVector;
  76. return Vector3.Slerp(fromVector, toVector, weight);
  77. }
  78. /// <summary>
  79. /// Returns vector projection on axis multiplied by weight.
  80. /// </summary>
  81. public static Vector3 ExtractVertical(Vector3 v, Vector3 verticalAxis, float weight) {
  82. if (weight == 0f) return Vector3.zero;
  83. return Vector3.Project(v, verticalAxis) * weight;
  84. }
  85. /// <summary>
  86. /// Returns vector projected to a plane and multiplied by weight.
  87. /// </summary>
  88. public static Vector3 ExtractHorizontal(Vector3 v, Vector3 normal, float weight) {
  89. if (weight == 0f) return Vector3.zero;
  90. Vector3 tangent = v;
  91. Vector3.OrthoNormalize(ref normal, ref tangent);
  92. return Vector3.Project(v, tangent) * weight;
  93. }
  94. /// <summary>
  95. /// Clamps the direction to clampWeight from normalDirection, clampSmoothing is the number of sine smoothing iterations applied on the result.
  96. /// </summary>
  97. public static Vector3 ClampDirection(Vector3 direction, Vector3 normalDirection, float clampWeight, int clampSmoothing)
  98. {
  99. if (clampWeight <= 0) return direction;
  100. if (clampWeight >= 1f) return normalDirection;
  101. // Getting the angle between direction and normalDirection
  102. float angle = Vector3.Angle(normalDirection, direction);
  103. float dot = 1f - (angle / 180f);
  104. if (dot > clampWeight) return direction;
  105. // Clamping the target
  106. float targetClampMlp = clampWeight > 0 ? Mathf.Clamp(1f - ((clampWeight - dot) / (1f - dot)), 0f, 1f) : 1f;
  107. // Calculating the clamp multiplier
  108. float clampMlp = clampWeight > 0 ? Mathf.Clamp(dot / clampWeight, 0f, 1f) : 1f;
  109. // Sine smoothing iterations
  110. for (int i = 0; i < clampSmoothing; i++)
  111. {
  112. float sinF = clampMlp * Mathf.PI * 0.5f;
  113. clampMlp = Mathf.Sin(sinF);
  114. }
  115. // Slerping the direction (don't use Lerp here, it breaks it)
  116. return Vector3.Slerp(normalDirection, direction, clampMlp * targetClampMlp);
  117. }
  118. /// <summary>
  119. /// Clamps the direction to clampWeight from normalDirection, clampSmoothing is the number of sine smoothing iterations applied on the result.
  120. /// </summary>
  121. public static Vector3 ClampDirection(Vector3 direction, Vector3 normalDirection, float clampWeight, int clampSmoothing, out bool changed) {
  122. changed = false;
  123. if (clampWeight <= 0) return direction;
  124. if (clampWeight >= 1f) {
  125. changed = true;
  126. return normalDirection;
  127. }
  128. // Getting the angle between direction and normalDirection
  129. float angle = Vector3.Angle(normalDirection, direction);
  130. float dot = 1f - (angle / 180f);
  131. if (dot > clampWeight) return direction;
  132. changed = true;
  133. // Clamping the target
  134. float targetClampMlp = clampWeight > 0? Mathf.Clamp(1f - ((clampWeight - dot) / (1f - dot)), 0f, 1f): 1f;
  135. // Calculating the clamp multiplier
  136. float clampMlp = clampWeight > 0? Mathf.Clamp(dot / clampWeight, 0f, 1f): 1f;
  137. // Sine smoothing iterations
  138. for (int i = 0; i < clampSmoothing; i++) {
  139. float sinF = clampMlp * Mathf.PI * 0.5f;
  140. clampMlp = Mathf.Sin(sinF);
  141. }
  142. // Slerping the direction (don't use Lerp here, it breaks it)
  143. return Vector3.Slerp(normalDirection, direction, clampMlp * targetClampMlp);
  144. }
  145. /// <summary>
  146. /// Clamps the direction to clampWeight from normalDirection, clampSmoothing is the number of sine smoothing iterations applied on the result.
  147. /// </summary>
  148. public static Vector3 ClampDirection(Vector3 direction, Vector3 normalDirection, float clampWeight, int clampSmoothing, out float clampValue) {
  149. clampValue = 1f;
  150. if (clampWeight <= 0) return direction;
  151. if (clampWeight >= 1f) {
  152. return normalDirection;
  153. }
  154. // Getting the angle between direction and normalDirection
  155. float angle = Vector3.Angle(normalDirection, direction);
  156. float dot = 1f - (angle / 180f);
  157. if (dot > clampWeight) {
  158. clampValue = 0f;
  159. return direction;
  160. }
  161. // Clamping the target
  162. float targetClampMlp = clampWeight > 0? Mathf.Clamp(1f - ((clampWeight - dot) / (1f - dot)), 0f, 1f): 1f;
  163. // Calculating the clamp multiplier
  164. float clampMlp = clampWeight > 0? Mathf.Clamp(dot / clampWeight, 0f, 1f): 1f;
  165. // Sine smoothing iterations
  166. for (int i = 0; i < clampSmoothing; i++) {
  167. float sinF = clampMlp * Mathf.PI * 0.5f;
  168. clampMlp = Mathf.Sin(sinF);
  169. }
  170. // Slerping the direction (don't use Lerp here, it breaks it)
  171. float slerp = clampMlp * targetClampMlp;
  172. clampValue = 1f - slerp;
  173. return Vector3.Slerp(normalDirection, direction, slerp);
  174. }
  175. /// <summary>
  176. /// Get the intersection point of line and plane
  177. /// </summary>
  178. public static Vector3 LineToPlane(Vector3 origin, Vector3 direction, Vector3 planeNormal, Vector3 planePoint) {
  179. float dot = Vector3.Dot(planePoint - origin, planeNormal);
  180. float normalDot = Vector3.Dot(direction, planeNormal);
  181. if (normalDot == 0.0f) return Vector3.zero;
  182. float dist = dot / normalDot;
  183. return origin + direction.normalized * dist;
  184. }
  185. /// <summary>
  186. /// Projects a point to a plane.
  187. /// </summary>
  188. public static Vector3 PointToPlane(Vector3 point, Vector3 planePosition, Vector3 planeNormal) {
  189. if (planeNormal == Vector3.up) {
  190. return new Vector3(point.x, planePosition.y, point.z);
  191. }
  192. Vector3 tangent = point - planePosition;
  193. Vector3 normal = planeNormal;
  194. Vector3.OrthoNormalize(ref normal, ref tangent);
  195. return planePosition + Vector3.Project(point - planePosition, tangent);
  196. }
  197. /// <summary>
  198. /// Same as Transform.TransformPoint(), but not using scale.
  199. /// </summary>
  200. public static Vector3 TransformPointUnscaled(Transform t, Vector3 point)
  201. {
  202. return t.position + t.rotation * point;
  203. }
  204. /// <summary>
  205. /// Same as Transform.InverseTransformPoint(), but not using scale.
  206. /// </summary>
  207. public static Vector3 InverseTransformPointUnscaled(Transform t, Vector3 point)
  208. {
  209. return Quaternion.Inverse(t.rotation) * (point - t.position);
  210. }
  211. /// <summary>
  212. /// Same as Transform.InverseTransformPoint();
  213. /// </summary>
  214. public static Vector3 InverseTransformPoint(Vector3 tPos, Quaternion tRot, Vector3 tScale, Vector3 point)
  215. {
  216. return Div(Quaternion.Inverse(tRot) * (point - tPos), tScale);
  217. }
  218. /// <summary>
  219. /// Same as Transform.TransformPoint()
  220. /// </summary>
  221. public static Vector3 TransformPoint(Vector3 tPos, Quaternion tRot, Vector3 tScale, Vector3 point)
  222. {
  223. return tPos + Vector3.Scale(tRot * point, tScale);
  224. }
  225. /// <summary>
  226. /// Divides the values of v1 by the values of v2.
  227. /// </summary>
  228. public static Vector3 Div(Vector3 v1, Vector3 v2)
  229. {
  230. return new Vector3(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
  231. }
  232. }
  233. }