Exemple #1
0
        /// <summary>
        /// Performs spherical interpolation between two quaternions. Spherical interpolation neatly interpolates between
        /// two rotations without modifying the size of the vector it is applied to (unlike linear interpolation).
        /// </summary>
        /// <param name="from">Start quaternion.</param>
        /// <param name="to">End quaternion.</param>
        /// <param name="t">Interpolation factor in range [0, 1] that determines how much to interpolate between
        /// <paramref name="from"/> and <paramref name="to"/>.</param>
        /// <param name="shortestPath">Should the interpolation be performed between the shortest or longest path between
        ///                            the two quaternions.</param>
        /// <returns>Interpolated quaternion representing a rotation between <paramref name="from"/> and
        /// <paramref name="to"/>.</returns>
        public static Quaternion Slerp(Quaternion from, Quaternion to, float t, bool shortestPath = true)
        {
            float      dot = Dot(from, to);
            Quaternion quat;

            if (dot < 0.0f && shortestPath)
            {
                dot  = -dot;
                quat = -to;
            }
            else
            {
                quat = to;
            }

            if (MathEx.Abs(dot) < (1 - epsilon))
            {
                float  sin    = MathEx.Sqrt(1 - (dot * dot));
                Radian angle  = MathEx.Atan2(sin, dot);
                float  invSin = 1.0f / sin;
                float  a      = MathEx.Sin((1.0f - t) * angle) * invSin;
                float  b      = MathEx.Sin(t * angle) * invSin;

                return(a * from + b * quat);
            }
            else
            {
                Quaternion ret = (1.0f - t) * from + t * quat;

                ret.Normalize();
                return(ret);
            }
        }
Exemple #2
0
        /// <summary>
        /// Normalizes the quaternion.
        /// </summary>
        /// <returns>Length of the quaternion prior to normalization.</returns>
        public float Normalize()
        {
            float len    = w * w + x * x + y * y + z * z;
            float factor = 1.0f / (float)MathEx.Sqrt(len);

            x *= factor;
            y *= factor;
            z *= factor;
            w *= factor;
            return(len);
        }
Exemple #3
0
        /// <summary>
        /// Creates a quaternion from a rotation matrix.
        /// </summary>
        /// <param name="rotMatrix">Rotation matrix to convert to quaternion.</param>
        /// <returns>Newly created quaternion that has equivalent rotation as the provided rotation matrix.</returns>
        public static Quaternion FromRotationMatrix(Matrix3 rotMatrix)
        {
            // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
            // article "Quaternion Calculus and Fast Animation".

            Quaternion quat  = new Quaternion();
            float      trace = rotMatrix.m00 + rotMatrix.m11 + rotMatrix.m22;
            float      root;

            if (trace > 0.0f)
            {
                // |w| > 1/2, may as well choose w > 1/2
                root   = MathEx.Sqrt(trace + 1.0f); // 2w
                quat.w = 0.5f * root;
                root   = 0.5f / root;               // 1/(4w)
                quat.x = (rotMatrix.m21 - rotMatrix.m12) * root;
                quat.y = (rotMatrix.m02 - rotMatrix.m20) * root;
                quat.z = (rotMatrix.m10 - rotMatrix.m01) * root;
            }
            else
            {
                // |w| <= 1/2
                int[] nextLookup = { 1, 2, 0 };
                int   i          = 0;

                if (rotMatrix.m11 > rotMatrix.m00)
                {
                    i = 1;
                }

                if (rotMatrix.m22 > rotMatrix[i, i])
                {
                    i = 2;
                }

                int j = nextLookup[i];
                int k = nextLookup[j];

                root = MathEx.Sqrt(rotMatrix[i, i] - rotMatrix[j, j] - rotMatrix[k, k] + 1.0f);

                quat[i] = 0.5f * root;
                root    = 0.5f / root;

                quat.w  = (rotMatrix[k, j] - rotMatrix[j, k]) * root;
                quat[j] = (rotMatrix[j, i] + rotMatrix[i, j]) * root;
                quat[k] = (rotMatrix[k, i] + rotMatrix[i, k]) * root;
            }

            quat.Normalize();

            return(quat);
        }
Exemple #4
0
        /// <summary>
        /// Initializes the quaternion with rotation that rotates from one direction to another.
        /// </summary>
        /// <param name="fromDirection">Rotation to start at.</param>
        /// <param name="toDirection">Rotation to end at.</param>
        /// <param name="fallbackAxis">Fallback axis to use if the from/to vectors are almost completely opposite.
        ///                            Fallback axis should be perpendicular to both vectors.</param>
        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
        {
            fromDirection.Normalize();
            toDirection.Normalize();

            float d = Vector3.Dot(fromDirection, toDirection);

            // If dot == 1, vectors are the same
            if (d >= 1.0f)
            {
                this = Identity;
                return;
            }

            if (d < (1e-6f - 1.0f))
            {
                if (fallbackAxis != Vector3.Zero)
                {
                    // Rotate 180 degrees about the fallback axis
                    this = FromAxisAngle(fallbackAxis, MathEx.Pi);
                }
                else
                {
                    // Generate an axis
                    Vector3 axis = Vector3.Cross(Vector3.XAxis, fromDirection);
                    if (axis.SqrdLength < ((1e-06f * 1e-06f))) // Pick another if collinear
                    {
                        axis = Vector3.Cross(Vector3.YAxis, fromDirection);
                    }
                    axis.Normalize();
                    this = FromAxisAngle(axis, MathEx.Pi);
                }
            }
            else
            {
                float s    = MathEx.Sqrt((1 + d) * 2);
                float invs = 1 / s;

                Vector3 c = Vector3.Cross(fromDirection, toDirection);

                x = c.x * invs;
                y = c.y * invs;
                z = c.z * invs;
                w = s * 0.5f;
                Normalize();
            }
        }
Exemple #5
0
        /// <summary>
        /// Calculates the distance between two points.
        /// </summary>
        /// <param name="a">First three dimensional point.</param>
        /// <param name="b">Second three dimensional point.</param>
        /// <returns>Distance between the two points.</returns>
        public static float Distance(Vector3 a, Vector3 b)
        {
            Vector3 vector3 = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);

            return(MathEx.Sqrt(vector3.x * vector3.x + vector3.y * vector3.y + vector3.z * vector3.z));
        }
Exemple #6
0
 /// <summary>
 /// Calculates the magnitude of the provided vector.
 /// </summary>
 /// <param name="v">Vector to calculate the magnitude for.</param>
 /// <returns>Magnitude of the vector.</returns>
 public static float Magnitude(Vector3 v)
 {
     return(MathEx.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
 }
Exemple #7
0
        /// <summary>
        /// Converts an orthonormal matrix to axis angle representation.
        /// </summary>
        /// <param name="axis">Axis around which the rotation is performed.</param>
        /// <param name="angle">Amount of rotation.</param>
        public void ToAxisAngle(out Vector3 axis, out Degree angle)
        {
            float  trace   = m00 + m11 + m22;
            float  cos     = 0.5f * (trace - 1.0f);
            Radian radians = (Radian)MathEx.Acos(cos);  // In [0, PI]

            angle = radians;

            if (radians > (Radian)0.0f)
            {
                if (radians < MathEx.Pi)
                {
                    axis.x = m21 - m12;
                    axis.y = m02 - m20;
                    axis.z = m10 - m01;

                    axis.Normalize();
                }
                else
                {
                    // Angle is PI
                    float halfInverse;
                    if (m00 >= m11)
                    {
                        // r00 >= r11
                        if (m00 >= m22)
                        {
                            // r00 is maximum diagonal term
                            axis.x      = 0.5f * MathEx.Sqrt(m00 - m11 - m22 + 1.0f);
                            halfInverse = 0.5f / axis.x;
                            axis.y      = halfInverse * m01;
                            axis.z      = halfInverse * m02;
                        }
                        else
                        {
                            // r22 is maximum diagonal term
                            axis.z      = 0.5f * MathEx.Sqrt(m22 - m00 - m11 + 1.0f);
                            halfInverse = 0.5f / axis.z;
                            axis.x      = halfInverse * m02;
                            axis.y      = halfInverse * m12;
                        }
                    }
                    else
                    {
                        // r11 > r00
                        if (m11 >= m22)
                        {
                            // r11 is maximum diagonal term
                            axis.y      = 0.5f * MathEx.Sqrt(m11 - m00 - m22 + 1.0f);
                            halfInverse = 0.5f / axis.y;
                            axis.x      = halfInverse * m01;
                            axis.z      = halfInverse * m12;
                        }
                        else
                        {
                            // r22 is maximum diagonal term
                            axis.z      = 0.5f * MathEx.Sqrt(m22 - m00 - m11 + 1.0f);
                            halfInverse = 0.5f / axis.z;
                            axis.x      = halfInverse * m02;
                            axis.y      = halfInverse * m12;
                        }
                    }
                }
            }
            else
            {
                // The angle is 0 and the matrix is the identity.  Any axis will
                // work, so just use the x-axis.
                axis.x = 1.0f;
                axis.y = 0.0f;
                axis.z = 0.0f;
            }
        }
Exemple #8
0
        /// <summary>
        /// Calculates the distance between two points.
        /// </summary>
        /// <param name="a">First four dimensional point.</param>
        /// <param name="b">Second four dimensional point.</param>
        /// <returns>Distance between the two points.</returns>
        public static float Distance(Vector4 a, Vector4 b)
        {
            Vector4 vector4 = new Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);

            return(MathEx.Sqrt(vector4.x * vector4.x + vector4.y * vector4.y + vector4.z * vector4.z + vector4.w * vector4.w));
        }
Exemple #9
0
        /// <summary>
        /// Calculates the distance between two points.
        /// </summary>
        /// <param name="a">First two dimensional point.</param>
        /// <param name="b">Second two dimensional point.</param>
        /// <returns>Distance between the two points.</returns>
        public static float Distance(Vector2 a, Vector2 b)
        {
            Vector2 vector2 = new Vector2(a.x - b.x, a.y - b.y);

            return(MathEx.Sqrt(vector2.x * vector2.x + vector2.y * vector2.y));
        }