Procházet zdrojové kódy

Added C# quaternion and refactored C++ quaternions a bit

Marko Pintera před 12 roky
rodič
revize
d778ed5b15

+ 2 - 2
CamelotCore/Source/CmSceneObject.cpp

@@ -128,7 +128,7 @@ namespace CamelotFramework
 		// TODO - I'm ignoring "up" direction
 		setForward(forward);
 
-		Quaternion upRot = getUp().getRotationTo(up);
+		Quaternion upRot = Quaternion::getRotationFromTo(getUp(), up);
 		setRotation(getRotation() * upRot);
 	}
 
@@ -217,7 +217,7 @@ namespace CamelotFramework
 		else
 		{
 			// Derive shortest arc to new direction
-			Quaternion rotQuat = currentForwardDir.getRotationTo(nrmForwardDir);
+			Quaternion rotQuat = Quaternion::getRotationFromTo(currentForwardDir, nrmForwardDir);
 			targetRotation = rotQuat * currentRotation;
 		}
 

+ 8 - 11
CamelotUtility/Include/CmQuaternion.h

@@ -37,6 +37,7 @@ THE SOFTWARE.
 
 #include "CmPrerequisitesUtil.h"
 #include "CmMath.h"
+#include "CmVector3.h"
 
 namespace CamelotFramework 
 {
@@ -122,16 +123,6 @@ namespace CamelotFramework
 			return *(&w+i);
 		}
 
-		inline float* ptr()
-		{
-			return &w;
-		}
-
-		inline const float* ptr() const
-		{
-			return &w;
-		}
-
 		void fromRotationMatrix(const Matrix3& mat);
         void fromAxisAngle(const Vector3& axis, const Radian& angle);
         void fromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis);
@@ -263,12 +254,18 @@ namespace CamelotFramework
         static Quaternion slerp(float t, const Quaternion& p,
             const Quaternion& q, bool shortestPath = false);
 
+        /**
+		 * @brief	Gets the shortest arc quaternion to rotate this vector to the destination
+		 *		vector.
+         */
+        static Quaternion getRotationFromTo(const Vector3& from, const Vector3& dest, const Vector3& fallbackAxis = Vector3::ZERO);
+
         static const float EPSILON;
 
         static const Quaternion ZERO;
         static const Quaternion IDENTITY;
 
-		float w, x, y, z;
+		float x, y, z, w;
 
 		private:
 			static const EulerAngleOrderData EA_LOOKUP[6];

+ 0 - 55
CamelotUtility/Include/CmVector3.h

@@ -29,7 +29,6 @@ THE SOFTWARE.
 
 #include "CmPrerequisitesUtil.h"
 #include "CmMath.h"
-#include "CmQuaternion.h"
 
 namespace CamelotFramework
 {
@@ -384,60 +383,6 @@ namespace CamelotFramework
 
 		}
 
-        /**
-		 * @brief	Gets the shortest arc quaternion to rotate this vector to the destination
-		 *		vector.
-         */
-        Quaternion getRotationTo(const Vector3& dest, const Vector3& fallbackAxis = Vector3::ZERO) const
-        {
-            // Based on Stan Melax's article in Game Programming Gems
-            Quaternion q;
-
-            Vector3 v0 = *this;
-            Vector3 v1 = dest;
-            v0.normalize();
-            v1.normalize();
-
-            float d = v0.dot(v1);
-
-            // If dot == 1, vectors are the same
-            if (d >= 1.0f)
-                return Quaternion::IDENTITY;
-
-			if (d < (1e-6f - 1.0f))
-			{
-				if (fallbackAxis != Vector3::ZERO)
-				{
-					// Rotate 180 degrees about the fallback axis
-					q.fromAxisAngle(fallbackAxis, Radian(Math::PI));
-				}
-				else
-				{
-					// Generate an axis
-					Vector3 axis = Vector3::UNIT_X.cross(*this);
-					if (axis.isZeroLength()) // Pick another if colinear
-						axis = Vector3::UNIT_Y.cross(*this);
-					axis.normalize();
-					q.fromAxisAngle(axis, Radian(Math::PI));
-				}
-			}
-			else
-			{
-                float s = Math::sqrt( (1+d)*2 );
-	            float invs = 1 / s;
-
-				Vector3 c = v0.cross(v1);
-
-    	        q.x = c.x * invs;
-        	    q.y = c.y * invs;
-            	q.z = c.z * invs;
-            	q.w = s * 0.5f;
-				q.normalize();
-			}
-
-            return q;
-        }
-
         /**
          * @brief	Returns true if this vector is zero length.
          */

+ 1 - 1
CamelotUtility/Source/CmMatrix3.cpp

@@ -26,7 +26,7 @@ THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
 #include "CmMatrix3.h"
-
+#include "CmQuaternion.h"
 #include "CmMath.h"
 
 // Adapted from Matrix math by Wild Magic http://www.geometrictools.com/

+ 1 - 0
CamelotUtility/Source/CmMatrix4.cpp

@@ -29,6 +29,7 @@ THE SOFTWARE.
 
 #include "CmVector3.h"
 #include "CmMatrix3.h"
+#include "CmQuaternion.h"
 
 namespace CamelotFramework
 {

+ 83 - 33
CamelotUtility/Source/CmQuaternion.cpp

@@ -99,12 +99,12 @@ namespace CamelotFramework
     {
         // Assert:  axis[] is unit length
 
-        Radian fHalfAngle (0.5f*angle);
-        float fSin = Math::sin(fHalfAngle);
-        w = Math::cos(fHalfAngle);
-        x = fSin*axis.x;
-        y = fSin*axis.y;
-        z = fSin*axis.z;
+        Radian halfAngle (0.5f*angle);
+        float sin = Math::sin(halfAngle);
+        w = Math::cos(halfAngle);
+        x = sin*axis.x;
+        y = sin*axis.y;
+        z = sin*axis.z;
     }
 
     void Quaternion::fromAxes(const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
@@ -150,40 +150,40 @@ namespace CamelotFramework
 
 	void Quaternion::toRotationMatrix(Matrix3& mat) const
 	{
-		float fTx  = x+x;
-		float fTy  = y+y;
+		float tx  = x+x;
+		float ty  = y+y;
 		float fTz  = z+z;
-		float fTwx = fTx*w;
-		float fTwy = fTy*w;
-		float fTwz = fTz*w;
-		float fTxx = fTx*x;
-		float fTxy = fTy*x;
-		float fTxz = fTz*x;
-		float fTyy = fTy*y;
-		float fTyz = fTz*y;
-		float fTzz = fTz*z;
-
-		mat[0][0] = 1.0f-(fTyy+fTzz);
-		mat[0][1] = fTxy-fTwz;
-		mat[0][2] = fTxz+fTwy;
-		mat[1][0] = fTxy+fTwz;
-		mat[1][1] = 1.0f-(fTxx+fTzz);
-		mat[1][2] = fTyz-fTwx;
-		mat[2][0] = fTxz-fTwy;
-		mat[2][1] = fTyz+fTwx;
-		mat[2][2] = 1.0f-(fTxx+fTyy);
+		float twx = tx*w;
+		float twy = ty*w;
+		float twz = fTz*w;
+		float txx = tx*x;
+		float txy = ty*x;
+		float txz = fTz*x;
+		float tyy = ty*y;
+		float tyz = fTz*y;
+		float tzz = fTz*z;
+
+		mat[0][0] = 1.0f-(tyy+tzz);
+		mat[0][1] = txy-twz;
+		mat[0][2] = txz+twy;
+		mat[1][0] = txy+twz;
+		mat[1][1] = 1.0f-(txx+tzz);
+		mat[1][2] = tyz-twx;
+		mat[2][0] = txz-twy;
+		mat[2][1] = tyz+twx;
+		mat[2][2] = 1.0f-(txx+tyy);
 	}
 
 	void Quaternion::toAxisAngle(Vector3& axis, Radian& angle) const
 	{
-		float fSqrLength = x*x+y*y+z*z;
-		if ( fSqrLength > 0.0 )
+		float sqrLength = x*x+y*y+z*z;
+		if ( sqrLength > 0.0 )
 		{
 			angle = 2.0*Math::acos(w);
-			float fInvLength = Math::invSqrt(fSqrLength);
-			axis.x = x*fInvLength;
-			axis.y = y*fInvLength;
-			axis.z = z*fInvLength;
+			float invLength = Math::invSqrt(sqrLength);
+			axis.x = x*invLength;
+			axis.y = y*invLength;
+			axis.z = z*invLength;
 		}
 		else
 		{
@@ -378,6 +378,56 @@ namespace CamelotFramework
         return len;
     }
 
+	Quaternion Quaternion::getRotationFromTo(const Vector3& from, const Vector3& dest, const Vector3& fallbackAxis)
+	{
+		// Based on Stan Melax's article in Game Programming Gems
+		Quaternion q;
+
+		Vector3 v0 = from;
+		Vector3 v1 = dest;
+		v0.normalize();
+		v1.normalize();
+
+		float d = v0.dot(v1);
+
+		// If dot == 1, vectors are the same
+		if (d >= 1.0f)
+			return Quaternion::IDENTITY;
+
+		if (d < (1e-6f - 1.0f))
+		{
+			if (fallbackAxis != Vector3::ZERO)
+			{
+				// Rotate 180 degrees about the fallback axis
+				q.fromAxisAngle(fallbackAxis, Radian(Math::PI));
+			}
+			else
+			{
+				// Generate an axis
+				Vector3 axis = Vector3::UNIT_X.cross(from);
+				if (axis.isZeroLength()) // Pick another if colinear
+					axis = Vector3::UNIT_Y.cross(from);
+				axis.normalize();
+				q.fromAxisAngle(axis, Radian(Math::PI));
+			}
+		}
+		else
+		{
+			float s = Math::sqrt( (1+d)*2 );
+			float invs = 1 / s;
+
+			Vector3 c = v0.cross(v1);
+
+			q.x = c.x * invs;
+			q.y = c.y * invs;
+			q.z = c.z * invs;
+			q.w = s * 0.5f;
+			q.normalize();
+		}
+
+		return q;
+	}
+
 	Quaternion operator* (float lhs, const Quaternion& rhs)
 	{
 		return Quaternion(lhs*rhs.w,lhs*rhs.x,lhs*rhs.y,

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -42,8 +42,10 @@
   <ItemGroup>
     <Compile Include="Color.cs" />
     <Compile Include="MathEx.cs" />
+    <Compile Include="Matrix3.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Quaternion.cs" />
     <Compile Include="ScriptObject.cs" />
     <Compile Include="Texture2D.cs" />
     <Compile Include="TextureFormat.cs" />

+ 21 - 0
MBansheeEngine/MathEx.cs

@@ -2,8 +2,24 @@
 
 namespace BansheeEngine
 {
+    public enum EulerAngleOrder
+	{
+		XYZ,
+		XZY,
+		YXZ,
+		YZX,
+		ZXY,
+		ZYX
+	};
+
     class MathEx
     {
+        public const float Pi = 3.141593f;
+        public const float TwoPi = (2.0f * Pi);
+        public const float HalfPi = (0.5f * Pi);
+        public const float Deg2Rad = Pi / 180.0f;
+        public const float Rad2Deg = 180.0f / Pi;
+
         public static float Min(float a, float b)
         {
             if (a < b)
@@ -210,6 +226,11 @@ namespace BansheeEngine
             return (float)Math.Sqrt(f);
         }
 
+        public static float InvSqrt(float f)
+        {
+            return 1.0f/(float) Math.Sqrt(f);
+        }
+
         public static float Clamp(float value, float min, float max)
         {
             if (value < min)

+ 46 - 0
MBansheeEngine/Matrix3.cs

@@ -0,0 +1,46 @@
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    [StructLayout(LayoutKind.Sequential)]
+    public class Matrix3
+    {
+        public float[,] m = new float[3,3];
+
+        public float this[int row, int column]
+        {
+            get
+            {
+                return m[row, column];
+            }
+            set
+            {
+                m[row, column] = value;
+            }
+        }
+
+        public float this[int index]
+        {
+            get
+            {
+                return (float)m.GetValue(index);
+            }
+            set
+            {
+                m.SetValue(value, index);
+            }
+        }
+
+        public Vector3 Transform(Vector3 vec)
+        {
+            // TODO
+            return Vector3.zero;
+        }
+
+        public Vector3 ToEulerAngles(EulerAngleOrder order)
+        {
+            // TODO - Angles returned must be in degrees
+            return Vector3.zero;
+        }
+    }
+}

+ 489 - 0
MBansheeEngine/Quaternion.cs

@@ -0,0 +1,489 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    [StructLayout(LayoutKind.Sequential)]
+    public struct Quaternion
+    {
+        private struct EulerAngleOrderData
+		{
+            public EulerAngleOrderData(int a, int b, int c)
+            {
+                this.a = a;
+                this.b = b;
+                this.c = c;
+            }
+
+			public int a, b, c;
+		};
+
+        public static readonly Quaternion zero = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);
+        public static readonly Quaternion identity = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
+
+        private static readonly float epsilon = 1e-03f;
+
+        private static readonly EulerAngleOrderData[] EA_LOOKUP = new EulerAngleOrderData[6]
+		    { new EulerAngleOrderData(0, 1, 2), new EulerAngleOrderData(0, 2, 1), new EulerAngleOrderData(1, 0, 2),
+		      new EulerAngleOrderData(1, 2, 0), new EulerAngleOrderData(2, 0, 1), new EulerAngleOrderData(2, 1, 0) };
+
+        public float x;
+        public float y;
+        public float z;
+        public float w;
+
+        public float this[int index]
+        {
+            get
+            {
+                switch (index)
+                {
+                    case 0:
+                        return x;
+                    case 1:
+                        return y;
+                    case 2:
+                        return z;
+                    case 3:
+                        return w;
+                    default:
+                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
+                }
+            }
+            set
+            {
+                switch (index)
+                {
+                    case 0:
+                        x = value;
+                        break;
+                    case 1:
+                        y = value;
+                        break;
+                    case 2:
+                        z = value;
+                        break;
+                    case 3:
+                        w = value;
+                        break;
+                    default:
+                        throw new IndexOutOfRangeException("Invalid Quaternion index.");
+                }
+            }
+        }
+
+        public Quaternion(float x, float y, float z, float w)
+        {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+
+        public static Quaternion operator* (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion((lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y), 
+                (lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z), 
+                (lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x), 
+                (lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z));
+        }
+
+        public static Quaternion operator* (float lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
+        }
+
+        public static Quaternion operator+ (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
+        }
+
+        public static Quaternion operator- (Quaternion lhs, Quaternion rhs)
+        {
+            return new Quaternion(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
+        }
+
+        public static Quaternion operator- (Quaternion quat)
+        {
+            return new Quaternion(-quat.w, -quat.x, -quat.y, -quat.z);
+        }
+
+        public static bool operator== (Quaternion lhs, Quaternion rhs)
+        {
+            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
+        }
+
+        public static bool operator!= (Quaternion lhs, Quaternion rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        public static float Dot(Quaternion a, Quaternion b)
+        {
+            return (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
+        }
+
+        public Vector3 Rotate(Vector3 point)
+        {
+            return ToRotationMatrix().Transform(point);
+        }
+
+        public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
+        {
+            SetFromToRotation(fromDirection, toDirection, Vector3.zero);
+        }
+
+        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 = AxisAngle(fallbackAxis, MathEx.Pi * MathEx.Rad2Deg);
+			    }
+			    else
+			    {
+				    // Generate an axis
+				    Vector3 axis = Vector3.Cross(Vector3.xAxis, fromDirection);
+                    if (axis.sqrdMagnitude < ((1e-06f * 1e-06f))) // Pick another if collinear
+					    axis = Vector3.Cross(Vector3.yAxis, fromDirection);
+				    axis.Normalize();
+                    this = AxisAngle(axis, MathEx.Pi * MathEx.Rad2Deg);
+			    }
+		    }
+		    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();
+		    }
+        }
+
+        public float Normalize()
+        {
+            float len = w*w+x*x+y*y+z*z;
+            float factor = 1.0f / MathEx.Sqrt(len);
+
+            x *= factor;
+            y *= factor;
+            z *= factor;
+            w *= factor;
+            return len;
+        }
+
+        public void Inverse()
+        {
+            float fNorm = w * w + x * x + y * y + z * z;
+            if (fNorm > 0.0f)
+            {
+                float fInvNorm = 1.0f / fNorm;
+                x *= -fInvNorm;
+                y *= -fInvNorm;
+                z *= -fInvNorm;
+                w *= fInvNorm;
+            }
+            else
+            {
+                this = zero;
+            }
+        }
+
+        public void SetLookRotation(Vector3 forward)
+        {
+            SetLookRotation(forward, Vector3.yAxis);
+        }
+
+        public void SetLookRotation(Vector3 forward, Vector3 up)
+        {
+            Quaternion forwardRot = FromToRotation(Vector3.zAxis, forward);
+            Quaternion upRot = FromToRotation(Vector3.yAxis, up);
+
+            this = forwardRot * upRot;
+        }
+
+        public static Quaternion Slerp(Quaternion from, Quaternion to, float t, bool shortestPath = false)
+        {
+            float cos = from.w*to.w + from.x*to.x + from.y*to.y + from.z*from.z;
+            Quaternion quat;
+
+            if (cos < 0.0f && shortestPath)
+            {
+                cos = -cos;
+                quat = -to;
+            }
+            else
+            {
+                quat = to;
+            }
+
+            if (MathEx.Abs(cos) < (1 - epsilon))
+            {
+                // Standard case (slerp)
+                float sin = MathEx.Sqrt(1 - (cos*cos));
+                float angle = MathEx.Atan2(sin, cos);
+                float invSin = 1.0f / sin;
+                float coeff0 = MathEx.Sin((1.0f - t) * angle) * invSin;
+                float coeff1 = MathEx.Sin(t * angle) * invSin;
+                return coeff0 * from + coeff1 * quat;
+            }
+            else
+            {
+                // There are two situations:
+                // 1. "p" and "q" are very close (fCos ~= +1), so we can do a linear
+                //    interpolation safely.
+                // 2. "p" and "q" are almost inverse of each other (fCos ~= -1), there
+                //    are an infinite number of possibilities interpolation. but we haven't
+                //    have method to fix this case, so just use linear interpolation here.
+                Quaternion ret = (1.0f - t) * from + t * quat;
+
+                // Taking the complement requires renormalization
+                ret.Normalize();
+                return ret;
+            }
+        }
+
+        public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegelta)
+        {
+            float num = Angle(from, to);
+            if (num == 0.0f)
+                return to;
+
+            float t = MathEx.Min(1f, maxDegelta / num);
+            return Slerp(from, to, t);
+        }
+
+        public static Quaternion Inverse(Quaternion rotation)
+        {
+            Quaternion copy = rotation;
+            copy.Inverse();
+
+            return copy;
+        }
+
+        /**
+         * @note Returns angle in degrees.
+         */
+        public static float Angle(Quaternion a, Quaternion b)
+        {
+            return (MathEx.Acos(MathEx.Min(MathEx.Abs(Dot(a, b)), 1.0f)) * 2.0f * MathEx.Rad2Deg);
+        }
+
+        public void ToAxisAngle(out Vector3 axis, out float angleDeg)
+        {
+            float fSqrLength = x*x+y*y+z*z;
+		    if (fSqrLength > 0.0f)
+		    {
+                angleDeg = 2.0f * MathEx.Acos(w) * MathEx.Rad2Deg;
+			    float fInvLength = MathEx.InvSqrt(fSqrLength);
+			    axis.x = x*fInvLength;
+			    axis.y = y*fInvLength;
+			    axis.z = z*fInvLength;
+		    }
+		    else
+		    {
+			    // Angle is 0, so any axis will do
+                angleDeg = 0.0f;
+			    axis.x = 1.0f;
+			    axis.y = 0.0f;
+			    axis.z = 0.0f;
+		    }
+        }
+
+        // Returns angles in degrees
+        public Vector3 ToEulerAngles(EulerAngleOrder order = EulerAngleOrder.XYZ)
+        {
+            Matrix3 matRot = ToRotationMatrix();
+            return matRot.ToEulerAngles(order);
+        }
+
+        public Matrix3 ToRotationMatrix()
+        {
+            Matrix3 mat = new Matrix3();
+
+            float tx = x + x;
+            float ty = y + y;
+            float fTz = z + z;
+            float twx = tx * w;
+            float twy = ty * w;
+            float twz = fTz * w;
+            float txx = tx * x;
+            float txy = ty * x;
+            float txz = fTz * x;
+            float tyy = ty * y;
+            float tyz = fTz * y;
+            float tzz = fTz * z;
+
+            mat[0, 0] = 1.0f - (tyy + tzz);
+            mat[0, 1] = txy - twz;
+            mat[0, 2] = txz + twy;
+            mat[1, 0] = txy + twz;
+            mat[1, 1] = 1.0f - (txx + tzz);
+            mat[1, 2] = tyz - twx;
+            mat[2, 0] = txz - twy;
+            mat[2, 1] = tyz + twx;
+            mat[2, 2] = 1.0f - (txx + tyy);
+
+            return mat;
+        }
+
+        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection)
+        {
+            Quaternion q = new Quaternion();
+            q.SetFromToRotation(fromDirection, toDirection);
+            return q;
+        }
+
+        public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection, Vector3 fallbackAxis)
+        {
+            Quaternion q = new Quaternion();
+            q.SetFromToRotation(fromDirection, toDirection, fallbackAxis);
+            return q;
+        }
+
+        public static Quaternion LookRotation(Vector3 forward)
+        {
+            Quaternion quat = new Quaternion();
+            quat.SetLookRotation(forward);
+
+            return quat;
+        }
+
+        public static Quaternion LookRotation(Vector3 forward, Vector3 up)
+        {
+            Quaternion quat = new Quaternion();
+            quat.SetLookRotation(forward, up);
+
+            return quat;
+        }
+
+        public static Vector3 ToEulerAngles(Quaternion rotation, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        {
+            return rotation.ToEulerAngles(order);
+        }
+
+        public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out float angleDeg)
+        {
+            rotation.ToAxisAngle(out axis, out angleDeg);
+        }
+
+        public static Quaternion RotationMatrix(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.m[0, 0] + rotMatrix.m[1, 1] + rotMatrix.m[2, 2];
+            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.m[2, 1] - rotMatrix.m[1, 2]) * root;
+                quat.y = (rotMatrix.m[0, 2] - rotMatrix.m[2, 0]) * root;
+                quat.z = (rotMatrix.m[1, 0] - rotMatrix.m[0, 1]) * root;
+            }
+            else
+            {
+                // |w| <= 1/2
+                int[] nextLookup = { 1, 2, 0 };
+                int i = 0;
+
+                if (rotMatrix.m[1, 1] > rotMatrix.m[0, 0])
+                    i = 1;
+
+                if (rotMatrix.m[2, 2] > rotMatrix.m[i, i])
+                    i = 2;
+
+                int j = nextLookup[i];
+                int k = nextLookup[j];
+
+                root = MathEx.Sqrt(rotMatrix.m[i,i] - rotMatrix.m[j, j] - rotMatrix.m[k, k] + 1.0f);
+
+                quat[i] = 0.5f*root;
+                root = 0.5f/root;
+
+                quat.w = (rotMatrix.m[k, j] - rotMatrix.m[j, k]) * root;
+                quat[j] = (rotMatrix.m[j, i] + rotMatrix.m[i, j]) * root;
+                quat[k] = (rotMatrix.m[k, i] + rotMatrix.m[i, k]) * root;
+            }
+
+		    quat.Normalize();
+
+            return quat;
+        }
+
+        public static Quaternion AxisAngle(Vector3 axis, float angleDeg)
+        {
+            Quaternion quat;
+
+            float halfAngle = (0.5f*angleDeg*MathEx.Deg2Rad);
+            float sin = MathEx.Sin(halfAngle);
+            quat.w = MathEx.Cos(halfAngle);
+            quat.x = sin * axis.x;
+            quat.y = sin * axis.y;
+            quat.z = sin * axis.z;
+
+            return quat;
+        }
+
+        public static Quaternion Euler(float xDeg, float yDeg, float zDeg, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        {
+            EulerAngleOrderData l = EA_LOOKUP[(int)order];
+
+            Quaternion[] quats = new Quaternion[3];
+		    quats[0] = AxisAngle(Vector3.xAxis, xDeg);
+		    quats[1] = AxisAngle(Vector3.yAxis, yDeg);
+		    quats[2] = AxisAngle(Vector3.zAxis, zDeg);
+
+            return quats[l.c]*(quats[l.a] * quats[l.b]);
+        }
+
+        /**
+         * @note Angles in degrees.
+         */
+        public static Quaternion Euler(Vector3 euler, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        {
+            return Euler(euler.x, euler.y, euler.z, order);
+        }
+
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ y.GetHashCode() << 2 ^ z.GetHashCode() >> 2 ^ w.GetHashCode() >> 1;
+        }
+
+        public override bool Equals(object other)
+        {
+            if (!(other is Quaternion))
+                return false;
+
+            Quaternion quat = (Quaternion)other;
+            if (x.Equals(quat.x) && y.Equals(quat.y) && z.Equals(quat.z) && w.Equals(quat.w))
+                return true;
+
+            return false;
+        }
+    }
+}

+ 31 - 15
MBansheeEngine/Vector2.cs

@@ -9,21 +9,10 @@ namespace BansheeEngine
         public float x;
         public float y;
 
-        public static Vector2 zero
-        {
-            get
-            {
-                return new Vector2(0.0f, 0.0f);
-            }
-        }
-
-        public static Vector2 one
-        {
-            get
-            {
-                return new Vector2(1.0f, 1.0f);
-            }
-        }
+        public static readonly Vector2 zero = new Vector2(0.0f, 0.0f);
+        public static readonly Vector2 one = new Vector2(1.0f, 1.0f);
+        public static readonly Vector2 xAxis = new Vector2(1.0f, 0.0f);
+        public static readonly Vector2 yAxis = new Vector2(0.0f, 1.0f);
 
         public float this[int index]
         {
@@ -116,6 +105,16 @@ namespace BansheeEngine
             return new Vector2(v.x / d, v.y / d);
         }
 
+        public static bool operator== (Vector2 lhs, Vector2 rhs)
+        {
+            return lhs.x == rhs.x && lhs.y == rhs.y;
+        }
+
+        public static bool operator!= (Vector2 lhs, Vector2 rhs)
+        {
+            return !(lhs == rhs);
+        }
+
         public static Vector2 Scale(Vector2 a, Vector2 b)
         {
             return new Vector2(a.x * b.x, a.y * b.y);
@@ -165,5 +164,22 @@ namespace BansheeEngine
             else
                 this = zero;
         }
+
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ y.GetHashCode() << 2;
+        }
+
+        public override bool Equals(object other)
+        {
+            if (!(other is Vector2))
+                return false;
+
+            Vector2 vec = (Vector2)other;
+            if (x.Equals(vec.x) && y.Equals(vec.y))
+                return true;
+            
+            return false;
+        }
     }
 }

+ 33 - 16
MBansheeEngine/Vector3.cs

@@ -6,26 +6,16 @@ namespace BansheeEngine
     [StructLayout(LayoutKind.Sequential)]
     public struct Vector3
     {
+        public static readonly Vector3 zero = new Vector3(0.0f, 0.0f, 0.0f);
+        public static readonly Vector3 one = new Vector3(1.0f, 1.0f, 1.0f);
+        public static readonly Vector3 xAxis = new Vector3(1.0f, 0.0f, 0.0f);
+        public static readonly Vector3 yAxis = new Vector3(0.0f, 1.0f, 0.0f);
+        public static readonly Vector3 zAxis = new Vector3(0.0f, 0.0f, 1.0f);
+
         public float x;
         public float y;
         public float z;
 
-        public static Vector3 zero
-        {
-            get
-            {
-                return new Vector3(0.0f, 0.0f, 0.0f);
-            }
-        }
-
-        public static Vector3 one
-        {
-            get
-            {
-                return new Vector3(1.0f, 1.0f, 1.0f);
-            }
-        }
-
         public float this[int index]
         {
             get
@@ -133,6 +123,16 @@ namespace BansheeEngine
             return new Vector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
         }
 
+        public static bool operator ==(Vector3 lhs, Vector3 rhs)
+        {
+            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
+        }
+
+        public static bool operator !=(Vector3 lhs, Vector3 rhs)
+        {
+            return !(lhs == rhs);
+        }
+
         public static Vector3 Normalize(Vector3 value)
         {
             float num = Magnitude(value);
@@ -178,5 +178,22 @@ namespace BansheeEngine
             else
                 this = zero;
         }
+
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ y.GetHashCode() << 2 ^ z.GetHashCode() >> 2;
+        }
+
+        public override bool Equals(object other)
+        {
+            if (!(other is Vector3))
+                return false;
+
+            Vector3 vec = (Vector3)other;
+            if (x.Equals(vec.x) && y.Equals(vec.y) && z.Equals(vec.z))
+                return true;
+
+            return false;
+        }
     }
 }

+ 34 - 17
MBansheeEngine/Vector4.cs

@@ -6,27 +6,17 @@ namespace BansheeEngine
     [StructLayout(LayoutKind.Sequential)]
     public struct Vector4
     {
+        public static readonly Vector4 zero = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
+        public static readonly Vector4 one = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
+        public static readonly Vector4 xAxis = new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
+        public static readonly Vector4 yAxis = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
+        public static readonly Vector4 zAxis = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
+
         public float x;
         public float y;
         public float z;
         public float w;
 
-        public static Vector4 zero
-        {
-            get
-            {
-                return new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
-            }
-        }
-
-        public static Vector4 one
-        {
-            get
-            {
-                return new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
-            }
-        }
-
         public float this[int index]
         {
             get
@@ -130,6 +120,16 @@ namespace BansheeEngine
             return new Vector4(v.x / d, v.y / d, v.z / d, v.w / d);
         }
 
+        public static bool operator== (Vector4 lhs, Vector4 rhs)
+        {
+            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w;
+        }
+
+        public static bool operator!= (Vector4 lhs, Vector4 rhs)
+        {
+            return !(lhs == rhs);
+        }
+
         public static Vector4 Scale(Vector4 a, Vector4 b)
         {
             return new Vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
@@ -176,10 +176,27 @@ namespace BansheeEngine
         public void Normalize()
         {
             float num = Magnitude(this);
-            if (num > 9.999999E-06)
+            if (num > 9.999999e-06f)
                 this /= num;
             else
                 this = zero;
         }
+
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ y.GetHashCode() << 2 ^ z.GetHashCode() >> 2 ^ w.GetHashCode() >> 1;
+        }
+
+        public override bool Equals(object other)
+        {
+            if (!(other is Vector4))
+                return false;
+
+            Vector4 vec = (Vector4)other;
+            if (x.Equals(vec.x) && y.Equals(vec.y) && z.Equals(vec.z) && w.Equals(vec.w))
+                return true;
+
+            return false;
+        }
     }
 }