Quaternion.cpp 3.7 KB

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