Explorar el Código

inverse fixes

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
marauder2k7 hace 1 año
padre
commit
4078f3ad4e
Se han modificado 2 ficheros con 53 adiciones y 18 borrados
  1. 19 4
      Engine/source/math/mMatrix.h
  2. 34 14
      Engine/source/testing/mathMatrixTest.cpp

+ 19 - 4
Engine/source/math/mMatrix.h

@@ -698,6 +698,17 @@ public:
 
    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; }
@@ -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++)
    {
@@ -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
@@ -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);
 }
 

+ 34 - 14
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)