diff --git a/Engine/source/math/mMatrix.h b/Engine/source/math/mMatrix.h index 211c17f329..8226bb12c7 100644 --- a/Engine/source/math/mMatrix.h +++ b/Engine/source/math/mMatrix.h @@ -698,6 +698,17 @@ class Matrix { void setPosition(const Point3F& pos) { setColumn(3, pos); } + DATA_TYPE determinant() const { + AssertFatal(rows == cols, "Determinant is only defined for square matrices."); + // For simplicity, only implement for 3x3 matrices + AssertFatal(rows >= 3 && cols >= 3, "Determinant only for 3x3 or more"); // Ensure the matrix is 3x3 + DATA_TYPE det = + data[0] * (data[4] * data[8] - data[5] * data[7]) - + data[1] * (data[3] * data[8] - data[5] * data[6]) + + data[2] * (data[3] * data[7] - data[4] * data[6]); + return det; + } + ///< M * a -> M Matrix& mul(const Matrix& a) { return *this = *this * a; } @@ -1406,10 +1417,10 @@ inline Matrix& Matrix::inverse() { // TODO: insert return statement here AssertFatal(rows == cols, "Can only perform inverse on square matrices."); - const U32 size = rows; + const U32 size = rows - 1; // Create augmented matrix [this | I] - Matrix augmentedMatrix; + Matrix augmentedMatrix; for (U32 i = 0; i < size; i++) { @@ -1449,12 +1460,12 @@ inline Matrix& Matrix::inverse() return *this; } - DATA_TYPE pivotVal = augmentedMatrix(i, i); + DATA_TYPE pivotVal = 1.0f / augmentedMatrix(i, i); // scale the pivot for (U32 j = 0; j < 2 * size; j++) { - augmentedMatrix(i, j) /= pivotVal; + augmentedMatrix(i, j) *= pivotVal; } // Eliminate the current column in all other rows @@ -1479,6 +1490,10 @@ inline Matrix& Matrix::inverse() } } + Point3F pos = -this->getPosition(); + mulV(pos); + this->setPosition(pos); + return (*this); } diff --git a/Engine/source/testing/mathMatrixTest.cpp b/Engine/source/testing/mathMatrixTest.cpp index f3cc6a233b..9237bc8b30 100644 --- a/Engine/source/testing/mathMatrixTest.cpp +++ b/Engine/source/testing/mathMatrixTest.cpp @@ -8,6 +8,7 @@ #include "console/engineAPI.h" #include "math/mMath.h" #include "math/util/frustum.h" +#include "math/mathUtils.h" TEST(MatrixTest, TestIdentityInit) { @@ -800,28 +801,47 @@ TEST(MatrixTest, TestMatrixAdd) } -TEST(MatrixTest, TestReverseProjection) +TEST(MatrixTest, TestFrustumProjectionMatrix) { MatrixF test(true); - test.setPosition(Point3F(5.0f, 2.0f, 1.0f)); - - Frustum testFrustum(false, -1.0f, 1.0f, 1.0f, -1.0f, 0.1f, 100.0f, test); + Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f); testFrustum.getProjectionMatrix(&test); - - // test before and after reverse. - EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1001f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), -0.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.1f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); test.reverseProjection(); - EXPECT_NEAR(test(0, 0), 0.1f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); - EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.1, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); - EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1001f, 0.001f); - EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(0, 0), 0.8341f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 1.3032f, 0.001f); EXPECT_NEAR(test(1, 3), 0.0, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 1.0001f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), -0.1f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + + test.inverse(); + + EXPECT_NEAR(test(0, 0), 1.1989f, 0.001f); EXPECT_NEAR(test(0, 1), 0.0f, 0.001f); EXPECT_NEAR(test(0, 2), 0.0f, 0.001f); EXPECT_NEAR(test(0, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(1, 0), 0.0f, 0.001f); EXPECT_NEAR(test(1, 1), 0.0f, 0.001f); EXPECT_NEAR(test(1, 2), 0.9999f, 0.001f); EXPECT_NEAR(test(1, 3), 0.1f, 0.001f); + EXPECT_NEAR(test(2, 0), 0.0f, 0.001f); EXPECT_NEAR(test(2, 1), 0.7673f, 0.001f); EXPECT_NEAR(test(2, 2), 0.0f, 0.001f); EXPECT_NEAR(test(2, 3), 0.0f, 0.001f); + EXPECT_NEAR(test(3, 0), 0.0f, 0.001f); EXPECT_NEAR(test(3, 1), 1.0f, 0.001f); EXPECT_NEAR(test(3, 2), 0.0f, 0.001f); EXPECT_NEAR(test(3, 3), 0.0f, 0.001f); + +} + +TEST(MatrixTest, TestUnProjectStack) +{ + MatrixF saveModel(true); + MatrixF saveProjection(true); + RectI renderRect(0 ,0, 1600, 1024); + + Frustum testFrustum(false, -0.119894862f, 0.119894862f, 0.0767327100f, -0.0767327100f, 0.1f, 1000.0f); + + testFrustum.getProjectionMatrix(&saveProjection); + + Point3F dest; + MathUtils::mProjectScreenToWorld(Point3F(626.0f, 600.0f, 1.0f), &dest, renderRect, saveModel, saveProjection, 0.1f, 10.0f); + EXPECT_NEAR(dest.x, -0.2868f, 0.001f); EXPECT_NEAR(dest.y, 1.1998f, 0.001f); EXPECT_NEAR(dest.z, -0.1450f, 0.001f); } TEST(MatrixTest, TestInverse)