123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- #include <cmath>
- #include "client/math/Quaternion.h"
- Quaternion::Quaternion() : xyz(0.0f, 0.0f, 0.0f), w(1.0f) {
- }
- Quaternion::Quaternion(float x, float y, float z, float w) : xyz(x, y, z), w(w) {
- }
- Quaternion::Quaternion(const Vector3& axis, float angle) : xyz(axis) {
- xyz.normalize();
- float sin;
- sincosf(angle * (M_PI / 360.0f), &sin, &w);
- xyz *= sin;
- }
- Quaternion Quaternion::lerp(float f, const Quaternion& other) const {
- return interpolate(1 - f, f, other).normalize();
- }
- Quaternion Quaternion::slerp(float f, const Quaternion& other) const {
- float angle = xyz.dot(other.xyz) + w * other.w;
- if(angle >= 1.0f) {
- return *this;
- } else if(angle < -1.0f) {
- angle = -1.0f;
- }
- float arccos = acosf(angle);
- float sin = 1.0f / sinf(arccos);
- return interpolate(sinf((1 - f) * arccos) * sin, sinf(f * arccos) * sin, other);
- }
- Quaternion Quaternion::interpolate(float a, float b, const Quaternion& other) const {
- Vector3 interpolated = xyz * a + other.xyz * b;
- return Quaternion(interpolated[0], interpolated[1], interpolated[2], w * a + other.w * b);
- }
- Quaternion Quaternion::squad(float f, const Quaternion& prev, const Quaternion& next, const Quaternion& nextNext) const {
- float diff = static_cast<Vector3>(xyz - next.xyz).squareLength() + (w - next.w) * (w - next.w);
- if(diff < 0.0001f) {
- return *this;
- }
- Quaternion s1 = squadControl(prev, next);
- Quaternion s2 = next.squadControl(*this, nextNext);
- return slerp(f, next).slerp(2.0f * f * (1.0f - f), s1.slerp(f, s2));
- }
- Quaternion Quaternion::squadControl(const Quaternion& prev, const Quaternion& next) const {
- Quaternion conjugate(*this);
- conjugate.conjugate();
- Quaternion s1(next);
- s1.mul(conjugate).log().add(Quaternion(prev).mul(conjugate).log()).mul(-0.25f).exp().mul(*this);
- return s1;
- }
- Quaternion& Quaternion::normalize() {
- float f = 1.0f / sqrtf(xyz.squareLength() + w * w);
- xyz *= f;
- w *= f;
- return *this;
- }
- Matrix Quaternion::toMatrix() const {
- float x = xyz[0];
- float y = xyz[1];
- float z = xyz[2];
- float x2 = 2 * x * x;
- float y2 = 2 * y * y;
- float z2 = 2 * z * z;
- float xy = 2 * x * y;
- float xz = 2 * x * z;
- float xw = 2 * x * w;
- float zw = 2 * z * w;
- float yz = 2 * y * z;
- float yw = 2 * y * w;
- Matrix m;
- m.set(0, 1 - y2 - z2).set(1, xy - zw).set(2, xz + yw);
- m.set(4, xy + zw).set(5, 1 - x2 - z2).set(6, yz - xw);
- m.set(8, xz - yw).set(9, yz + xw).set(10, 1 - x2 - y2);
- return m;
- }
- Quaternion& Quaternion::mul(const Quaternion& other) {
- Vector3 v = other.xyz * w + xyz * other.w + xyz.cross(other.xyz);
- w = w * other.w - xyz.dot(other.xyz);
- xyz = v;
- return *this;
- }
- Quaternion& Quaternion::mul(float f) {
- xyz *= f;
- w *= f;
- return *this;
- }
- Quaternion& Quaternion::add(const Quaternion& other) {
- xyz += other.xyz;
- w += other.w;
- return *this;
- }
- Quaternion& Quaternion::conjugate() {
- xyz = -xyz;
- return *this;
- }
- Quaternion& Quaternion::log() {
- // general log
- //float length = sqrtf(xyz.dot(xyz) + w * w);
- //float arccos = acos(w / length);
- //w = logf(length);
- //xyz.mul(arccos / xyz.length());
- // optimized use case log
- xyz.normalize();
- xyz *= acos(w);
- w = 0.0f;
- return *this;
- }
- Quaternion& Quaternion::exp() {
- // general exp
- //float expw = expf(w);
- //float length = xyz.length();
- //w = expw * cosf(length);
- //xyz.mul((expw * sin(length)) / length);
- // optimized use case exp
- float length = xyz.length();
- w = cosf(length);
- xyz *= sinf(length) / length;
- return *this;
- }
|