File size: 5,522 Bytes
7b853a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#pragma once

#include "Vector.h"

namespace Math
{
    class alignas(16) Quaternion
    {
    public:

        static Quaternion const Identity;

        // Calculate the rotation required to align the source vector to the target vector (shortest path)
        static Quaternion FromRotationBetweenNormalizedVectors(const Vector& sourceVector, const Vector& targetVector);

        // Calculate the rotation required to align one vector onto another but also taking account a fallback rotation axis for opposite parallel vectors
        static Quaternion FromRotationBetweenNormalizedVectors(const Vector& sourceVector, const Vector& targetVector, const Vector& fallbackRotationAxis);

        // Calculate the rotation required to align the source vector to the target vector (shortest path)
        static Quaternion FromRotationBetweenVectors(const Vector& sourceVector, const Vector& targetVector);

        // Normalized LERP - not accurate - only use for really short distances
        static Quaternion NLerp(const Quaternion& from, const Quaternion& to, float t);

        // Standard and accurate Spherical LERP - based on DirectX Math
        static Quaternion SLerp(const Quaternion& from, const Quaternion& to, float t);

        // Fast approximation of a Spherical LERP - based on "A fast and accurate estimate for SLERP" by David Eberly
        static Quaternion FastSLerp(const Quaternion& from, const Quaternion& to, float t);

        // Spherical quadrangle/cubic interpolation for quaternions
        static Quaternion SQuad(const Quaternion& q0, const Quaternion& q1, const Quaternion& q2, const Quaternion& q3, float t);

        // Calculate the shortest delta quaternion needed to rotate 'from' onto 'to'
        static Quaternion Delta(const Quaternion& from, const Quaternion& to);

        // Simple vector dot product between two quaternions
        static Vector Dot(const Quaternion& q0, const Quaternion& q1);

        // Calculate the angular distance between two quaternions
        static Radians Distance(const Quaternion& q0, const Quaternion& q1);

        // Calculate look rotation given forward and up vectors
        static Quaternion LookRotation(const Vector& forward, const Vector& up);

    public:

        Quaternion() = default;
        explicit Quaternion(NoInit_t);
        explicit Quaternion(IdentityInit_t);
        explicit Quaternion(const Vector& v);
        explicit Quaternion(float ix, float iy, float iz, float iw);
        explicit Quaternion(const Float4& v);

        explicit Quaternion(const Vector& axis, Radians angle);
        explicit Quaternion(AxisAngle axisAngle);

        explicit Quaternion(const EulerAngles& eulerAngles);
        explicit Quaternion(Radians rotX, Radians rotY, Radians rotZ);

        operator __m128& ();
        operator const __m128& () const;

        Float4 ToFloat4() const;
        Vector ToVector() const;

        Vector Length();
        float GetLength() const;

        // Get the angle this rotation represents around the specified axis
        Radians GetAngle() const;

        AxisAngle ToAxisAngle() const;
        EulerAngles ToEulerAngles() const;

        Vector RotateVector(const Vector& vector) const;
        Vector RotateVectorInverse(const Vector& vector) const;

        Quaternion& Conjugate();
        Quaternion GetConjugate() const;

        Quaternion& Negate();
        Quaternion GetNegated() const;

        Quaternion& Invert();
        Quaternion GetInverse() const;

        Quaternion& Normalize();
        Quaternion GetNormalized() const;

        Vector XAxis() const noexcept;
        Vector YAxis() const noexcept;
        Vector ZAxis() const noexcept;

        // Ensure that this rotation is the shortest in terms of the angle (i.e. -5 instead of 355)
        Quaternion& MakeShortestPath();

        // Ensure that this rotation is the shortest in terms of the angle (i.e. -5 instead of 355)
        Quaternion GetShortestPath() const;

        // This function will return the estimated normalized quaternion, this is not super accurate but a lot faster (use with care)
        Quaternion& NormalizeInaccurate();

        // This function will return the estimated normalized quaternion, this is not super accurate but a lot faster (use with care)
        Quaternion GetNormalizedInaccurate() const;

        bool IsNormalized() const;
        bool IsIdentity() const;

        // Concatenate the rotation of this onto rhs and return the result i.e. first rotate by rhs then by this
        // This means order of rotation is right-to-left: child-rotation * parent-rotation
        Quaternion operator*(const Quaternion& rhs) const;
        Quaternion& operator*=(const Quaternion& rhs);

        // Is the distance between this quaternion and another one under the threshold?
        bool IsNearEqual(const Quaternion& rhs, Radians const threshold = Math::DegreesToRadians) const;

        // Exact equality
        bool operator==(const Quaternion& rhs) const;

        // Exact equality
        bool operator!=(const Quaternion& rhs) const;

    private:

        Vector GetSplatW() const;
        float GetW() const;

        Quaternion& operator=(const Vector& v) = delete;

    public:

        __m128 m_data;
    };

    static_assert(sizeof(Vector) == 16, "Quaternion size must be 16 bytes!");
}

#include "Quaternion.inl"