Skip to content

Commit

Permalink
inverse fixes
Browse files Browse the repository at this point in the history
further tests showed issues with inverse function, now to better match what was originally happening, the inverse only happens on the 3x3 portion of the matrix and translation is handled separately.

Frustum test now uses more real world examples of a projection matrix. Test for the full unproject stack of math to test its result as unproject was where the issue about inverse originated
  • Loading branch information
marauder2k7 committed Jul 30, 2024
1 parent f96e044 commit 4078f3a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 18 deletions.
23 changes: 19 additions & 4 deletions Engine/source/math/mMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<DATA_TYPE, rows, cols>& mul(const Matrix<DATA_TYPE, rows, cols>& a)
{ return *this = *this * a; }
Expand Down Expand Up @@ -1406,10 +1417,10 @@ inline Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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<DATA_TYPE, size, 2 * size> augmentedMatrix;
Matrix<DATA_TYPE, size, rows + size> augmentedMatrix;

for (U32 i = 0; i < size; i++)
{
Expand Down Expand Up @@ -1449,12 +1460,12 @@ inline Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::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
Expand All @@ -1479,6 +1490,10 @@ inline Matrix<DATA_TYPE, rows, cols>& Matrix<DATA_TYPE, rows, cols>::inverse()
}
}

Point3F pos = -this->getPosition();
mulV(pos);
this->setPosition(pos);

return (*this);
}

Expand Down
48 changes: 34 additions & 14 deletions Engine/source/testing/mathMatrixTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "console/engineAPI.h"
#include "math/mMath.h"
#include "math/util/frustum.h"
#include "math/mathUtils.h"

TEST(MatrixTest, TestIdentityInit)
{
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 4078f3a

Please sign in to comment.