Berserk
TQuat.hpp
Go to the documentation of this file.
1 /**********************************************************************************/
2 /* This file is part of Berserk Engine project */
3 /* https://github.com/EgorOrachyov/Berserk */
4 /**********************************************************************************/
5 /* MIT License */
6 /* */
7 /* Copyright (c) 2018 - 2021 Egor Orachyov */
8 /* */
9 /* Permission is hereby granted, free of charge, to any person obtaining a copy */
10 /* of this software and associated documentation files (the "Software"), to deal */
11 /* in the Software without restriction, including without limitation the rights */
12 /* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
13 /* copies of the Software, and to permit persons to whom the Software is */
14 /* furnished to do so, subject to the following conditions: */
15 /* */
16 /* The above copyright notice and this permission notice shall be included in all */
17 /* copies or substantial portions of the Software. */
18 /* */
19 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
20 /* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
21 /* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
22 /* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
23 /* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
24 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
25 /* SOFTWARE. */
26 /**********************************************************************************/
27 
28 #ifndef BERSERK_TQUAT_H
29 #define BERSERK_TQUAT_H
30 
31 #include <core/Config.hpp>
32 #include <core/Crc32.hpp>
33 #include <core/Typedefs.hpp>
34 #include <core/math/TMatMxN.hpp>
35 #include <core/math/TVecN.hpp>
36 
37 #include <ostream>
38 
40 
51 template<typename T>
52 class TQuat {
53 public:
54  using Vec = TVecN<T, 3>;
56 
57  TQuat() = default;
58 
59  TQuat(T s, const Vec &v) {
60  scalar = s;
61  vec = v;
62  }
63 
64  TQuat(T s, T x, T y, T z) {
65  scalar = s;
66  vec = {x, y, z};
67  }
68 
70  TQuat(const Vec &axis, T angle) {
71  scalar = MathUtils::Cos(angle * (T) 0.5);
72  vec = axis.Normalized() * MathUtils::Sin(angle * (T) 0.5);
73  }
74 
75  TQuat(T roll, T yaw, T pitch) {
76  *this = TQuat({1, 0, 0}, roll) *
77  TQuat({0, 1, 0}, yaw) *
78  TQuat({0, 0, 1}, pitch);
79  }
80 
81  explicit TQuat(const Mat &mat) {
82  T q[4];// notation: x[0] y[1] z[2] w[3]
83  auto &v = mat.values;
84 
85  T trace = v[0] + v[5] + v[10];
86 
87  // Matrix 4x4 indexes
88  // 0 1 2 3
89  // 4 5 6 7
90  // 8 9 10 11
91  // 12 13 14 15
92 
93  // Check the diagonal
94  if (trace > 0.0) {
95  // positive diagonal
96 
97  T s = MathUtils::Sqrt(trace + 1.0f);
98  q[3] = static_cast<T>(s * 0.5);
99 
100  T t = 0.5f / s;
101  q[0] = (v[9] - v[6]) * t;
102  q[1] = (v[2] - v[8]) * t;
103  q[2] = (v[4] - v[1]) * t;
104  } else {
105  // negative diagonal
106 
107  int32 i = 0;
108  if (v[5] > v[0]) i = 1;
109  if (v[10] > v[4 * i + i]) i = 2;
110 
111  static const int32 NEXT[3] = {1, 2, 0};
112  int32 j = NEXT[i];
113  int32 k = NEXT[j];
114 
115  auto s = (T) MathUtils::Sqrt(v[i * 4 + i] - (v[j * 4 + j] + v[k * 4 + k]) + 1.0);
116 
117  T t;
118  if (s == 0.0) t = s;
119  else
120  t = static_cast<T>(0.5 / s);
121 
122  q[i] = s * 0.5f;
123  q[3] = (v[k * 4 + j] - v[j * 4 + k]) * t;
124  q[j] = (v[j * 4 + i] - v[i * 4 + j]) * t;
125  q[k] = (v[k * 4 + i] - v[i * 4 + k]) * t;
126  }
127 
128  scalar = q[3];
129  vec = {q[0], q[1], q[2]};
130  }
131 
132  TQuat(const TQuat &other) = default;
133  TQuat(TQuat &&other) noexcept = default;
134  ~TQuat() = default;
135 
136  TQuat &operator=(const TQuat &other) = default;
137  TQuat &operator=(TQuat &&other) noexcept = default;
138 
139  void Identity() {
140  scalar = 1;
141  vec.Zero();
142  }
143 
144  void Zero() {
145  scalar = 0;
146  vec.Zero();
147  }
148 
149  TQuat operator*(const TQuat &other) const {
150  auto s = other.scalar;
151  auto v = other.vec;
152 
153  return TQuat(scalar * s - Vec::Dot(vec, v), v * scalar + vec * s + Vec::Cross(vec, v));
154  }
155 
157  scalar /= a;
158  vec /= a;
159  return *this;
160  }
161 
163  scalar /= a;
164  vec /= a;
165  return *this;
166  }
167 
168  T Length2() const {
169  return scalar * scalar + vec.Length2();
170  }
171 
172  T Length() const {
173  T l2 = Length2();
174  return MathUtils::Sqrt(l2);
175  }
176 
177  TQuat Normalized() const {
178  TQuat r = *this;
179  return r.Normalize();
180  }
181 
183  T len2 = Length2();
184 
186  Zero();
187  } else {
188  T len = MathUtils::Sqrt(len2);
189  *this /= len;
190  }
191 
192  return *this;
193  }
194 
195  TQuat Inverse() const {
196  T len2 = Length2();
197 
199  TQuat q;
200  q.Zero();
201  return q;
202  } else {
203  T len = MathUtils::Sqrt(len2);
204  return TQuat(scalar / len, -vec / len);
205  }
206  }
207 
208  TQuat Conjugate() const {
209  return TQuat(scalar, -vec);
210  }
211 
212  Vec Rotate(const Vec &v) const {
213  TQuat q(0, v);
214  TQuat r = *this * q * Conjugate();
215  return r.vec;
216  }
217 
218  Vec RotateReverse(const Vec &v) const {
219  TQuat q(0, v);
220  TQuat r = Conjugate() * q * *this;
221  return r.vec;
222  }
223 
224  Vec GetAxisX() const {
225  return Rotate({1, 0, 0});
226  }
227 
228  Vec GetAxisY() const {
229  return Rotate({0, 1, 0});
230  }
231 
232  Vec GetAxisZ() const {
233  return Rotate({0, 0, 1});
234  }
235 
236  T GetAngle() const {
237  return (T) 2 * MathUtils::Acos(scalar);
238  }
239 
240  Mat AsMatrix() const {
241  T x = vec[0];
242  T y = vec[1];
243  T z = vec[2];
244 
245  T xx = x * x;
246  T xy = x * y;
247  T xz = x * z;
248  T xw = x * scalar;
249 
250  T yy = y * y;
251  T yz = y * z;
252  T yw = y * scalar;
253 
254  T zz = z * z;
255  T zw = z * scalar;
256 
257  Mat r;
258  auto &v = r.values;
259 
260  v[0] = 1 - 2 * (yy + zz);
261  v[1] = 2 * (xy - zw);
262  v[2] = 2 * (xz + yw);
263  v[3] = 0;
264  v[4] = 2 * (xy + zw);
265  v[5] = 1 - 2 * (xx + zz);
266  v[6] = 2 * (yz - xw);
267  v[7] = 0;
268  v[8] = 2 * (xz - yw);
269  v[9] = 2 * (yz + xw);
270  v[10] = 1 - 2 * (xx + yy);
271  v[11] = 0;
272  v[12] = 0;
273  v[13] = 0;
274  v[14] = 0;
275  v[15] = 1;
276 
277  return r;
278  }
279 
280  void GetAxisAngle(Vec &axis, T &angle) const {
281  angle = (T) 2 * MathUtils::Acos(scalar);
282  T s = MathUtils::Max((T) (1.0 - scalar * scalar), (T) 0.0);
283 
285  axis = vec / MathUtils::Sqrt(s);
286  else
287  axis = vec({0, 1, 0});
288  }
289 
290  Crc32Hash Hash() const {
291  Crc32Builder builder;
292  builder.Hash(&vec, sizeof(vec));
293  builder.Hash(&scalar, sizeof(scalar));
294  return builder.GetHash();
295  }
296 
297  bool operator==(const TQuat &other) const {
298  return vec == other.vec && scalar == other.scalar;
299  }
300 
301  bool operator!=(const TQuat &other) const {
302  return vec != other.vec || scalar != other.scalar;
303  }
304 
306  static TQuat Rotation(const Vec &axis, T angle) {
307  return TQuat(axis, angle);
308  }
309 
310  static T Dot(const TQuat &a, const TQuat &b) {
311  return a.scalar * b.scalar + Vec::Dot(a.vec, b.vec);
312  }
313 
314  static T Angle(const TQuat &a, const TQuat &b) {
315  return MathUtils::Acos(Dot(a.Normalized(), b.Normalized()));
316  }
317 
318  static TQuat Lerp(T t, const TQuat &a, const TQuat &b) {
319  TQuat q;
320  q.scalar = MathUtils::Lerp(t, a.scalar, b.scalar);
321  q.vec = Vec::Lerp(t, a.vec, b.vec);
322  return q;
323  }
324 
325  static TQuat Slerp(T t, const TQuat &a, const TQuat &b) {
326  T ang = angle(a, b);
327 
328  if (ang <= MathUtils::THRESH_FLOAT32) {
329  return lerp(t, a, b);
330  }
331 
332  TQuat r;
333  T angleSin = MathUtils::Sin(ang);
334  T angle1 = MathUtils::Sin(ang * (1 - t)) / angleSin;
335  T angle2 = MathUtils::Sin(ang * t) / angleSin;
336 
337  r.scalar = a.scalar * angle1 + b.scalar * angle2;
338  r.vec = a.vec * angle1 + b.vec * angle2;
339 
340  return r;
341  }
342 
343  static TQuat Slerp(T t, T ang, const TQuat &a, const TQuat &b) {
344  if (ang <= MathUtils::THRESH_FLOAT32) {
345  return Lerp(t, a, b);
346  }
347 
348  TQuat r;
349  T angleSin = MathUtils::Sin(ang);
350  T angle1 = MathUtils::Sin(ang * (1 - t)) / angleSin;
351  T angle2 = MathUtils::Sin(ang * t) / angleSin;
352 
353  r.scalar = a.scalar * angle1 + b.scalar * angle2;
354  r.vec = a.vec * angle1 + b.vec * angle2;
355 
356  return r;
357  }
358 
373  static TQuat LookAt(const TVecN<T, 3> &direction, const TVecN<T, 3> &up) {
374  auto Z = (-direction).Normalized();
375  auto X = TVecN<T, 3>::Cross(up, Z).Normalized();
376  auto Y = TVecN<T, 3>::Cross(Z, X);
377 
379 
380  for (int i = 0; i < 3; i++) {
381  m.values[0 + i] = X[i];
382  m.values[4 + i] = Y[i];
383  m.values[8 + i] = Z[i];
384  }
385 
386  return TQuat(m);
387  }
388 
402  static TQuat FaceAt(const TVecN<T, 3> &direction, const TVecN<T, 3> &up) {
403  auto Z = direction.Normalized();
404  auto X = TVecN<T, 3>::Cross(up, Z).Normalized();
405  auto Y = TVecN<T, 3>::Cross(Z, X);
406 
408 
409  for (uint32 i = 0; i < 3; i++) {
410  m.values[0 + i] = X[i];
411  m.values[4 + i] = Y[i];
412  m.values[8 + i] = Z[i];
413  }
414 
415  return TQuat(m).Inverse();
416  }
417 
418 public:
419  T scalar = 1;
421 };
422 
424 
430 
431 namespace std {
432 
433  template<typename T>
434  struct hash<BRK_NS::TQuat<T>> {
435  public:
436  std::size_t operator()(const BRK_NS::TQuat<T> &quat) const {
437  return quat.Hash();
438  }
439  };
440 
441 }// namespace std
442 
443 template<typename T>
444 inline std::ostream &operator<<(std::ostream &ostream, const BRK_NS::TQuat<T> &quat) {
445  ostream << "(" << quat.scalar << "," << quat.vec[0] << "," << quat.vec[1] << "," << quat.vec[2] << ")";
446  return ostream;
447 }
448 
449 #endif//BERSERK_TQUAT_H
#define BRK_NS_END
Definition: Config.hpp:48
#define BRK_NS
Definition: Config.hpp:50
std::ostream & operator<<(std::ostream &ostream, const BRK_NS::TQuat< T > &quat)
Definition: TQuat.hpp:444
std::int32_t int32
Definition: Typedefs.hpp:43
std::size_t size_t
Definition: Typedefs.hpp:49
std::uint32_t uint32
Definition: Typedefs.hpp:44
Crc32 hash builder.
Definition: Crc32.hpp:68
Crc32Hash GetHash() const
Definition: Crc32.hpp:86
Crc32Builder & Hash(const void *buffer, size_t size)
Definition: Crc32.hpp:78
Crc32 hash value type.
static float Lerp(float t, float left, float right)
Definition: MathUtils.hpp:156
static float Sqrt(float a)
Definition: MathUtils.hpp:106
static float Acos(float a)
Definition: MathUtils.hpp:100
static float Cos(float a)
Definition: MathUtils.hpp:91
static BRK_API const float THRESH_FLOAT32
Definition: MathUtils.hpp:53
static BRK_API const float THRESH_ZERO_NORM_SQUARED
Definition: MathUtils.hpp:56
static float Max(float a, float b)
Definition: MathUtils.hpp:85
static float Sin(float a)
Definition: MathUtils.hpp:88
Generic matrix of M x N size for space of type T.
Definition: TMatMxN.hpp:56
T values[M *N]
Definition: TMatMxN.hpp:377
General quaternion math class.
Definition: TQuat.hpp:52
Vec RotateReverse(const Vec &v) const
Definition: TQuat.hpp:218
static TQuat Slerp(T t, const TQuat &a, const TQuat &b)
Definition: TQuat.hpp:325
static TQuat LookAt(const TVecN< T, 3 > &direction, const TVecN< T, 3 > &up)
Definition: TQuat.hpp:373
Mat AsMatrix() const
Definition: TQuat.hpp:240
void Zero()
Definition: TQuat.hpp:144
Crc32Hash Hash() const
Definition: TQuat.hpp:290
static T Dot(const TQuat &a, const TQuat &b)
Definition: TQuat.hpp:310
TQuat & operator=(const TQuat &other)=default
static TQuat Rotation(const Vec &axis, T angle)
Definition: TQuat.hpp:306
TQuat & Normalize()
Definition: TQuat.hpp:182
TQuat & operator*=(T a)
Definition: TQuat.hpp:156
TQuat & operator/=(T a)
Definition: TQuat.hpp:162
TQuat operator*(const TQuat &other) const
Definition: TQuat.hpp:149
TQuat(const TQuat &other)=default
static TQuat Lerp(T t, const TQuat &a, const TQuat &b)
Definition: TQuat.hpp:318
T GetAngle() const
Definition: TQuat.hpp:236
void Identity()
Definition: TQuat.hpp:139
static T Angle(const TQuat &a, const TQuat &b)
Definition: TQuat.hpp:314
Vec GetAxisZ() const
Definition: TQuat.hpp:232
bool operator!=(const TQuat &other) const
Definition: TQuat.hpp:301
Vec GetAxisX() const
Definition: TQuat.hpp:224
TQuat(T s, const Vec &v)
Definition: TQuat.hpp:59
TQuat(T s, T x, T y, T z)
Definition: TQuat.hpp:64
~TQuat()=default
TQuat(const Vec &axis, T angle)
Definition: TQuat.hpp:70
bool operator==(const TQuat &other) const
Definition: TQuat.hpp:297
TQuat(TQuat &&other) noexcept=default
Vec vec
Definition: TQuat.hpp:420
Vec Rotate(const Vec &v) const
Definition: TQuat.hpp:212
TQuat Conjugate() const
Definition: TQuat.hpp:208
T scalar
Definition: TQuat.hpp:419
Vec GetAxisY() const
Definition: TQuat.hpp:228
TQuat Inverse() const
Definition: TQuat.hpp:195
T Length2() const
Definition: TQuat.hpp:168
TQuat & operator=(TQuat &&other) noexcept=default
T Length() const
Definition: TQuat.hpp:172
TQuat Normalized() const
Definition: TQuat.hpp:177
TQuat(const Mat &mat)
Definition: TQuat.hpp:81
void GetAxisAngle(Vec &axis, T &angle) const
Definition: TQuat.hpp:280
TQuat()=default
static TQuat Slerp(T t, T ang, const TQuat &a, const TQuat &b)
Definition: TQuat.hpp:343
static TQuat FaceAt(const TVecN< T, 3 > &direction, const TVecN< T, 3 > &up)
Definition: TQuat.hpp:402
TQuat(T roll, T yaw, T pitch)
Definition: TQuat.hpp:75
T Length2() const
Definition: TVecN.hpp:505
TVecN & Zero()
Definition: TVecN.hpp:538
static TVecN Cross(const TVecN &a, const TVecN &b)
Definition: TVecN.hpp:375
TVecN Normalized() const
Definition: TVecN.hpp:520
static T Dot(const TVecN &a, const TVecN &b)
Definition: TVecN.hpp:354
static TVecN Lerp(float t, const TVecN &a, const TVecN &b)
Definition: TVecN.hpp:409
Definition: GLDevice.cpp:46
Definition: TQuat.hpp:431
std::size_t operator()(const BRK_NS::TQuat< T > &quat) const
Definition: TQuat.hpp:436