MathUtil.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. using UnityEngine;
  3. namespace Util
  4. {
  5. class MathUtil
  6. {
  7. public static bool Decompose(Matrix4x4 matrix, out Vector3 scale, out Quaternion rotation, out Vector3 translation)
  8. {
  9. Matrix4x4 rotationMatrix;
  10. Decompose(matrix, out scale, out rotationMatrix, out translation);
  11. RotationMatrix(rotationMatrix, out rotation);
  12. return true;
  13. }
  14. private static bool Decompose(Matrix4x4 matrix, out Vector3 scale, out Matrix4x4 rotation, out Vector3 translation)
  15. {
  16. //Get the translation.
  17. translation.x = matrix.m30;
  18. translation.y = matrix.m31;
  19. translation.z = matrix.m32;
  20. //Scaling is the length of the rows.
  21. scale.x = (float)Math.Sqrt((matrix.m00 * matrix.m00) + (matrix.m01 * matrix.m01) + (matrix.m02 * matrix.m02));
  22. scale.y = (float)Math.Sqrt((matrix.m10 * matrix.m10) + (matrix.m11 * matrix.m11) + (matrix.m12 * matrix.m12));
  23. scale.z = (float)Math.Sqrt((matrix.m20 * matrix.m20) + (matrix.m21 * matrix.m21) + (matrix.m22 * matrix.m22));
  24. //If any of the scaling factors are zero, than the rotation matrix can not exist.
  25. if (IsZero(scale.x) || IsZero(scale.y) || IsZero(scale.z))
  26. {
  27. rotation = Matrix4x4.identity;
  28. return false;
  29. }
  30. Vector3 at = new Vector3(matrix.m20 / scale.z, matrix.m21 / scale.z, matrix.m22 / scale.z);
  31. Vector3 up = Vector3.Cross(at, new Vector3(matrix.m00 / scale.x, matrix.m01 / scale.x, matrix.m02 / scale.x));
  32. Vector3 right = Vector3.Cross(up, at);
  33. rotation = Matrix4x4.identity;
  34. rotation.m00 = right.x;
  35. rotation.m01 = right.y;
  36. rotation.m02 = right.z;
  37. rotation.m10 = up.x;
  38. rotation.m11 = up.y;
  39. rotation.m12 = up.z;
  40. rotation.m20 = at.x;
  41. rotation.m21 = at.y;
  42. rotation.m22 = at.z;
  43. // In case of reflexions
  44. scale.x = Vector3.Dot(right, new Vector3(matrix.m00, matrix.m01, matrix.m02)) > 0.0f ? scale.x : -scale.x;
  45. scale.y = Vector3.Dot(up, new Vector3(matrix.m10, matrix.m11, matrix.m12)) > 0.0f ? scale.y : -scale.y;
  46. scale.z = Vector3.Dot(at, new Vector3(matrix.m20, matrix.m21, matrix.m22)) > 0.0f ? scale.z : -scale.z;
  47. return true;
  48. }
  49. private static void RotationMatrix(Matrix4x4 matrix, out Quaternion result)
  50. {
  51. float sqrt;
  52. float half;
  53. float scale = matrix.m00 + matrix.m11 + matrix.m22;
  54. if (scale > 0.0f)
  55. {
  56. sqrt = (float)Math.Sqrt(scale + 1.0f);
  57. result.w = sqrt * 0.5f;
  58. sqrt = 0.5f / sqrt;
  59. result.x = (matrix.m12 - matrix.m21) * sqrt;
  60. result.y = (matrix.m20 - matrix.m02) * sqrt;
  61. result.z = (matrix.m01 - matrix.m10) * sqrt;
  62. }
  63. else if ((matrix.m00 >= matrix.m11) && (matrix.m00 >= matrix.m22))
  64. {
  65. sqrt = (float)Math.Sqrt(1.0f + matrix.m00 - matrix.m11 - matrix.m22);
  66. half = 0.5f / sqrt;
  67. result.x = 0.5f * sqrt;
  68. result.y = (matrix.m01 + matrix.m10) * half;
  69. result.z = (matrix.m02 + matrix.m20) * half;
  70. result.w = (matrix.m12 - matrix.m21) * half;
  71. }
  72. else if (matrix.m11 > matrix.m22)
  73. {
  74. sqrt = (float)Math.Sqrt(1.0f + matrix.m11 - matrix.m00 - matrix.m22);
  75. half = 0.5f / sqrt;
  76. result.x = (matrix.m10 + matrix.m01) * half;
  77. result.y = 0.5f * sqrt;
  78. result.z = (matrix.m21 + matrix.m12) * half;
  79. result.w = (matrix.m20 - matrix.m02) * half;
  80. }
  81. else
  82. {
  83. sqrt = (float)Math.Sqrt(1.0f + matrix.m22 - matrix.m00 - matrix.m11);
  84. half = 0.5f / sqrt;
  85. result.x = (matrix.m20 + matrix.m02) * half;
  86. result.y = (matrix.m21 + matrix.m12) * half;
  87. result.z = 0.5f * sqrt;
  88. result.w = (matrix.m01 - matrix.m10) * half;
  89. }
  90. }
  91. private static bool IsZero(float a)
  92. {
  93. return Math.Abs(a) < 1e-6f;
  94. }
  95. public static bool isSimilar(float a, float b)
  96. {
  97. return a - b <= 0.001;
  98. }
  99. public static float Interpolate(float startX, float endX, float start, float end, float tanPoint1, float tanPoint2, float t, out float tangent)
  100. {
  101. // Catmull-Rom splines are Hermite curves with special tangent values.
  102. // Hermite curve formula:
  103. // (2t^3 - 3t^2 + 1) * p0 + (t^3 - 2t^2 + t) * m0 + (-2t^3 + 3t^2) * p1 + (t^3 - t^2) * m1
  104. // For points p0 and p1 passing through points m0 and m1 interpolated over t = [0, 1]
  105. // Tangent M[k] = (P[k+1] - P[k-1]) / 2
  106. // With [] indicating subscript
  107. float value = (2.0f * t * t * t - 3.0f * t * t + 1.0f) * start
  108. + (t * t * t - 2.0f * t * t + t) * tanPoint1
  109. + (-2.0f * t * t * t + 3.0f * t * t) * end
  110. + (t * t * t - t * t) * tanPoint2;
  111. // Calculate tangents
  112. // p'(t) = (6t² - 6t)p0 + (3t² - 4t + 1)m0 + (-6t² + 6t)p1 + (3t² - 2t)m1
  113. tangent = (6 * t * t - 6 * t) * start
  114. + (3 * t * t - 4 * t + 1) * tanPoint1
  115. + (-6 * t * t + 6 * t) * end
  116. + (3 * t * t - 2 * t) * tanPoint2;
  117. tangent /= (endX - startX);
  118. return value;
  119. }
  120. }
  121. }