12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- // Description : Common quaternion class
- #pragma once
- #include <AzCore/Math/Quaternion.h>
- //----------------------------------------------------------------------
- // Quaternion
- //----------------------------------------------------------------------
- template <typename F>
- struct Quat_tpl
- {
- Vec3_tpl<F> v;
- F w;
- //-------------------------------
- //constructors
- #if defined(_DEBUG)
- ILINE Quat_tpl()
- {
- if constexpr (sizeof(F) == 4)
- {
- uint32* p = alias_cast<uint32*>(&v.x);
- p[0] = F32NAN;
- p[1] = F32NAN;
- p[2] = F32NAN;
- p[3] = F32NAN;
- }
- if constexpr (sizeof(F) == 8)
- {
- uint64* p = alias_cast<uint64*>(&v.x);
- p[0] = F64NAN;
- p[1] = F64NAN;
- p[2] = F64NAN;
- p[3] = F64NAN;
- }
- }
- #else
- ILINE Quat_tpl() {}
- #endif
- //initialize with zeros
- ILINE Quat_tpl(type_zero)
- {
- w = 0, v.x = 0, v.y = 0, v.z = 0;
- }
- ILINE Quat_tpl(type_identity)
- {
- w = 1, v.x = 0, v.y = 0, v.z = 0;
- }
- //ASSIGNMENT OPERATOR of identical Quat types.
- //The assignment operator has precedence over assignment constructor
- //Quat q; q=q0;
- ILINE Quat_tpl<F>& operator = (const Quat_tpl<F>& src)
- {
- v.x = src.v.x;
- v.y = src.v.y;
- v.z = src.v.z;
- w = src.w;
- assert(IsValid());
- return *this;
- }
- //CONSTRUCTOR to initialize a Quat from 4 floats
- //Quat q(1,0,0,0);
- ILINE Quat_tpl<F>(F qw, F qx, F qy, F qz)
- {
- w = qw;
- v.x = qx;
- v.y = qy;
- v.z = qz;
- assert(IsValid());
- }
- //CONSTRUCTOR to initialize a Quat with a scalar and a vector
- //Quat q(1,Vec3(0,0,0));
- ILINE Quat_tpl<F>(F scalar, const Vec3_tpl<F> &vector)
- {
- v = vector;
- w = scalar;
- assert(IsValid());
- };
- //CONSTRUCTOR for identical types
- //Quat q=q0;
- ILINE Quat_tpl<F>(const Quat_tpl<F>&q)
- {
- w = q.w;
- v.x = q.v.x;
- v.y = q.v.y;
- v.z = q.v.z;
- assert(IsValid());
- }
- //CONSTRUCTOR for AZ::Quaternion
- explicit ILINE Quat_tpl<F>(const AZ::Quaternion& q)
- {
- w = q.GetW();
- v.x = q.GetX();
- v.y = q.GetY();
- v.z = q.GetZ();
- assert(IsValid());
- }
- //CONSTRUCTOR for identical types which converts between double/float
- //Quat q32=q64;
- //Quatr q64=q32;
- template <class F1>
- ILINE Quat_tpl<F>(const Quat_tpl<F1>&q)
- {
- assert(q.IsValid());
- w = F(q.w);
- v.x = F(q.v.x);
- v.y = F(q.v.y);
- v.z = F(q.v.z);
- }
- //CONSTRUCTOR for different types. It converts a Euler Angle into a Quat.
- //Needs to be 'explicit' because we loose fp-precision in the conversion process
- //Quat(Ang3(1,2,3));
- explicit ILINE Quat_tpl<F>(const Ang3_tpl<F>&ang)
- {
- assert(ang.IsValid());
- SetRotationXYZ(ang);
- }
- //CONSTRUCTOR for different types. It converts a Euler Angle into a Quat and converts between double/float. .
- //Needs to be 'explicit' because we loose fp-precision in the conversion process
- //Quat(Ang3r(1,2,3));
- template<class F1>
- explicit ILINE Quat_tpl<F>(const Ang3_tpl<F1>&ang)
- {
- assert(ang.IsValid());
- SetRotationXYZ(Ang3_tpl<F>(F(ang.x), F(ang.y), F(ang.z)));
- }
- //CONSTRUCTOR for different types. It converts a Matrix33 into a Quat.
- //Needs to be 'explicit' because we loose fp-precision in the conversion process
- //Quat(m33);
- explicit ILINE Quat_tpl<F>(const Matrix33_tpl<F>&m)
- {
- assert(m.IsOrthonormalRH(0.1f));
- F s, p, tr = m.m00 + m.m11 + m.m22;
- w = 1, v.x = 0, v.y = 0, v.z = 0;
- if (tr > 0)
- {
- s = sqrt_tpl(tr + 1.0f), p = 0.5f / s, w = s * 0.5f, v.x = (m.m21 - m.m12) * p, v.y = (m.m02 - m.m20) * p, v.z = (m.m10 - m.m01) * p;
- }
- else if ((m.m00 >= m.m11) && (m.m00 >= m.m22))
- {
- s = sqrt_tpl(m.m00 - m.m11 - m.m22 + 1.0f), p = 0.5f / s, w = (m.m21 - m.m12) * p, v.x = s * 0.5f, v.y = (m.m10 + m.m01) * p, v.z = (m.m20 + m.m02) * p;
- }
- else if ((m.m11 >= m.m00) && (m.m11 >= m.m22))
- {
- s = sqrt_tpl(m.m11 - m.m22 - m.m00 + 1.0f), p = 0.5f / s, w = (m.m02 - m.m20) * p, v.x = (m.m01 + m.m10) * p, v.y = s * 0.5f, v.z = (m.m21 + m.m12) * p;
- }
- else if ((m.m22 >= m.m00) && (m.m22 >= m.m11))
- {
- s = sqrt_tpl(m.m22 - m.m00 - m.m11 + 1.0f), p = 0.5f / s, w = (m.m10 - m.m01) * p, v.x = (m.m02 + m.m20) * p, v.y = (m.m12 + m.m21) * p, v.z = s * 0.5f;
- }
- }
- //CONSTRUCTOR for different types. It converts a Matrix33 into a Quat and converts between double/float.
- //Needs to be 'explicit' because we loose fp-precision the conversion process
- //Quat(m33r);
- //Quatr(m33);
- template<class F1>
- explicit ILINE Quat_tpl<F>(const Matrix33_tpl<F1>&m)
- {
- assert(m.IsOrthonormalRH(0.1f));
- F1 s, p, tr = m.m00 + m.m11 + m.m22;
- w = 1, v.x = 0, v.y = 0, v.z = 0;
- if (tr > 0)
- {
- s = sqrt_tpl(tr + 1.0f), p = 0.5f / s, w = F(s * 0.5), v.x = F((m.m21 - m.m12) * p), v.y = F((m.m02 - m.m20) * p), v.z = F((m.m10 - m.m01) * p);
- }
- else if ((m.m00 >= m.m11) && (m.m00 >= m.m22))
- {
- s = sqrt_tpl(m.m00 - m.m11 - m.m22 + 1.0f), p = 0.5f / s, w = F((m.m21 - m.m12) * p), v.x = F(s * 0.5), v.y = F((m.m10 + m.m01) * p), v.z = F((m.m20 + m.m02) * p);
- }
- else if ((m.m11 >= m.m00) && (m.m11 >= m.m22))
- {
- s = sqrt_tpl(m.m11 - m.m22 - m.m00 + 1.0f), p = 0.5f / s, w = F((m.m02 - m.m20) * p), v.x = F((m.m01 + m.m10) * p), v.y = F(s * 0.5), v.z = F((m.m21 + m.m12) * p);
- }
- else if ((m.m22 >= m.m00) && (m.m22 >= m.m11))
- {
- s = sqrt_tpl(m.m22 - m.m00 - m.m11 + 1.0f), p = 0.5f / s, w = F((m.m10 - m.m01) * p), v.x = F((m.m02 + m.m20) * p), v.y = F((m.m12 + m.m21) * p), v.z = F(s * 0.5);
- }
- }
- //CONSTRUCTOR for different types. It converts a Matrix34 into a Quat.
- //Needs to be 'explicit' because we loose fp-precision in the conversion process
- //Quat(m34);
- explicit ILINE Quat_tpl<F>(const Matrix34_tpl<F>&m)
- {
- *this = Quat_tpl<F>(Matrix33_tpl<F>(m));
- }
- //CONSTRUCTOR for different types. It converts a Matrix34 into a Quat and converts between double/float.
- //Needs to be 'explicit' because we loose fp-precision the conversion process
- //Quat(m34r);
- //Quatr(m34);
- template<class F1>
- explicit ILINE Quat_tpl<F>(const Matrix34_tpl<F1>&m)
- {
- *this = Quat_tpl<F>(Matrix33_tpl<F1>(m));
- }
- /*!
- * invert quaternion.
- *
- * Example 1:
- * Quat q=Quat::CreateRotationXYZ(Ang3(1,2,3));
- * Quat result = !q;
- * Quat result = GetInverted(q);
- * q.Invert();
- */
- ILINE Quat_tpl<F> operator ! () const { return Quat_tpl(w, -v); }
- ILINE void Invert(void) { *this = !*this; }
- ILINE Quat_tpl<F> GetInverted() const { return !(*this); }
- //flip quaternion. don't confuse this with quaternion-inversion.
- ILINE Quat_tpl<F> operator - () const { return Quat_tpl<F>(-w, -v); };
- //multiplication by a scalar
- void operator *= (F op) { w *= op; v *= op; }
- // Exact compare of 2 quats.
- ILINE bool operator==(const Quat_tpl<F>& q) const { return (v == q.v) && (w == q.w); }
- ILINE bool operator!=(const Quat_tpl<F>& q) const { return !(*this == q); }
- //A quaternion is a compressed matrix. Thus there is no problem extracting the rows & columns.
- ILINE Vec3_tpl<F> GetColumn(uint32 i)
- {
- if (i == 0)
- {
- return GetColumn0();
- }
- if (i == 1)
- {
- return GetColumn1();
- }
- if (i == 2)
- {
- return GetColumn2();
- }
- assert(0); //bad index
- return Vec3(ZERO);
- }
- ILINE Vec3_tpl<F> GetColumn0() const {return Vec3_tpl<F>(2 * (v.x * v.x + w * w) - 1, 2 * (v.y * v.x + v.z * w), 2 * (v.z * v.x - v.y * w)); }
- ILINE Vec3_tpl<F> GetColumn1() const {return Vec3_tpl<F>(2 * (v.x * v.y - v.z * w), 2 * (v.y * v.y + w * w) - 1, 2 * (v.z * v.y + v.x * w)); }
- ILINE Vec3_tpl<F> GetColumn2() const {return Vec3_tpl<F>(2 * (v.x * v.z + v.y * w), 2 * (v.y * v.z - v.x * w), 2 * (v.z * v.z + w * w) - 1); }
- ILINE Vec3_tpl<F> GetRow0() const {return Vec3_tpl<F>(2 * (v.x * v.x + w * w) - 1, 2 * (v.x * v.y - v.z * w), 2 * (v.x * v.z + v.y * w)); }
- ILINE Vec3_tpl<F> GetRow1() const {return Vec3_tpl<F>(2 * (v.y * v.x + v.z * w), 2 * (v.y * v.y + w * w) - 1, 2 * (v.y * v.z - v.x * w)); }
- ILINE Vec3_tpl<F> GetRow2() const {return Vec3_tpl<F>(2 * (v.z * v.x - v.y * w), 2 * (v.z * v.y + v.x * w), 2 * (v.z * v.z + w * w) - 1); }
- // These are just copy & pasted components of the GetColumn1() above.
- ILINE F GetFwdX() const { return (2 * (v.x * v.y - v.z * w)); }
- ILINE F GetFwdY() const { return (2 * (v.y * v.y + w * w) - 1); }
- ILINE F GetFwdZ() const { return (2 * (v.z * v.y + v.x * w)); }
- ILINE F GetRotZ() const { return atan2_tpl(-GetFwdX(), GetFwdY()); }
- /*!
- * set identity quaternion
- *
- * Example:
- * Quat q=Quat::CreateIdentity();
- * or
- * q.SetIdentity();
- * or
- * Quat p=Quat(IDENTITY);
- */
- ILINE void SetIdentity(void)
- {
- w = 1;
- v.x = 0;
- v.y = 0;
- v.z = 0;
- }
- ILINE static Quat_tpl<F> CreateIdentity(void)
- {
- return Quat_tpl<F>(1, 0, 0, 0);
- }
- // Description:
- // Check if identity quaternion.
- ILINE bool IsIdentity() const
- {
- return w == 1 && v.x == 0 && v.y == 0 && v.z == 0;
- }
- ILINE bool IsUnit(F e = VEC_EPSILON) const
- {
- return fabs_tpl(1 - (w * w + v.x * v.x + v.y * v.y + v.z * v.z)) < e;
- }
- ILINE bool IsValid([[maybe_unused]] F e = VEC_EPSILON) const
- {
- if (!v.IsValid())
- {
- return false;
- }
- if (!NumberValid(w))
- {
- return false;
- }
- //if (!IsUnit(e)) return false;
- return true;
- }
- ILINE void SetRotationAA(F rad, const Vec3_tpl<F>& axis)
- {
- F s, c;
- sincos_tpl(rad * (F)0.5, &s, &c);
- SetRotationAA(c, s, axis);
- }
- ILINE static Quat_tpl<F> CreateRotationAA(F rad, const Vec3_tpl<F>& axis)
- {
- Quat_tpl<F> q;
- q.SetRotationAA(rad, axis);
- return q;
- }
- ILINE void SetRotationAA(F cosha, F sinha, const Vec3_tpl<F>& axis)
- {
- assert(axis.IsUnit(0.001f));
- w = cosha;
- v = axis * sinha;
- }
- ILINE static Quat_tpl<F> CreateRotationAA(F cosha, F sinha, const Vec3_tpl<F>& axis)
- {
- Quat_tpl<F> q;
- q.SetRotationAA(cosha, sinha, axis);
- return q;
- }
- /*!
- * Create rotation-quaternion that around the fixed coordinate axes.
- *
- * Example:
- * Quat q=Quat::CreateRotationXYZ( Ang3(1,2,3) );
- * or
- * q.SetRotationXYZ( Ang3(1,2,3) );
- */
- ILINE void SetRotationXYZ(const Ang3_tpl<F>& a)
- {
- assert(a.IsValid());
- F sx, cx;
- sincos_tpl(F(a.x * F(0.5)), &sx, &cx);
- F sy, cy;
- sincos_tpl(F(a.y * F(0.5)), &sy, &cy);
- F sz, cz;
- sincos_tpl(F(a.z * F(0.5)), &sz, &cz);
- w = cx * cy * cz + sx * sy * sz;
- v.x = cz * cy * sx - sz * sy * cx;
- v.y = cz * sy * cx + sz * cy * sx;
- v.z = sz * cy * cx - cz * sy * sx;
- }
- ILINE static Quat_tpl<F> CreateRotationXYZ(const Ang3_tpl<F>& a)
- {
- assert(a.IsValid());
- Quat_tpl<F> q;
- q.SetRotationXYZ(a);
- return q;
- }
- // creatr rotation quatation base on ZYX axis
- ILINE void SetRotationZYX(const Ang3_tpl<F>& a)
- {
- assert(a.IsValid());
- F sx, cx;
- sincos_tpl(F(a.x * F(0.5)), &sx, &cx);
- F sy, cy;
- sincos_tpl(F(a.y * F(0.5)), &sy, &cy);
- F sz, cz;
- sincos_tpl(F(a.z * F(0.5)), &sz, &cz);
- w = cx * cy * cz - sx * sy * sz;
- v.x = cx * sy * sz + sx * cy * cz;
- v.y = cx * sy * cz - sx * cy * sz;
- v.z = cx * cy * sz + sx * sy * cz;
- }
- ILINE static Quat_tpl<F> CreateRotationZYX(const Ang3_tpl<F>& a)
- {
- assert(a.IsValid());
- Quat_tpl<F> q;
- q.SetRotationZYX(a);
- return q;
- }
- /*!
- * Create rotation-quaternion that about the x-axis.
- *
- * Example:
- * Quat q=Quat::CreateRotationX( radiant );
- * or
- * q.SetRotationX( Ang3(1,2,3) );
- */
- ILINE void SetRotationX(f32 r)
- {
- F s, c;
- sincos_tpl(F(r * F(0.5)), &s, &c);
- w = c;
- v.x = s;
- v.y = 0;
- v.z = 0;
- }
- ILINE static Quat_tpl<F> CreateRotationX(f32 r)
- {
- Quat_tpl<F> q;
- q.SetRotationX(r);
- return q;
- }
- /*!
- * Create rotation-quaternion that about the y-axis.
- *
- * Example:
- * Quat q=Quat::CreateRotationY( radiant );
- * or
- * q.SetRotationY( radiant );
- */
- ILINE void SetRotationY(f32 r)
- {
- F s, c;
- sincos_tpl(F(r * F(0.5)), &s, &c);
- w = c;
- v.x = 0;
- v.y = s;
- v.z = 0;
- }
- ILINE static Quat_tpl<F> CreateRotationY(f32 r)
- {
- Quat_tpl<F> q;
- q.SetRotationY(r);
- return q;
- }
- /*!
- * Create rotation-quaternion that about the z-axis.
- *
- * Example:
- * Quat q=Quat::CreateRotationZ( radiant );
- * or
- * q.SetRotationZ( radiant );
- */
- ILINE void SetRotationZ(f32 r)
- {
- F s, c;
- sincos_tpl(F(r * F(0.5)), &s, &c);
- w = c;
- v.x = 0;
- v.y = 0;
- v.z = s;
- }
- ILINE static Quat_tpl<F> CreateRotationZ(f32 r)
- {
- Quat_tpl<F> q;
- q.SetRotationZ(r);
- return q;
- }
- /*!
- *
- * Create rotation-quaternion that rotates from one vector to another.
- * Both vectors are assumed to be normalized.
- *
- * Example:
- * Quat q=Quat::CreateRotationV0V1( v0,v1 );
- * q.SetRotationV0V1( v0,v1 );
- */
- ILINE void SetRotationV0V1(const Vec3_tpl<F>& v0, const Vec3_tpl<F>& v1)
- {
- assert(v0.IsUnit(0.01f));
- assert(v1.IsUnit(0.01f));
- F dot = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + F(1.0);
- if (dot > F(0.0001))
- {
- F vx = v0.y * v1.z - v0.z * v1.y;
- F vy = v0.z * v1.x - v0.x * v1.z;
- F vz = v0.x * v1.y - v0.y * v1.x;
- F d = isqrt_tpl(dot * dot + vx * vx + vy * vy + vz * vz);
- w = F(dot * d);
- v.x = F(vx * d);
- v.y = F(vy * d);
- v.z = F(vz * d);
- return;
- }
- w = 0;
- v = v0.GetOrthogonal().GetNormalized();
- }
- ILINE static Quat_tpl<F> CreateRotationV0V1(const Vec3_tpl<F>& v0, const Vec3_tpl<F>& v1) { Quat_tpl<F> q; q.SetRotationV0V1(v0, v1); return q; }
- /*!
- *
- * \param vdir normalized view direction.
- * \param roll radiant to rotate about Y-axis.
- *
- * Given a view-direction and a radiant to rotate about Y-axis, this function builds a 3x3 look-at quaternion
- * using only simple vector arithmetic. This function is always using the implicit up-vector Vec3(0,0,1).
- * The view-direction is always stored in column(1).
- * IMPORTANT: The view-vector is assumed to be normalized, because all trig-values for the orientation are being
- * extracted directly out of the vector. This function must NOT be called with a view-direction
- * that is close to Vec3(0,0,1) or Vec3(0,0,-1). If one of these rules is broken, the function returns a quaternion
- * with an undefined rotation about the Z-axis.
- *
- * Rotation order for the look-at-quaternion is Z-X-Y. (Zaxis=YAW / Xaxis=PITCH / Yaxis=ROLL)
- *
- * COORDINATE-SYSTEM
- *
- * z-axis
- * ^
- * |
- * | y-axis
- * | /
- * | /
- * |/
- * +---------------> x-axis
- *
- * Example:
- * Quat LookAtQuat=Quat::CreateRotationVDir( Vec3(0,1,0) );
- * or
- * Quat LookAtQuat=Quat::CreateRotationVDir( Vec3(0,1,0), 0.333f );
- */
- ILINE void SetRotationVDir(const Vec3_tpl<F>& vdir)
- {
- assert(vdir.IsUnit(0.01f));
- //set default initialization for up-vector
- w = F(0.70710676908493042);
- v.x = F(vdir.z * 0.70710676908493042);
- v.y = F(0.0);
- v.z = F(0.0);
- F l = sqrt_tpl(vdir.x * vdir.x + vdir.y * vdir.y);
- if (l > F(0.00001))
- {
- //calculate LookAt quaternion
- Vec3_tpl<F> hv = Vec3_tpl<F> (vdir.x / l, vdir.y / l + 1.0f, l + 1.0f);
- F r = sqrt_tpl(hv.x * hv.x + hv.y * hv.y);
- F s = sqrt_tpl(hv.z * hv.z + vdir.z * vdir.z);
- //generate the half-angle sine&cosine
- F hacos0 = 0.0;
- F hasin0 = -1.0;
- if (r > F(0.00001))
- {
- hacos0 = hv.y / r;
- hasin0 = -hv.x / r;
- } //yaw
- F hacos1 = hv.z / s;
- F hasin1 = vdir.z / s; //pitch
- w = F(hacos0 * hacos1);
- v.x = F(hacos0 * hasin1);
- v.y = F(hasin0 * hasin1);
- v.z = F(hasin0 * hacos1);
- }
- }
- ILINE static Quat_tpl<F> CreateRotationVDir(const Vec3_tpl<F>& vdir) { Quat_tpl<F> q; q.SetRotationVDir(vdir); return q; }
- ILINE void SetRotationVDir(const Vec3_tpl<F>& vdir, F r)
- {
- SetRotationVDir(vdir);
- F sy, cy;
- sincos_tpl(r * (F)0.5, &sy, &cy);
- F vx = v.x, vy = v.y;
- v.x = F(vx * cy - v.z * sy);
- v.y = F(w * sy + vy * cy);
- v.z = F(v.z * cy + vx * sy);
- w = F(w * cy - vy * sy);
- }
- ILINE static Quat_tpl<F> CreateRotationVDir(const Vec3_tpl<F>& vdir, F roll) { Quat_tpl<F> q; q.SetRotationVDir(vdir, roll); return q; }
- /*!
- * normalize quaternion.
- *
- * Example 1:
- * Quat q; q.Normalize();
- *
- * Example 2:
- * Quat q=Quat(1,2,3,4);
- * Quat qn=q.GetNormalized();
- */
- ILINE void Normalize(void)
- {
- F d = isqrt_tpl(w * w + v.x * v.x + v.y * v.y + v.z * v.z);
- w *= d;
- v.x *= d;
- v.y *= d;
- v.z *= d;
- }
- ILINE Quat_tpl<F> GetNormalized() const
- {
- Quat_tpl<F> t = *this;
- t.Normalize();
- return t;
- }
- ILINE void NormalizeSafe(void)
- {
- F d = w * w + v.x * v.x + v.y * v.y + v.z * v.z;
- if (d > 1e-8f)
- {
- d = isqrt_tpl(d);
- w *= d;
- v.x *= d;
- v.y *= d;
- v.z *= d;
- }
- else
- {
- SetIdentity();
- }
- }
- ILINE Quat_tpl<F> GetNormalizedSafe() const
- {
- Quat_tpl<F> t = *this;
- t.NormalizeSafe();
- return t;
- }
- ILINE void NormalizeFast(void)
- {
- assert(this->IsValid());
- F fInvLen = isqrt_fast_tpl(v.x * v.x + v.y * v.y + v.z * v.z + w * w);
- v.x *= fInvLen;
- v.y *= fInvLen;
- v.z *= fInvLen;
- w *= fInvLen;
- }
- ILINE Quat_tpl<F> GetNormalizedFast() const
- {
- Quat_tpl<F> t = *this;
- t.NormalizeFast();
- return t;
- }
- /*!
- * get length of quaternion.
- *
- * Example 1:
- * f32 l=q.GetLength();
- */
- ILINE F GetLength() const
- {
- return sqrt_tpl(w * w + v.x * v.x + v.y * v.y + v.z * v.z);
- }
- ILINE static bool IsEquivalent(const Quat_tpl<F>& q1, const Quat_tpl<F>& q2, F qe = RAD_EPSILON)
- {
- Quat_tpl<f64> q1r = q1;
- Quat_tpl<f64> q2r = q2;
- f64 rad = acos(min(1.0, fabs_tpl(q1r.v.x * q2r.v.x + q1r.v.y * q2r.v.y + q1r.v.z * q2r.v.z + q1r.w * q2r.w)));
- bool qdif = rad <= qe;
- return qdif;
- }
- // Exponent of Quaternion.
- ILINE static Quat_tpl<F> exp(const Vec3_tpl<F>& v)
- {
- F lensqr = v.len2();
- if (lensqr > F(0))
- {
- F len = sqrt_tpl(lensqr);
- F s, c;
- sincos_tpl(len, &s, &c);
- s /= len;
- return Quat_tpl<F>(c, v.x * s, v.y * s, v.z * s);
- }
- return Quat_tpl<F> (IDENTITY);
- }
- // logarithm of a quaternion, imaginary part (the real part of the logarithm is always 0)
- ILINE static Vec3_tpl<F> log (const Quat_tpl<F>& q)
- {
- assert(q.IsValid());
- F lensqr = q.v.len2();
- if (lensqr > 0.0f)
- {
- F len = sqrt_tpl(lensqr);
- F angle = atan2_tpl(len, q.w) / len;
- return q.v * angle;
- }
- // logarithm of a quaternion, imaginary part (the real part of the logarithm is always 0)
- return Vec3_tpl<F>(0, 0, 0);
- }
- //////////////////////////////////////////////////////////////////////////
- //! Logarithm of Quaternion difference.
- ILINE static Quat_tpl<F> LnDif(const Quat_tpl<F>& q1, const Quat_tpl<F>& q2)
- {
- return Quat_tpl<F>(0, log(q2 / q1));
- }
- /*!
- * linear-interpolation between quaternions (lerp)
- *
- * Example:
- * CQuaternion result,p,q;
- * result=qlerp( p, q, 0.5f );
- */
- ILINE void SetNlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
- {
- Quat_tpl<F> q = tq;
- assert(p.IsValid());
- assert(q.IsValid());
- if ((p | q) < 0)
- {
- q = -q;
- }
- v.x = p.v.x * (1.0f - t) + q.v.x * t;
- v.y = p.v.y * (1.0f - t) + q.v.y * t;
- v.z = p.v.z * (1.0f - t) + q.v.z * t;
- w = p.w * (1.0f - t) + q.w * t;
- Normalize();
- }
- ILINE static Quat_tpl<F> CreateNlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
- {
- Quat_tpl<F> d;
- d.SetNlerp(p, tq, t);
- return d;
- }
- /*!
- * spherical-interpolation between quaternions (geometrical slerp)
- *
- * Example:
- * Quat result,p,q;
- * result.SetSlerp( p, q, 0.5f );
- */
- ILINE void SetSlerp(const Quat_tpl<F>& tp, const Quat_tpl<F>& tq, F t)
- {
- assert(tp.IsValid());
- assert(tq.IsUnit());
- Quat_tpl<F> p = tp, q = tq;
- Quat_tpl<F> q2;
- F cosine = (p | q);
- if (cosine < 0.0f)
- {
- cosine = -cosine;
- q = -q;
- } //take shortest arc
- if (cosine > 0.9999f)
- {
- SetNlerp(p, q, t);
- return;
- }
- // from now on, a division by 0 is not possible any more
- q2.w = q.w - p.w * cosine;
- q2.v.x = q.v.x - p.v.x * cosine;
- q2.v.y = q.v.y - p.v.y * cosine;
- q2.v.z = q.v.z - p.v.z * cosine;
- F sine = sqrt(q2 | q2);
- // Actually you can divide by 0 right here.
- assert(sine != 0.0000f);
- F s, c;
- sincos_tpl(atan2_tpl(sine, cosine) * t, &s, &c);
- w = F(p.w * c + q2.w * s / sine);
- v.x = F(p.v.x * c + q2.v.x * s / sine);
- v.y = F(p.v.y * c + q2.v.y * s / sine);
- v.z = F(p.v.z * c + q2.v.z * s / sine);
- }
- ILINE static Quat_tpl<F> CreateSlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
- {
- Quat_tpl<F> d;
- d.SetSlerp(p, tq, t);
- return d;
- }
- //! squad(p,a,b,q,t) = slerp( slerp(p,q,t),slerp(a,b,t), 2(1-t)t).
- ILINE void SetSquad(const Quat_tpl<F>& p, const Quat_tpl<F>& a, const Quat_tpl<F>& b, const Quat_tpl<F>& q, F t)
- {
- SetSlerp(CreateSlerp(p, q, t), CreateSlerp(a, b, t), 2.0f * (1.0f - t) * t);
- }
- ILINE static Quat_tpl<F> CreateSquad(const Quat_tpl<F>& p, const Quat_tpl<F>& a, const Quat_tpl<F>& b, const Quat_tpl<F>& q, F t)
- {
- Quat_tpl<F> d;
- d.SetSquad(p, a, b, q, t);
- return d;
- }
- //useless, please delete
- ILINE Quat_tpl<F> GetScaled(F scale) const
- {
- return CreateNlerp(IDENTITY, *this, scale);
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // Typedefs //
- ///////////////////////////////////////////////////////////////////////////////
- typedef Quat_tpl<f32> Quat; //always 32 bit
- /*!
- *
- * The "inner product" or "dot product" operation.
- *
- * calculate the "inner product" between two Quaternion.
- * If both Quaternion are unit-quaternions, the result is the cosine: p*q=cos(angle)
- *
- * Example:
- * Quat p(1,0,0,0),q(1,0,0,0);
- * f32 cosine = ( p | q );
- *
- */
- template<typename F1, typename F2>
- ILINE F1 operator | (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- assert(q.v.IsValid());
- assert(p.v.IsValid());
- return (q.v.x * p.v.x + q.v.y * p.v.y + q.v.z * p.v.z + q.w * p.w);
- }
- /*!
- *
- * Implements the multiplication operator: Qua=QuatA*QuatB
- *
- * AxB = operation B followed by operation A.
- * A multiplication takes 16 muls and 12 adds.
- *
- * Example 1:
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat result=p*q;
- *
- * Example 2: (self-multiplication)
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat p*=q;
- */
- template<class F1, class F2>
- Quat_tpl<F1> ILINE operator * (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- assert(q.IsValid());
- assert(p.IsValid());
- return Quat_tpl<F1>
- (
- q.w * p.w - (q.v.x * p.v.x + q.v.y * p.v.y + q.v.z * p.v.z),
- q.v.y * p.v.z - q.v.z * p.v.y + q.w * p.v.x + q.v.x * p.w,
- q.v.z * p.v.x - q.v.x * p.v.z + q.w * p.v.y + q.v.y * p.w,
- q.v.x * p.v.y - q.v.y * p.v.x + q.w * p.v.z + q.v.z * p.w
- );
- }
- template<class F1, class F2>
- ILINE void operator *= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- assert(q.IsValid());
- assert(p.IsValid());
- F1 s0 = q.w;
- q.w = q.w * p.w - (q.v | p.v);
- q.v = p.v * s0 + q.v * p.w + (q.v % p.v);
- }
- /*!
- * division operator
- *
- * Example 1:
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat result=p/q;
- *
- * Example 2: (self-division)
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat p/=q;
- */
- template<class F1, class F2>
- ILINE Quat_tpl<F1> operator / (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- return (!p * q);
- }
- template<class F1, class F2>
- ILINE void operator /= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- q = (!p * q);
- }
- /*!
- * addition operator
- *
- * Example:
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat result=p+q;
- *
- * Example:(self-addition operator)
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat p-=q;
- */
- template<class F1, class F2>
- ILINE Quat_tpl<F1> operator + (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- return Quat_tpl<F1>(q.w + p.w, q.v + p.v);
- }
- template<class F1, class F2>
- ILINE void operator += (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- q.w += p.w;
- q.v += p.v;
- }
- /*!
- * subtraction operator
- *
- * Example:
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat result=p-q;
- *
- * Example: (self-subtraction operator)
- * Quat p(1,0,0,0),q(1,0,0,0);
- * Quat p-=q;
- *
- */
- template<class F1, class F2>
- ILINE Quat_tpl<F1> operator - (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- return Quat_tpl<F1>(q.w - p.w, q.v - p.v);
- }
- template<class F1, class F2>
- ILINE void operator -= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
- {
- q.w -= p.w;
- q.v -= p.v;
- }
- //! Scale quaternion free function.
- template <typename F>
- ILINE Quat_tpl<F> operator * (F t, const Quat_tpl<F>& q)
- {
- return Quat_tpl<F>(t * q.w, t * q.v);
- };
- template <typename F1, typename F2>
- ILINE Quat_tpl<F1> operator * (const Quat_tpl<F1>& q, F2 t)
- {
- return Quat_tpl<F1>(q.w * t, q.v * t);
- };
- template <typename F1, typename F2>
- ILINE Quat_tpl<F1> operator / (const Quat_tpl<F1>& q, F2 t)
- {
- return Quat_tpl<F1>(q.w / t, q.v / t);
- };
- /*!
- *
- * post-multiply of a quaternion and a Vec3 (3D rotations with quaternions)
- *
- * Example:
- * Quat q(1,0,0,0);
- * Vec3 v(33,44,55);
- * Vec3 result = q*v;
- */
- template<class F, class F2>
- ILINE Vec3_tpl<F> operator * (const Quat_tpl<F>& q, const Vec3_tpl<F2>& v)
- {
- assert(v.IsValid());
- assert(q.IsValid());
- //muls=15 / adds=15
- Vec3_tpl<F> out, r2;
- r2.x = (q.v.y * v.z - q.v.z * v.y) + q.w * v.x;
- r2.y = (q.v.z * v.x - q.v.x * v.z) + q.w * v.y;
- r2.z = (q.v.x * v.y - q.v.y * v.x) + q.w * v.z;
- out.x = (r2.z * q.v.y - r2.y * q.v.z);
- out.x += out.x + v.x;
- out.y = (r2.x * q.v.z - r2.z * q.v.x);
- out.y += out.y + v.y;
- out.z = (r2.y * q.v.x - r2.x * q.v.y);
- out.z += out.z + v.z;
- return out;
- }
- /*!
- * pre-multiply of a quaternion and a Vec3 (3D rotations with quaternions)
- *
- * Example:
- * Quat q(1,0,0,0);
- * Vec3 v(33,44,55);
- * Vec3 result = v*q;
- */
- template<class F, class F2>
- ILINE Vec3_tpl<F2> operator * (const Vec3_tpl<F>& v, const Quat_tpl<F2>& q)
- {
- assert(v.IsValid());
- assert(q.IsValid());
- //muls=15 / adds=15
- Vec3_tpl<F> out, r2;
- r2.x = (q.v.z * v.y - q.v.y * v.z) + q.w * v.x;
- r2.y = (q.v.x * v.z - q.v.z * v.x) + q.w * v.y;
- r2.z = (q.v.y * v.x - q.v.x * v.y) + q.w * v.z;
- out.x = (r2.y * q.v.z - r2.z * q.v.y);
- out.x += out.x + v.x;
- out.y = (r2.z * q.v.x - r2.x * q.v.z);
- out.y += out.y + v.y;
- out.z = (r2.x * q.v.y - r2.y * q.v.x);
- out.z += out.z + v.z;
- return out;
- }
- template<class F1, class F2>
- ILINE Quat_tpl<F1> operator % (const Quat_tpl<F1>& q, const Quat_tpl<F2>& tp)
- {
- Quat_tpl<F1> p = tp;
- if ((p | q) < 0)
- {
- p = -p;
- }
- return Quat_tpl<F1>(q.w + p.w, q.v + p.v);
- }
- template<class F1, class F2>
- ILINE void operator %= (Quat_tpl<F1>& q, const Quat_tpl<F2>& tp)
- {
- Quat_tpl<F1> p = tp;
- if ((p | q) < 0)
- {
- p = -p;
- }
- q = Quat_tpl<F1>(q.w + p.w, q.v + p.v);
- }
|