0
\$\begingroup\$

In my game engine I'm passing a normal matrix to my shaders like so:

Matrix3f normalMatrix = modelMatrix.invert().transpose();

However this is causing lighting to rotate with my object, producing a weird effect.

As I'm not performing any non-uniform scaling, I tried substituting normalMatrix for mat3(modelMatrix), and that worked fine.

Also doing the transpose inverse on the GPU using transpose(inverse(modelMatrix)) worked fine.

This has lead me to believe there is a bug in my invert() and transpose() functions.

According to some math websites, when the modelMatrix lacks any non-uniform scaling, calling inverse().transpose() on it will produce the exact same matrix.

However in my code the output is far from the same:

modelMatrix


0.25    0      0      2353.3474
0       0.25   0      0
0       0      0.25   51.86973
0       0      0      1


normalMatrix = new Matrix3f(modelMatrix).invert().transpose()

4.0 0.0 0.0 
0.0 4.0 0.0 
0.0 0.0 4.0 

Would anyone be able to shed some light on this issue... (I don't want to just stick with modelMatrix because I do want to support non-uniform scaling in the future)

Here are some screenshots describing the issue:

These are two frames of my planet as it rotates. The light source appears to be rotating with it (it shouldn't be). Using the modelMatrix instead of normalMatrix solves the issue. These are two frames of my planet as it rotates The light source appears to be rotating with it (it shouldn't be). Using the <code>modelMatrix</code> instead of <code>normalMatrix</code> solves the issue

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

According to some math websites, when the modelMatrix lacks any non-uniform scaling, calling inverse().transpose() on it will produce the exact same matrix.

This is slightly incorrect. Let's define N as M.inverse().transpose(). Then N = M is true only if M is a rotation matrix. If M has uniform scaling, the resulting matrix N will be different. However when transforming vertices with matrix N, the resulting vectors will have the same direction as with M but different magnitude. If you normalize the vectors after the transformation, the results will indeed be the same. With non-uniform scaling this is no longer enough. As a summary:

  • If all you have is rotation, you don't need a separate normal matrix.
  • If you have rotation and uniform scaling, you don't need the normal matrix either, but you need to normalize the transformed normals.
  • If you have non-uniform scaling / shearing, you need to calculate normal matrix with the transpose of the inverse.

The output from your normal matrix calculation looks correct.

Also doing the transpose inverse on the GPU using transpose(inverse(normalMatrix)) worked fine.

Is this a typo? You are using the normal matrix calculation for the normalMatrix, which results in the original matrix.

Based on the given information it's hard to guess what is wrong. Note that normal matrix is 3x3 whereas your model matrix is 4x4. Try to reduce the model matrix to 3x3 as the first thing by discarding the w components. It's also possible that you are passing the normal matrix incorrectly to the GPU. You might need to add more information / screenshots to the question.

\$\endgroup\$
2
  • \$\begingroup\$ Yes whoops, in my testing i sent the modelMatrix to my shader but I kept using the name normalMatrix so it is effectively transpose(inverse(modelMatrix)). Thanks for that info I'll look over my code again. \$\endgroup\$
    – neon64
    Commented Apr 20, 2015 at 7:56
  • \$\begingroup\$ As for passing the matrices to the GPU, I'm using the following code: glUniformMatrix4(location, false, matrixBuffer); \$\endgroup\$
    – neon64
    Commented Apr 20, 2015 at 8:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .