Quat.inl 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. namespace JPH {
  4. Quat Quat::operator * (QuatArg inRHS) const
  5. {
  6. #if defined(JPH_USE_SSE)
  7. // Taken from: http://momchil-velikov.blogspot.nl/2013/10/fast-sse-quternion-multiplication.html
  8. __m128 abcd = mValue.mValue;
  9. __m128 xyzw = inRHS.mValue.mValue;
  10. __m128 t0 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(3, 3, 3, 3));
  11. __m128 t1 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(2, 3, 0, 1));
  12. __m128 t3 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(0, 0, 0, 0));
  13. __m128 t4 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(1, 0, 3, 2));
  14. __m128 t5 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(1, 1, 1, 1));
  15. __m128 t6 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(2, 0, 3, 1));
  16. // [d,d,d,d] * [z,w,x,y] = [dz,dw,dx,dy]
  17. __m128 m0 = _mm_mul_ps(t0, t1);
  18. // [a,a,a,a] * [y,x,w,z] = [ay,ax,aw,az]
  19. __m128 m1 = _mm_mul_ps(t3, t4);
  20. // [b,b,b,b] * [z,x,w,y] = [bz,bx,bw,by]
  21. __m128 m2 = _mm_mul_ps(t5, t6);
  22. // [c,c,c,c] * [w,z,x,y] = [cw,cz,cx,cy]
  23. __m128 t7 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(2, 2, 2, 2));
  24. __m128 t8 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(3, 2, 0, 1));
  25. __m128 m3 = _mm_mul_ps(t7, t8);
  26. // [dz,dw,dx,dy] + -[ay,ax,aw,az] = [dz+ay,dw-ax,dx+aw,dy-az]
  27. __m128 e = _mm_addsub_ps(m0, m1);
  28. // [dx+aw,dz+ay,dy-az,dw-ax]
  29. e = _mm_shuffle_ps(e, e, _MM_SHUFFLE(1, 3, 0, 2));
  30. // [dx+aw,dz+ay,dy-az,dw-ax] + -[bz,bx,bw,by] = [dx+aw+bz,dz+ay-bx,dy-az+bw,dw-ax-by]
  31. e = _mm_addsub_ps(e, m2);
  32. // [dz+ay-bx,dw-ax-by,dy-az+bw,dx+aw+bz]
  33. e = _mm_shuffle_ps(e, e, _MM_SHUFFLE(2, 0, 1, 3));
  34. // [dz+ay-bx,dw-ax-by,dy-az+bw,dx+aw+bz] + -[cw,cz,cx,cy] = [dz+ay-bx+cw,dw-ax-by-cz,dy-az+bw+cx,dx+aw+bz-cy]
  35. e = _mm_addsub_ps(e, m3);
  36. // [dw-ax-by-cz,dz+ay-bx+cw,dy-az+bw+cx,dx+aw+bz-cy]
  37. return Quat(Vec4(_mm_shuffle_ps(e, e, _MM_SHUFFLE(2, 3, 1, 0))));
  38. #else
  39. float lx = mValue.GetX();
  40. float ly = mValue.GetY();
  41. float lz = mValue.GetZ();
  42. float lw = mValue.GetW();
  43. float rx = inRHS.mValue.GetX();
  44. float ry = inRHS.mValue.GetY();
  45. float rz = inRHS.mValue.GetZ();
  46. float rw = inRHS.mValue.GetW();
  47. float x = lw * rx + lx * rw + ly * rz - lz * ry;
  48. float y = lw * ry - lx * rz + ly * rw + lz * rx;
  49. float z = lw * rz + lx * ry - ly * rx + lz * rw;
  50. float w = lw * rw - lx * rx - ly * ry - lz * rz;
  51. return Quat(x, y, z, w);
  52. #endif
  53. }
  54. Quat Quat::sRotation(Vec3Arg inAxis, float inAngle)
  55. {
  56. JPH_ASSERT(inAxis.IsNormalized());
  57. float half_angle = 0.5f * inAngle;
  58. return Quat(Vec4(inAxis * sin(half_angle), cos(half_angle)));
  59. }
  60. void Quat::GetAxisAngle(Vec3 &outAxis, float &outAngle) const
  61. {
  62. JPH_ASSERT(IsNormalized());
  63. Quat w_pos = EnsureWPositive();
  64. float abs_w = w_pos.GetW();
  65. if (abs_w >= 1.0f)
  66. {
  67. outAxis = Vec3::sZero();
  68. outAngle = 0.0f;
  69. }
  70. else
  71. {
  72. outAngle = 2.0f * acos(abs_w);
  73. outAxis = w_pos.GetXYZ().NormalizedOr(Vec3::sZero());
  74. }
  75. }
  76. Quat Quat::sFromTo(Vec3Arg inFrom, Vec3Arg inTo)
  77. {
  78. /*
  79. Uses (inFrom = v1, inTo = v2):
  80. angle = arcos(v1 . v2 / |v1||v2|)
  81. axis = normalize(v1 x v2)
  82. Quaternion is then:
  83. s = sin(angle / 2)
  84. x = axis.x * s
  85. y = axis.y * s
  86. z = axis.z * s
  87. w = cos(angle / 2)
  88. Using identities:
  89. sin(2 * a) = 2 * sin(a) * cos(a)
  90. cos(2 * a) = cos(a)^2 - sin(a)^2
  91. sin(a)^2 + cos(a)^2 = 1
  92. This reduces to:
  93. x = (v1 x v2).x
  94. y = (v1 x v2).y
  95. z = (v1 x v2).z
  96. w = |v1||v2| + v1 . v2
  97. which then needs to be normalized because the whole equation was multiplied by 2 cos(angle / 2)
  98. */
  99. float w = sqrt(inFrom.LengthSq() * inTo.LengthSq()) + inFrom.Dot(inTo);
  100. // Check if vectors are perpendicular, if take one of the many 180 degree rotations that exist
  101. if (w == 0.0f)
  102. return Quat(Vec4(inFrom.GetNormalizedPerpendicular(), 0));
  103. Vec3 v = inFrom.Cross(inTo);
  104. return Quat(Vec4(v, w)).Normalized();
  105. }
  106. template <class Random>
  107. Quat Quat::sRandom(Random &inRandom)
  108. {
  109. uniform_real_distribution<float> zero_to_one(0.0f, 1.0f);
  110. float x0 = zero_to_one(inRandom);
  111. float r1 = sqrt(1.0f - x0), r2 = sqrt(x0);
  112. uniform_real_distribution<float> zero_to_two_pi(0.0f, 2.0f * JPH_PI);
  113. float t1 = zero_to_two_pi(inRandom), t2 = zero_to_two_pi(inRandom);
  114. return Quat(sin(t1) * r1, cos(t1) * r1, sin(t2) * r2, cos(t2) * r2);
  115. }
  116. Quat Quat::sEulerAngles(Vec3Arg inAngles)
  117. {
  118. Vec3 half = 0.5f * inAngles;
  119. float x = half.GetX();
  120. float y = half.GetY();
  121. float z = half.GetZ();
  122. float cx = cos(x);
  123. float sx = sin(x);
  124. float cy = cos(y);
  125. float sy = sin(y);
  126. float cz = cos(z);
  127. float sz = sin(z);
  128. return Quat(
  129. cz * sx * cy - sz * cx * sy,
  130. cz * cx * sy + sz * sx * cy,
  131. sz * cx * cy - cz * sx * sy,
  132. cz * cx * cy + sz * sx * sy);
  133. }
  134. Vec3 Quat::GetEulerAngles() const
  135. {
  136. float y_sq = GetY() * GetY();
  137. // X
  138. float t0 = 2.0f * (GetW() * GetX() + GetY() * GetZ());
  139. float t1 = 1.0f - 2.0f * (GetX() * GetX() + y_sq);
  140. // Y
  141. float t2 = 2.0f * (GetW() * GetY() - GetZ() * GetX());
  142. t2 = t2 > 1.0f? 1.0f : t2;
  143. t2 = t2 < -1.0f? -1.0f : t2;
  144. // Z
  145. float t3 = 2.0f * (GetW() * GetZ() + GetX() * GetY());
  146. float t4 = 1.0f - 2.0f * (y_sq + GetZ() * GetZ());
  147. return Vec3(atan2(t0, t1), asin(t2), atan2(t3, t4));
  148. }
  149. Quat Quat::GetTwist(Vec3Arg inAxis) const
  150. {
  151. Quat twist(Vec4(GetXYZ().Dot(inAxis) * inAxis, GetW()));
  152. float twist_len = twist.LengthSq();
  153. if (twist_len != 0.0f)
  154. return twist / sqrt(twist_len);
  155. else
  156. return Quat::sIdentity();
  157. }
  158. void Quat::GetSwingTwist(Quat &outSwing, Quat &outTwist) const
  159. {
  160. float x = GetX(), y = GetY(), z = GetZ(), w = GetW();
  161. float s = sqrt(Square(w) + Square(x));
  162. if (s != 0.0f)
  163. {
  164. outTwist = Quat(x / s, 0, 0, w / s);
  165. outSwing = Quat(0, (w * y - x * z) / s, (w * z + x * y) / s, s);
  166. }
  167. else
  168. {
  169. // If both x and w are zero, this must be a 180 degree rotation around either y or z
  170. outTwist = Quat::sIdentity();
  171. outSwing = *this;
  172. }
  173. }
  174. Quat Quat::LERP(QuatArg inDestination, float inFraction) const
  175. {
  176. float scale0 = 1.0f - inFraction;
  177. return Quat(Vec4::sReplicate(scale0) * mValue + Vec4::sReplicate(inFraction) * inDestination.mValue);
  178. }
  179. Quat Quat::SLERP(QuatArg inDestination, float inFraction) const
  180. {
  181. // Difference at which to LERP instead of SLERP
  182. const float delta = 0.0001f;
  183. // Calc cosine
  184. float sign_scale1 = 1.0f;
  185. float cos_omega = Dot(inDestination);
  186. // Adjust signs (if necessary)
  187. if (cos_omega < 0.0f)
  188. {
  189. cos_omega = -cos_omega;
  190. sign_scale1 = -1.0f;
  191. }
  192. // Calculate coefficients
  193. float scale0, scale1;
  194. if (1.0f - cos_omega > delta)
  195. {
  196. // Standard case (slerp)
  197. float omega = acos(cos_omega);
  198. float sin_omega = sin(omega);
  199. scale0 = sin((1.0f - inFraction) * omega) / sin_omega;
  200. scale1 = sign_scale1 * sin(inFraction * omega) / sin_omega;
  201. }
  202. else
  203. {
  204. // Quaternions are very close so we can do a linear interpolation
  205. scale0 = 1.0f - inFraction;
  206. scale1 = sign_scale1 * inFraction;
  207. }
  208. // Interpolate between the two quaternions
  209. return Quat(Vec4::sReplicate(scale0) * mValue + Vec4::sReplicate(scale1) * inDestination.mValue).Normalized();
  210. }
  211. Vec3 Quat::operator * (Vec3Arg inValue) const
  212. {
  213. // Rotating a vector by a quaternion is done by: p' = q * p * q^-1 (q^-1 = conjugated(q) for a unit quaternion)
  214. JPH_ASSERT(IsNormalized());
  215. return Vec3((*this * Quat(Vec4(inValue, 0)) * Conjugated()).mValue);
  216. }
  217. Vec3 Quat::InverseRotate(Vec3Arg inValue) const
  218. {
  219. JPH_ASSERT(IsNormalized());
  220. return Vec3((Conjugated() * Quat(Vec4(inValue, 0)) * *this).mValue);
  221. }
  222. Vec3 Quat::RotateAxisX() const
  223. {
  224. // This is *this * Vec3::sAxisX() written out:
  225. JPH_ASSERT(IsNormalized());
  226. float x = GetX(), y = GetY(), z = GetZ(), w = GetW();
  227. float tx = 2.0f * x, tw = 2.0f * w;
  228. return Vec3(tx * x + tw * w - 1.0f, tx * y + z * tw, tx * z - y * tw);
  229. }
  230. Vec3 Quat::RotateAxisY() const
  231. {
  232. // This is *this * Vec3::sAxisY() written out:
  233. JPH_ASSERT(IsNormalized());
  234. float x = GetX(), y = GetY(), z = GetZ(), w = GetW();
  235. float ty = 2.0f * y, tw = 2.0f * w;
  236. return Vec3(x * ty - z * tw, tw * w + ty * y - 1.0f, x * tw + ty * z);
  237. }
  238. Vec3 Quat::RotateAxisZ() const
  239. {
  240. // This is *this * Vec3::sAxisZ() written out:
  241. JPH_ASSERT(IsNormalized());
  242. float x = GetX(), y = GetY(), z = GetZ(), w = GetW();
  243. float tz = 2.0f * z, tw = 2.0f * w;
  244. return Vec3(x * tz + y * tw, y * tz - x * tw, tw * w + tz * z - 1.0f);
  245. }
  246. void Quat::StoreFloat3(Float3 *outV) const
  247. {
  248. JPH_ASSERT(IsNormalized());
  249. EnsureWPositive().GetXYZ().StoreFloat3(outV);
  250. }
  251. Quat Quat::sLoadFloat3Unsafe(const Float3 &inV)
  252. {
  253. Vec3 v = Vec3::sLoadFloat3Unsafe(inV);
  254. float w = sqrt(max(1.0f - v.LengthSq(), 0.0f)); // It is possible that the length of v is a fraction above 1, and we don't want to introduce NaN's in that case so we clamp to 0
  255. return Quat(Vec4(v, w));
  256. }
  257. } // JPH