28#ifndef OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
29#define OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
31#include "ozz/base/maths/simd_math.h"
93 Swizzle<3, 3, 3, 2>(_a.xyzw) * Swizzle<0, 1, 2, 2>(_b.xyzw);
95 Swizzle<0, 1, 2, 0>(_a.xyzw) * Swizzle<3, 3, 3, 0>(_b.xyzw);
97 MAdd(Swizzle<1, 2, 0, 1>(_a.xyzw), Swizzle<2, 0, 1, 1>(_b.xyzw), p1);
99 NMAdd(Swizzle<2, 0, 1, 3>(_a.xyzw), Swizzle<1, 2, 0, 3>(_b.xyzw), p2);
100 const SimdQuaternion quat = {Xor(p13 + p24, simd_int4::mask_sign_w())};
106OZZ_INLINE SimdQuaternion Conjugate(
const SimdQuaternion& _q) {
107 const SimdQuaternion quat = {Xor(_q.xyzw, simd_int4::mask_sign_xyz())};
112OZZ_INLINE SimdQuaternion operator-(
const SimdQuaternion& _q) {
113 const SimdQuaternion
quat = {Xor(_q.xyzw, simd_int4::mask_sign())};
118OZZ_INLINE SimdQuaternion Normalize(
const SimdQuaternion& _q) {
119 const SimdQuaternion
quat = {Normalize4(_q.xyzw)};
125OZZ_INLINE SimdQuaternion NormalizeSafe(
const SimdQuaternion& _q,
126 const SimdQuaternion& _safer) {
127 const SimdQuaternion
quat = {NormalizeSafe4(_q.xyzw, _safer.xyzw)};
132OZZ_INLINE SimdQuaternion NormalizeEst(
const SimdQuaternion& _q) {
133 const SimdQuaternion
quat = {NormalizeEst4(_q.xyzw)};
139OZZ_INLINE SimdQuaternion NormalizeSafeEst(
const SimdQuaternion& _q,
140 const SimdQuaternion& _safer) {
141 const SimdQuaternion
quat = {NormalizeSafeEst4(_q.xyzw, _safer.xyzw)};
148OZZ_INLINE SimdInt4 IsNormalized(
const SimdQuaternion& _q) {
149 return IsNormalized4(_q.xyzw);
157OZZ_INLINE SimdInt4 IsNormalizedEst(
const SimdQuaternion& _q) {
158 return IsNormalizedEst4(_q.xyzw);
161OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisAngle(_SimdFloat4 _axis,
162 _SimdFloat4 _angle) {
163 assert(AreAllTrue1(IsNormalizedEst3(_axis)) &&
"axis is not normalized.");
164 const SimdFloat4 half_angle = _angle * simd_float4::Load1(.5f);
165 const SimdFloat4 half_sin = SinX(half_angle);
166 const SimdFloat4 half_cos = CosX(half_angle);
167 const SimdQuaternion
quat = {SetW(_axis * SplatX(half_sin), half_cos)};
171OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisCosAngle(_SimdFloat4 _axis,
173 const SimdFloat4 one = simd_float4::one();
174 const SimdFloat4 half = simd_float4::Load1(.5f);
176 assert(AreAllTrue1(IsNormalizedEst3(_axis)) &&
"axis is not normalized.");
177 assert(AreAllTrue1(And(CmpGe(_cos, -one), CmpLe(_cos, one))) &&
178 "cos is not in [-1,1] range.");
180 const SimdFloat4 half_cos2 = (one + _cos) * half;
181 const SimdFloat4 half_sin2 = one - half_cos2;
182 const SimdFloat4 half_sincos2 = SetY(half_cos2, half_sin2);
183 const SimdFloat4 half_sincos = Sqrt(half_sincos2);
184 const SimdFloat4 half_sin = SplatY(half_sincos);
185 const SimdQuaternion
quat = {SetW(_axis * half_sin, half_sincos)};
191OZZ_INLINE SimdFloat4 ToAxisAngle(
const SimdQuaternion& _q) {
192 assert(AreAllTrue1(IsNormalizedEst4(_q.xyzw)) &&
"_q is not normalized.");
193 const SimdFloat4 x_axis = simd_float4::x_axis();
194 const SimdFloat4 clamped_w = Clamp(-x_axis, SplatW(_q.xyzw), x_axis);
195 const SimdFloat4 half_angle = ACosX(clamped_w);
198 const SimdFloat4 s = SplatX(SqrtX(NMAdd(clamped_w, clamped_w, x_axis)));
200 const SimdInt4 low = CmpLt(s, simd_float4::Load1(1e-3f));
201 return Select(low, x_axis,
202 SetW(_q.xyzw * RcpEstNR(s), half_angle + half_angle));
205OZZ_INLINE SimdQuaternion SimdQuaternion::FromVectors(_SimdFloat4 _from,
208 const SimdFloat4 norm_from_norm_to =
209 SqrtX(Length3Sqr(_from) * Length3Sqr(_to));
210 const float norm_from_norm_to_x = GetX(norm_from_norm_to);
211 if (norm_from_norm_to_x < 1.e-6f) {
212 return SimdQuaternion::identity();
215 const SimdFloat4 real_part = norm_from_norm_to + Dot3(_from, _to);
217 if (GetX(real_part) < 1.e-6f * norm_from_norm_to_x) {
222 ozz::math::StorePtrU(_from, from);
223 quat.xyzw = std::abs(from[0]) > std::abs(from[2])
224 ? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
225 : ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f);
228 quat.xyzw = SetW(Cross3(_from, _to), real_part);
230 return Normalize(quat);
233OZZ_INLINE SimdQuaternion SimdQuaternion::FromUnitVectors(_SimdFloat4 _from,
236 assert(ozz::math::AreAllTrue1(
237 And(IsNormalizedEst3(_from), IsNormalizedEst3(_to))) &&
238 "Input vectors must be normalized.");
240 const SimdFloat4 real_part =
241 ozz::math::simd_float4::x_axis() + Dot3(_from, _to);
242 if (GetX(real_part) < 1.e-6f) {
247 ozz::math::StorePtrU(_from, from);
248 SimdQuaternion
quat = {
249 std::abs(from[0]) > std::abs(from[2])
250 ? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
251 : ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f)};
255 SimdQuaternion
quat = {SetW(Cross3(_from, _to), real_part)};
256 return Normalize(quat);
264OZZ_INLINE SimdFloat4 TransformVector(
const SimdQuaternion& _q,
268 const SimdFloat4 cross1 = MAdd(SplatW(_q.xyzw), _v, Cross3(_q.xyzw, _v));
269 const SimdFloat4 cross2 = Cross3(_q.xyzw, cross1);
270 return _v + cross2 + cross2;
qua< float, defaultp > quat
Quaternion of single-precision floating-point numbers.
Definition quaternion_float.hpp:35
Definition simd_math_config.h:121
Definition simd_quaternion.h:39