Quaternion.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include <cmath>
  2. #include "client/math/Quaternion.h"
  3. Quaternion::Quaternion() : xyz(0.0f, 0.0f, 0.0f), w(1.0f) {
  4. }
  5. Quaternion::Quaternion(float x, float y, float z, float w) : xyz(x, y, z), w(w) {
  6. }
  7. Quaternion::Quaternion(const Vector3& axis, float angle) : xyz(axis) {
  8. xyz.normalize();
  9. float sin;
  10. sincosf(angle * (M_PI / 360.0f), &sin, &w);
  11. xyz *= sin;
  12. }
  13. Quaternion Quaternion::lerp(float f, const Quaternion& other) const {
  14. return interpolate(1 - f, f, other).normalize();
  15. }
  16. Quaternion Quaternion::slerp(float f, const Quaternion& other) const {
  17. float angle = xyz.dot(other.xyz) + w * other.w;
  18. if(angle >= 1.0f) {
  19. return *this;
  20. } else if(angle < -1.0f) {
  21. angle = -1.0f;
  22. }
  23. float arccos = acosf(angle);
  24. float sin = 1.0f / sinf(arccos);
  25. return interpolate(sinf((1 - f) * arccos) * sin, sinf(f * arccos) * sin, other);
  26. }
  27. Quaternion Quaternion::interpolate(float a, float b, const Quaternion& other) const {
  28. Vector3 interpolated = xyz * a + other.xyz * b;
  29. return Quaternion(interpolated[0], interpolated[1], interpolated[2], w * a + other.w * b);
  30. }
  31. Quaternion Quaternion::squad(float f, const Quaternion& prev, const Quaternion& next, const Quaternion& nextNext) const {
  32. float diff = static_cast<Vector3>(xyz - next.xyz).squareLength() + (w - next.w) * (w - next.w);
  33. if(diff < 0.0001f) {
  34. return *this;
  35. }
  36. Quaternion s1 = squadControl(prev, next);
  37. Quaternion s2 = next.squadControl(*this, nextNext);
  38. return slerp(f, next).slerp(2.0f * f * (1.0f - f), s1.slerp(f, s2));
  39. }
  40. Quaternion Quaternion::squadControl(const Quaternion& prev, const Quaternion& next) const {
  41. Quaternion conjugate(*this);
  42. conjugate.conjugate();
  43. Quaternion s1(next);
  44. s1.mul(conjugate).log().add(Quaternion(prev).mul(conjugate).log()).mul(-0.25f).exp().mul(*this);
  45. return s1;
  46. }
  47. Quaternion& Quaternion::normalize() {
  48. float f = 1.0f / sqrtf(xyz.squareLength() + w * w);
  49. xyz *= f;
  50. w *= f;
  51. return *this;
  52. }
  53. Matrix Quaternion::toMatrix() const {
  54. float x = xyz[0];
  55. float y = xyz[1];
  56. float z = xyz[2];
  57. float x2 = 2 * x * x;
  58. float y2 = 2 * y * y;
  59. float z2 = 2 * z * z;
  60. float xy = 2 * x * y;
  61. float xz = 2 * x * z;
  62. float xw = 2 * x * w;
  63. float zw = 2 * z * w;
  64. float yz = 2 * y * z;
  65. float yw = 2 * y * w;
  66. Matrix m;
  67. m.set(0, 1 - y2 - z2).set(1, xy - zw).set(2, xz + yw);
  68. m.set(4, xy + zw).set(5, 1 - x2 - z2).set(6, yz - xw);
  69. m.set(8, xz - yw).set(9, yz + xw).set(10, 1 - x2 - y2);
  70. return m;
  71. }
  72. Quaternion& Quaternion::mul(const Quaternion& other) {
  73. Vector3 v = other.xyz * w + xyz * other.w + xyz.cross(other.xyz);
  74. w = w * other.w - xyz.dot(other.xyz);
  75. xyz = v;
  76. return *this;
  77. }
  78. Quaternion& Quaternion::mul(float f) {
  79. xyz *= f;
  80. w *= f;
  81. return *this;
  82. }
  83. Quaternion& Quaternion::add(const Quaternion& other) {
  84. xyz += other.xyz;
  85. w += other.w;
  86. return *this;
  87. }
  88. Quaternion& Quaternion::conjugate() {
  89. xyz = -xyz;
  90. return *this;
  91. }
  92. Quaternion& Quaternion::log() {
  93. // general log
  94. //float length = sqrtf(xyz.dot(xyz) + w * w);
  95. //float arccos = acos(w / length);
  96. //w = logf(length);
  97. //xyz.mul(arccos / xyz.length());
  98. // optimized use case log
  99. xyz.normalize();
  100. xyz *= acos(w);
  101. w = 0.0f;
  102. return *this;
  103. }
  104. Quaternion& Quaternion::exp() {
  105. // general exp
  106. //float expw = expf(w);
  107. //float length = xyz.length();
  108. //w = expw * cosf(length);
  109. //xyz.mul((expw * sin(length)) / length);
  110. // optimized use case exp
  111. float length = xyz.length();
  112. w = cosf(length);
  113. xyz *= sinf(length) / length;
  114. return *this;
  115. }