I've made some regular old Vector2,3, and 4 classes to use as rows in my Matrix2,3, and 4 classes. My matrix classes are row major. My main concern right now is the Matrix4 class. Since all the Vector classes are pretty standard, I don't think it's necessary to put them here. Here's my Matrix4 class:

template <typename ValueType> class Matrix4 { public: Matrix4() { Identity(1.0f); } Matrix4(const Matrix4 <ValueType>&Mat) { *this = Mat; } ~Matrix4() { } void DebugPrint() const { for(int i = 0;i < 4;i++)System::USystem::GetSystem()->Log(Ungine::System::LOG_MESSAGE,"%f\t%f\t%f\t%f\n",Rows[i][0],Rows[i][1],Rows[i][2],Rows[i][3]); } Matrix4 <ValueType>Transpose() const { Matrix4 <ValueType>Ret; Ret[0][0] = Rows[0][0]; Ret[0][1] = Rows[1][0]; Ret[0][2] = Rows[2][0]; Ret[0][3] = Rows[3][0]; Ret[1][0] = Rows[0][1]; Ret[1][1] = Rows[1][1]; Ret[1][2] = Rows[2][1]; Ret[1][3] = Rows[3][1]; Ret[2][0] = Rows[0][2]; Ret[2][1] = Rows[1][2]; Ret[2][2] = Rows[2][2]; Ret[2][3] = Rows[3][2]; Ret[3][0] = Rows[0][3]; Ret[3][1] = Rows[1][3]; Ret[3][2] = Rows[2][3]; Ret[3][3] = Rows[3][3]; return Ret; } void operator =(const Matrix4 <ValueType>&Mat) { for(int i = 0;i < 4;i++) for(int j = 0;j < 4;j++) Rows[i][j] = Mat[i][j]; } Matrix4 <ValueType>operator *(const Matrix4 <ValueType>&Mat) const { Matrix4 Ret; Ret[0][0] = Rows[0].DotProduct(Mat.GetColumn(0)); Ret[0][1] = Rows[0].DotProduct(Mat.GetColumn(1)); Ret[0][2] = Rows[0].DotProduct(Mat.GetColumn(2)); Ret[0][3] = Rows[0].DotProduct(Mat.GetColumn(3)); Ret[1][0] = Rows[1].DotProduct(Mat.GetColumn(0)); Ret[1][1] = Rows[1].DotProduct(Mat.GetColumn(1)); Ret[1][2] = Rows[1].DotProduct(Mat.GetColumn(2)); Ret[1][3] = Rows[1].DotProduct(Mat.GetColumn(3)); Ret[2][0] = Rows[2].DotProduct(Mat.GetColumn(0)); Ret[2][1] = Rows[2].DotProduct(Mat.GetColumn(1)); Ret[2][2] = Rows[2].DotProduct(Mat.GetColumn(2)); Ret[2][3] = Rows[2].DotProduct(Mat.GetColumn(3)); Ret[3][0] = Rows[3].DotProduct(Mat.GetColumn(0)); Ret[3][1] = Rows[3].DotProduct(Mat.GetColumn(1)); Ret[3][2] = Rows[3].DotProduct(Mat.GetColumn(2)); Ret[3][3] = Rows[3].DotProduct(Mat.GetColumn(3)); return Ret; } Matrix4 <ValueType>operator *=(const Matrix4 <ValueType>&Mat) { *this = *this * Mat; return *this; } Vector4 <ValueType>operator *(const Vector4<ValueType>&Vec) const { Vector4 <ValueType>Ret; Ret.x = Rows[0].DotProduct(Vec); Ret.y = Rows[1].DotProduct(Vec); Ret.z = Rows[2].DotProduct(Vec); Ret.w = Rows[3].DotProduct(Vec); return Ret; } Vector3 <ValueType>operator *(const Vector3<ValueType>&Vec) const { Vector3 <ValueType>Ret; Ret.x = Rows[0].DotProduct(Vec); Ret.y = Rows[1].DotProduct(Vec); Ret.z = Rows[2].DotProduct(Vec); return Ret; } void Identity(ValueType id = 1.0f) { Rows[0] = Vector4 <ValueType>(id,0.0f,0.0f,0.0f); Rows[1] = Vector4 <ValueType>(0.0f,id,0.0f,0.0f); Rows[2] = Vector4 <ValueType>(0.0f,0.0f,id,0.0f); Rows[3] = Vector4 <ValueType>(0.0f,0.0f,0.0f,id); } void Translate(const Vector3 <ValueType>&Trans) { Matrix4 <ValueType> Mat; Mat[0] = Vector4 <ValueType>(1.0f,0.0f,0.0f,Trans.x); Mat[1] = Vector4 <ValueType>(0.0f,1.0f,0.0f,Trans.y); Mat[2] = Vector4 <ValueType>(0.0f,0.0f,1.0f,Trans.z); Mat[3] = Vector4 <ValueType>(0.0f,0.0f,0.0f,1.0f ); *this = *this * Mat; } void Rotate(const Vector3 <ValueType>&Axis,ValueType Angle) { Matrix4 Mat; ValueType hAngle = Angle * 0.5f; ValueType SinAngle = Sin(hAngle); ValueType CosAngle = Cos(hAngle); ValueType w = CosAngle; ValueType x = Axis.x * SinAngle; ValueType y = Axis.y * SinAngle; ValueType z = Axis.z * SinAngle; ValueType xSq = x * x; ValueType ySq = y * y; ValueType zSq = z * z; ValueType xy = x * y; ValueType xz = x * z; ValueType xw = x * w; ValueType yw = y * w; ValueType zw = z * w; ValueType zy = z * y; Mat[0][0] = 1.0f - 2.0f * (ySq + zSq); Mat[0][1] = 2.0f * (xy + zw); Mat[0][2] = 2.0f * (xz - yw); Mat[0][3] = 0.0f; Mat[1][0] = 2.0f * (xy - zw); Mat[1][1] = 1.0f - 2.0f * (xSq + zSq); Mat[1][2] = 2.0f * (zy + xw); Mat[1][3] = 0.0f; Mat[2][0] = 2.0f * (xz + yw); Mat[2][1] = 2.0f * (zy - xw); Mat[2][2] = 1.0f - 2.0f * (xSq + ySq); Mat[2][3] = 0.0f; Mat[3][0] = 0.0f; Mat[3][1] = 0.0f; Mat[3][2] = 0.0f; Mat[3][3] = 1.0f; *this = *this * Mat; } void Scale(ValueType Scale) { Matrix4 <ValueType> Mat; Mat[0] = Vector4 <ValueType>(Scale,0.0f,0.0f,0.0f); Mat[1] = Vector4 <ValueType>(0.0f,Scale,0.0f,0.0f); Mat[2] = Vector4 <ValueType>(0.0f,0.0f,Scale,0.0f); Mat[3] = Vector4 <ValueType>(0.0f,0.0f,0.0f,Scale); *this = *this * Mat; } void Scale(const Vector4 <ValueType> &Scale) { Matrix4 <ValueType> Mat; Mat[0] = Vector4 <ValueType>(Scale.x,0.0f,0.0f,0.0f); Mat[1] = Vector4 <ValueType>(0.0f,Scale.y,0.0f,0.0f); Mat[2] = Vector4 <ValueType>(0.0f,0.0f,Scale.z,0.0f); Mat[3] = Vector4 <ValueType>(0.0f,0.0f,0.0f,Scale.w); *this = *this * Mat; } ValueType Determinant() const { abort(); } bool Inverse(Matrix4 <ValueType>*Mat) { abort(); return false; } ValueType *Ptr() { return &Rows[0].x; } Vector4 <ValueType>GetColumn(Index Idx) const { return Vector4 <ValueType>(Rows[0][Idx],Rows[1][Idx],Rows[2][Idx],Rows[3][Idx]); } Vector4 <ValueType>&operator[](Index Idx) { return Rows[Idx]; } Vector4 <ValueType>operator[](Index Idx) const { return Rows[Idx]; } protected: Vector4 <ValueType>Rows[4]; };

I realized I had a problems when I was trying to use this class to build a MVP matrix for a camera. No matter how I do it, what order I multiply in, whether or not the end MVP matrix or the individual matrices are transposed, what I see on the screen is just a very stretched out polygon. I am attempting to render a simple square at 0,0,0,0 with a perspective and orthographic projection.

Here's part of the render function where I am testing the matrix class:

System::USystem::GetSystem()->SetAngleType(Ungine::System::AT_DEGREE); Matrix4f Model, View, Projection, MVP; static f32 Val = 0.0f; Val += 0.01f; //Model.Translate(Vector3f(768 / 2,1024 / 2,0)); //Model.Rotate(Vector3f(0,1,1).Normalize(),Val / 2.0f); //Model.Scale(Vector4f((2 + Math::Sin(Val)) * 0.5f,(2 + Math::Sin(Val)) * 0.5f,(2 + Math::Sin(Val)) * 0.5f,1.0f));//;Rotate(Vector3f(0,0,1),Val); View = LookAt(Vector3f(0,0,-20.0f),Vector3f(0,0,0),Vector3f(0,1,0)); Projection = Perspectivef(50.0f,768.0f / 1024.0f,0.1f,1000.0f); //Projection = Orthographicf(0.0f,768.0f,0.0f,1024.0f,0.0f,1000.0f); MVP = Projection * View * Model; glUniformMatrix4fv(MVP_Loc,1,false,MVP.Ptr());

And here are the projection and LookAt functions:

Matrix4f Perspectivef(f32 FieldOfView,f32 AspectRatio,f32 Near,f32 Far) { Matrix4f Mat; f32 TanFov = Tan(FieldOfView * 0.5f); f32 a = 1.0f / (AspectRatio * TanFov); f32 b = 1.0f / TanFov; f32 c = Far / (Far - Near); f32 d = -(2.0f * Near * Far) / (Far - Near); Mat[0] = Vector4f(a , 0.0f , 0.0f , 0.0f); Mat[1] = Vector4f(0.0f , b , 0.0f , 0.0f); Mat[2] = Vector4f(0.0f , 0.0f , c , d ); Mat[3] = Vector4f(0.0f , 0.0f , 1.0f , 0.0f); return Mat; } Matrix4f Orthographicf(f32 Left,f32 Right,f32 Top,f32 Bottom,f32 Near,f32 Far) { Matrix4f Mat; f32 dW = Left - Right; f32 dH = Top - Bottom; f32 dL = Far - Near; f32 Tx = (Right + Left) / (Right - Left); f32 Ty = (Far + Near) / (Far - Near); f32 Tz = (Top + Bottom) / (Top - Bottom); Mat[0] = Vector4f(2.0f / (dW),0.0f ,0.0f ,Tx ); Mat[1] = Vector4f(0.0f ,2.0f / (dH),0.0f ,Ty ); Mat[2] = Vector4f(0.0f ,0.0f ,-(2.0f / dL),Tz ); Mat[3] = Vector4f(0.0f ,0.0f ,0.0f ,1.0f); return Mat; } Matrix4f LookAt(const Vector3f &Eye,const Vector3f &Target,const Vector3f &Up) { Matrix4f Mat; Vector3f Forward, Side, _Up; Forward = (Target - Eye).Normalize(); Side = Forward.CrossProduct(Up).Normalize(); _Up = Side.CrossProduct(Forward).Normalize(); Mat[0] = Vector4f(Side ,0.0f ); Mat[1] = Vector4f(_Up ,0.0f ); Mat[2] = Vector4f(Forward * -1.0f,0.0f ); Mat[3] = Vector4f(0.0f ,0.0f,0.0f,1.0f); Mat.Translate(Eye * -1.0f); return Mat; }

It's a bunch of code to look through, but if anyone has the patience, could you tell me if you see anything that looks wrong?

Matrix4f is just Matrix4 <f32>. Also, sorry about the large amount of whitespace before each line, that's just from the indentation from two namespaces that I didn't include in the code, for some reason they got larger when I submitted this thread.

Thank you for your time!