Path: blob/master/thirdparty/embree/common/math/quaternion.h
9912 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "vec3.h"6#include "vec4.h"78#include "transcendental.h"910namespace embree11{12////////////////////////////////////////////////////////////////13// Quaternion Struct14////////////////////////////////////////////////////////////////1516template<typename T>17struct QuaternionT18{19typedef Vec3<T> Vector;2021////////////////////////////////////////////////////////////////////////////////22/// Construction23////////////////////////////////////////////////////////////////////////////////2425__forceinline QuaternionT () { }26__forceinline QuaternionT ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; }27__forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; }2829__forceinline QuaternionT( const T& r ) : r(r), i(zero), j(zero), k(zero) {}30__forceinline explicit QuaternionT( const Vec3<T>& v ) : r(zero), i(v.x), j(v.y), k(v.z) {}31__forceinline explicit QuaternionT( const Vec4<T>& v ) : r(v.x), i(v.y), j(v.z), k(v.w) {}32__forceinline QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {}33__forceinline QuaternionT( const T& r, const Vec3<T>& v ) : r(r), i(v.x), j(v.y), k(v.z) {}3435__inline QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz );36__inline QuaternionT( const T& yaw, const T& pitch, const T& roll );3738////////////////////////////////////////////////////////////////////////////////39/// Constants40////////////////////////////////////////////////////////////////////////////////4142__forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {}43__forceinline QuaternionT( OneTy ) : r( one), i(zero), j(zero), k(zero) {}4445/*! return quaternion for rotation around arbitrary axis */46static __forceinline QuaternionT rotate(const Vec3<T>& u, const T& r) {47return QuaternionT<T>(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u));48}4950/*! returns the rotation axis of the quaternion as a vector */51__forceinline Vec3<T> v( ) const { return Vec3<T>(i, j, k); }5253public:54T r, i, j, k;55};5657template<typename T> __forceinline QuaternionT<T> operator *( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a * b.r, a * b.i, a * b.j, a * b.k); }58template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r * b, a.i * b, a.j * b, a.k * b); }5960////////////////////////////////////////////////////////////////61// Unary Operators62////////////////////////////////////////////////////////////////6364template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a ) { return QuaternionT<T>(+a.r, +a.i, +a.j, +a.k); }65template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a ) { return QuaternionT<T>(-a.r, -a.i, -a.j, -a.k); }66template<typename T> __forceinline QuaternionT<T> conj ( const QuaternionT<T>& a ) { return QuaternionT<T>(a.r, -a.i, -a.j, -a.k); }67template<typename T> __forceinline T abs ( const QuaternionT<T>& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }68template<typename T> __forceinline QuaternionT<T> rcp ( const QuaternionT<T>& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }69template<typename T> __forceinline QuaternionT<T> normalize ( const QuaternionT<T>& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }7071// evaluates a*q-r72template<typename T> __forceinline QuaternionT<T>73msub(const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)74{75return QuaternionT<T>(msub(a, q.r, p.r),76msub(a, q.i, p.i),77msub(a, q.j, p.j),78msub(a, q.k, p.k));79}80// evaluates a*q-r81template<typename T> __forceinline QuaternionT<T>82madd (const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)83{84return QuaternionT<T>(madd(a, q.r, p.r),85madd(a, q.i, p.i),86madd(a, q.j, p.j),87madd(a, q.k, p.k));88}8990////////////////////////////////////////////////////////////////91// Binary Operators92////////////////////////////////////////////////////////////////9394template<typename T> __forceinline QuaternionT<T> operator +( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a + b.r, b.i, b.j, b.k); }95template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r + b, a.i, a.j, a.k); }96template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); }97template<typename T> __forceinline QuaternionT<T> operator -( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a - b.r, -b.i, -b.j, -b.k); }98template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r - b, a.i, a.j, a.k); }99template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); }100101template<typename T> __forceinline Vec3<T> operator *( const QuaternionT<T>& a, const Vec3<T> & b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }102template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const QuaternionT<T>& b ) {103return QuaternionT<T>(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k,104a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j,105a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i,106a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r);107}108template<typename T> __forceinline QuaternionT<T> operator /( const T & a, const QuaternionT<T>& b ) { return a*rcp(b); }109template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const T & b ) { return a*rcp(b); }110template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a*rcp(b); }111112template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const T & b ) { return a = a+b; }113template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a+b; }114template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const T & b ) { return a = a-b; }115template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a-b; }116template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const T & b ) { return a = a*b; }117template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*b; }118template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const T & b ) { return a = a*rcp(b); }119template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*rcp(b); }120121template<typename T, typename M> __forceinline QuaternionT<T>122select(const M& m, const QuaternionT<T>& q, const QuaternionT<T>& p)123{124return QuaternionT<T>(select(m, q.r, p.r),125select(m, q.i, p.i),126select(m, q.j, p.j),127select(m, q.k, p.k));128}129130131template<typename T> __forceinline Vec3<T> xfmPoint ( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }132template<typename T> __forceinline Vec3<T> xfmVector( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }133template<typename T> __forceinline Vec3<T> xfmNormal( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }134135template<typename T> __forceinline T dot(const QuaternionT<T>& a, const QuaternionT<T>& b) { return a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k; }136137////////////////////////////////////////////////////////////////////////////////138/// Comparison Operators139////////////////////////////////////////////////////////////////////////////////140141template<typename T> __forceinline bool operator ==( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r == b.r && a.i == b.i && a.j == b.j && a.k == b.k; }142template<typename T> __forceinline bool operator !=( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r != b.r || a.i != b.i || a.j != b.j || a.k != b.k; }143144145////////////////////////////////////////////////////////////////////////////////146/// Orientation Functions147////////////////////////////////////////////////////////////////////////////////148149template<typename T> QuaternionT<T>::QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz )150{151if ( vx.x + vy.y + vz.z >= T(zero) )152{153const T t = T(one) + (vx.x + vy.y + vz.z);154const T s = rsqrt(t)*T(0.5f);155r = t*s;156i = (vy.z - vz.y)*s;157j = (vz.x - vx.z)*s;158k = (vx.y - vy.x)*s;159}160else if ( vx.x >= max(vy.y, vz.z) )161{162const T t = (T(one) + vx.x) - (vy.y + vz.z);163const T s = rsqrt(t)*T(0.5f);164r = (vy.z - vz.y)*s;165i = t*s;166j = (vx.y + vy.x)*s;167k = (vz.x + vx.z)*s;168}169else if ( vy.y >= vz.z ) // if ( vy.y >= max(vz.z, vx.x) )170{171const T t = (T(one) + vy.y) - (vz.z + vx.x);172const T s = rsqrt(t)*T(0.5f);173r = (vz.x - vx.z)*s;174i = (vx.y + vy.x)*s;175j = t*s;176k = (vy.z + vz.y)*s;177}178else //if ( vz.z >= max(vy.y, vx.x) )179{180const T t = (T(one) + vz.z) - (vx.x + vy.y);181const T s = rsqrt(t)*T(0.5f);182r = (vx.y - vy.x)*s;183i = (vz.x + vx.z)*s;184j = (vy.z + vz.y)*s;185k = t*s;186}187}188189template<typename T> QuaternionT<T>::QuaternionT( const T& yaw, const T& pitch, const T& roll )190{191const T cya = cos(yaw *T(0.5f));192const T cpi = cos(pitch*T(0.5f));193const T cro = cos(roll *T(0.5f));194const T sya = sin(yaw *T(0.5f));195const T spi = sin(pitch*T(0.5f));196const T sro = sin(roll *T(0.5f));197r = cro*cya*cpi + sro*sya*spi;198i = cro*cya*spi + sro*sya*cpi;199j = cro*sya*cpi - sro*cya*spi;200k = sro*cya*cpi - cro*sya*spi;201}202203//////////////////////////////////////////////////////////////////////////////204/// Output Operators205//////////////////////////////////////////////////////////////////////////////206207template<typename T> static embree_ostream operator<<(embree_ostream cout, const QuaternionT<T>& q) {208return cout << "{ r = " << q.r << ", i = " << q.i << ", j = " << q.j << ", k = " << q.k << " }";209}210211/*! default template instantiations */212typedef QuaternionT<float> Quaternion3f;213typedef QuaternionT<double> Quaternion3d;214215template<int N> using Quaternion3vf = QuaternionT<vfloat<N>>;216typedef QuaternionT<vfloat<4>> Quaternion3vf4;217typedef QuaternionT<vfloat<8>> Quaternion3vf8;218typedef QuaternionT<vfloat<16>> Quaternion3vf16;219220//////////////////////////////////////////////////////////////////////////////221/// Interpolation222//////////////////////////////////////////////////////////////////////////////223template<typename T>224__forceinline QuaternionT<T>lerp(const QuaternionT<T>& q0,225const QuaternionT<T>& q1,226const T& factor)227{228QuaternionT<T> q;229q.r = lerp(q0.r, q1.r, factor);230q.i = lerp(q0.i, q1.i, factor);231q.j = lerp(q0.j, q1.j, factor);232q.k = lerp(q0.k, q1.k, factor);233return q;234}235236template<typename T>237__forceinline QuaternionT<T> slerp(const QuaternionT<T>& q0,238const QuaternionT<T>& q1_,239const T& t)240{241T cosTheta = dot(q0, q1_);242QuaternionT<T> q1 = select(cosTheta < 0.f, -q1_, q1_);243cosTheta = select(cosTheta < 0.f, -cosTheta, cosTheta);244245// spherical linear interpolation246const T phi = t * fastapprox::acos(cosTheta);247T sinPhi, cosPhi;248fastapprox::sincos(phi, sinPhi, cosPhi);249QuaternionT<T> qperp = sinPhi * normalize(msub(cosTheta, q0, q1));250QuaternionT<T> qslerp = msub(cosPhi, q0, qperp);251252// regular linear interpolation as fallback253QuaternionT<T> qlerp = normalize(lerp(q0, q1, t));254255return select(cosTheta > 0.9995f, qlerp, qslerp);256}257}258259260