28#ifndef OZZ_OZZ_BASE_MATHS_QUATERNION_H_
29#define OZZ_OZZ_BASE_MATHS_QUATERNION_H_
33#include "ozz/base/maths/math_constant.h"
34#include "ozz/base/maths/math_ex.h"
35#include "ozz/base/maths/vec_float.h"
36#include "ozz/base/platform.h"
48 OZZ_INLINE
Quaternion(
float _x,
float _y,
float _z,
float _w)
49 : x(_x), y(_y), z(_z), w(_w) {}
55 static OZZ_INLINE
Quaternion FromAxisAngle(
const Float3& _axis,
float _angle);
67 static OZZ_INLINE
Quaternion FromEuler(
float _yaw,
float _pitch,
89 return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z && _a.w == _b.w;
93OZZ_INLINE
bool operator!=(
const Quaternion& _a,
const Quaternion& _b) {
94 return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z || _a.w != _b.w;
99OZZ_INLINE Quaternion Conjugate(
const Quaternion& _q) {
100 return Quaternion(-_q.x, -_q.y, -_q.z, _q.w);
104OZZ_INLINE Quaternion operator+(
const Quaternion& _a,
const Quaternion& _b) {
105 return Quaternion(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z, _a.w + _b.w);
109OZZ_INLINE Quaternion operator*(
const Quaternion& _q,
float _f) {
110 return Quaternion(_q.x * _f, _q.y * _f, _q.z * _f, _q.w * _f);
115OZZ_INLINE Quaternion operator*(
const Quaternion& _a,
const Quaternion& _b) {
116 return Quaternion(_a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y,
117 _a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z,
118 _a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x,
119 _a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z);
123OZZ_INLINE Quaternion operator-(
const Quaternion& _q) {
124 return Quaternion(-_q.x, -_q.y, -_q.z, -_q.w);
128OZZ_INLINE
bool Compare(
const math::Quaternion& _a,
const math::Quaternion& _b,
129 float _cos_half_tolerance) {
131 const float cos_half_angle =
132 _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
133 return std::abs(cos_half_angle) >= _cos_half_tolerance;
137OZZ_INLINE
bool IsNormalized(
const Quaternion& _q) {
138 const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
139 return std::abs(sq_len - 1.f) < kNormalizationToleranceSq;
143OZZ_INLINE Quaternion Normalize(
const Quaternion& _q) {
144 const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
145 assert(sq_len != 0.f &&
"_q is not normalizable");
146 const float inv_len = 1.f / std::sqrt(sq_len);
147 return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
153OZZ_INLINE Quaternion NormalizeSafe(
const Quaternion& _q,
154 const Quaternion& _safer) {
155 assert(IsNormalized(_safer) &&
"_safer is not normalized");
156 const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
160 const float inv_len = 1.f / std::sqrt(sq_len);
161 return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
165OZZ_INLINE Quaternion Quaternion::FromAxisAngle(
const Float3& _axis,
167 assert(IsNormalized(_axis) &&
"axis is not normalized.");
168 const float half_angle = _angle * .5f;
169 const float half_sin = std::sin(half_angle);
170 const float half_cos = std::cos(half_angle);
171 return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
175OZZ_INLINE Quaternion Quaternion::FromAxisCosAngle(
const Float3& _axis,
177 assert(IsNormalized(_axis) &&
"axis is not normalized.");
178 assert(_cos >= -1.f && _cos <= 1.f &&
"cos is not in [-1,1] range.");
180 const float half_cos2 = (1.f + _cos) * 0.5f;
181 const float half_sin = std::sqrt(1.f - half_cos2);
182 return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
183 std::sqrt(half_cos2));
188OZZ_INLINE Float4 ToAxisAngle(
const Quaternion& _q) {
189 assert(IsNormalized(_q));
190 const float clamped_w = Clamp(-1.f, _q.w, 1.f);
191 const float angle = 2.f * std::acos(clamped_w);
192 const float s = std::sqrt(1.f - clamped_w * clamped_w);
197 return Float4(1.f, 0.f, 0.f, angle);
200 const float inv_s = 1.f / s;
201 return Float4(_q.x * inv_s, _q.y * inv_s, _q.z * inv_s, angle);
205OZZ_INLINE Quaternion Quaternion::FromEuler(
float _yaw,
float _pitch,
207 const float half_yaw = _yaw * .5f;
208 const float c1 = std::cos(half_yaw);
209 const float s1 = std::sin(half_yaw);
210 const float half_pitch = _pitch * .5f;
211 const float c2 = std::cos(half_pitch);
212 const float s2 = std::sin(half_pitch);
213 const float half_roll = _roll * .5f;
214 const float c3 = std::cos(half_roll);
215 const float s3 = std::sin(half_roll);
216 const float c1c2 = c1 * c2;
217 const float s1s2 = s1 * s2;
218 return Quaternion(c1c2 * s3 + s1s2 * c3, s1 * c2 * c3 + c1 * s2 * s3,
219 c1 * s2 * c3 - s1 * c2 * s3, c1c2 * c3 - s1s2 * s3);
224OZZ_INLINE Float3 ToEuler(
const Quaternion& _q) {
225 const float sqw = _q.w * _q.w;
226 const float sqx = _q.x * _q.x;
227 const float sqy = _q.y * _q.y;
228 const float sqz = _q.z * _q.z;
230 const float unit = sqx + sqy + sqz + sqw;
231 const float test = _q.x * _q.y + _q.z * _q.w;
233 if (test > .499f * unit) {
234 euler.x = 2.f * std::atan2(_q.x, _q.w);
235 euler.y = ozz::math::kPi_2;
237 }
else if (test < -.499f * unit) {
238 euler.x = -2 * std::atan2(_q.x, _q.w);
242 euler.x = std::atan2(2.f * _q.y * _q.w - 2.f * _q.x * _q.z,
243 sqx - sqy - sqz + sqw);
244 euler.y = std::asin(2.f * test / unit);
245 euler.z = std::atan2(2.f * _q.x * _q.w - 2.f * _q.y * _q.z,
246 -sqx + sqy - sqz + sqw);
251OZZ_INLINE Quaternion Quaternion::FromVectors(
const Float3& _from,
255 const float norm_from_norm_to = std::sqrt(LengthSqr(_from) * LengthSqr(_to));
256 if (norm_from_norm_to < 1.e-5f) {
257 return Quaternion::identity();
259 const float real_part = norm_from_norm_to + Dot(_from, _to);
261 if (real_part < 1.e-6f * norm_from_norm_to) {
265 quat = std::abs(_from.x) > std::abs(_from.z)
266 ? Quaternion(-_from.y, _from.x, 0.f, 0.f)
267 : Quaternion(0.f, -_from.z, _from.y, 0.f);
269 const Float3
cross = Cross(_from, _to);
272 return Normalize(quat);
275OZZ_INLINE Quaternion Quaternion::FromUnitVectors(
const Float3& _from,
277 assert(IsNormalized(_from) && IsNormalized(_to) &&
278 "Input vectors must be normalized.");
281 const float real_part = 1.f + Dot(_from, _to);
282 if (real_part < 1.e-6f) {
286 return std::abs(_from.x) > std::abs(_from.z)
287 ? Quaternion(-_from.y, _from.x, 0.f, 0.f)
288 : Quaternion(0.f, -_from.z, _from.y, 0.f);
290 const Float3
cross = Cross(_from, _to);
296OZZ_INLINE
float Dot(
const Quaternion& _a,
const Quaternion& _b) {
297 return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
302OZZ_INLINE Quaternion Lerp(
const Quaternion& _a,
const Quaternion& _b,
304 return Quaternion((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
305 (_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
310OZZ_INLINE Quaternion NLerp(
const Quaternion& _a,
const Quaternion& _b,
312 const Float4
lerp((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
313 (_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
316 const float inv_len = 1.f / std::sqrt(sq_len);
317 return Quaternion(
lerp.x * inv_len,
lerp.y * inv_len,
lerp.z * inv_len,
323OZZ_INLINE Quaternion SLerp(
const Quaternion& _a,
const Quaternion& _b,
325 assert(IsNormalized(_a));
326 assert(IsNormalized(_b));
328 float cos_half_theta = _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
331 if (std::abs(cos_half_theta) >= .999f) {
336 const float half_theta = std::acos(cos_half_theta);
337 const float sin_half_theta = std::sqrt(1.f - cos_half_theta * cos_half_theta);
341 if (sin_half_theta < .001f) {
342 return Quaternion((_a.x + _b.x) * .5f, (_a.y + _b.y) * .5f,
343 (_a.z + _b.z) * .5f, (_a.w + _b.w) * .5f);
346 const float ratio_a = std::sin((1.f - _f) * half_theta) / sin_half_theta;
347 const float ratio_b = std::sin(_f * half_theta) / sin_half_theta;
351 ratio_a * _a.x + ratio_b * _b.x, ratio_a * _a.y + ratio_b * _b.y,
352 ratio_a * _a.z + ratio_b * _b.z, ratio_a * _a.w + ratio_b * _b.w);
358OZZ_INLINE Float3 TransformVector(
const Quaternion& _q,
const Float3& _v) {
361 const Float3 a(_q.y * _v.z - _q.z * _v.y + _v.x * _q.w,
362 _q.z * _v.x - _q.x * _v.z + _v.y * _q.w,
363 _q.x * _v.y - _q.y * _v.x + _v.z * _q.w);
364 const Float3 b(_q.y * a.z - _q.z * a.y, _q.z * a.x - _q.x * a.z,
365 _q.x * a.y - _q.y * a.x);
366 return Float3(_v.x + b.x + b.x, _v.y + b.y + b.y, _v.z + b.z + b.z);
GLM_FUNC_QUALIFIER vec< 3, T, Q > cross(vec< 3, T, Q > const &x, vec< 3, T, Q > const &y)
Definition func_geometric.inl:175
GLM_FUNC_DECL qua< T, Q > lerp(qua< T, Q > const &x, qua< T, Q > const &y, T a)
Definition quaternion_common.inl:29
qua< float, defaultp > quat
Quaternion of single-precision floating-point numbers.
Definition quaternion_float.hpp:35
GLM_FUNC_DECL T angle(qua< T, Q > const &x)
Definition quaternion_trigonometric.inl:6
GLM_FUNC_DECL GLM_CONSTEXPR genType euler()
Definition constants.inl:108
Definition vec_float.h:67
Definition quaternion.h:41