0
\$\begingroup\$

I'm into shader language with Webgl and GLSL. I've seen some tutorial about normal matrix and I don't really understand it. I mean, I think I'm ok with the math such as:

modelViewMatrix = mat4.multiply(camera.view, modelMatrix);
inverseModelViewMatrix = mat4.invert(this.modelViewMatrix);
normalMatrix = mat3.fromMat4(inverseModelViewMatrix);
normalMatrix = mat3.transpose(this.normalMatrix);

But why do I need it? Where can I find a case where I can see the difference between using it and not using it? Ot when do I don't need it?

\$\endgroup\$
  • 1
    \$\begingroup\$ This is for lighting calculations. Most lighting effects work in Eye space, that is that the calculations base the result on where the camera is looking from. Specular lighting is the first calculation like that that you will encounter. This inverse+transpose is a mathematical hack that moves the local Normal to an Eye space normal for those calculations and is required to keep the Normal vector normalized through the rotations. \$\endgroup\$ – Patrick Hughes Feb 25 '19 at 18:09
  • 1
    \$\begingroup\$ @PatrickHughes On a second reading, it looks like you might be thinking of a TBN matrix for unpacking a tangent space normal map into the shading space (eg. eye space). What's shown here is using the model's inverse transpose to transform normals in the presence of non-uniform scale. It does not guarantee that the normal remains unit length, only that its direction remains perpendicular to the surface. \$\endgroup\$ – DMGregory Feb 26 '19 at 2:18
2
\$\begingroup\$

You need to use a different matrix to transform your normal vectors when your model's transformation might include non-uniform scale.

When we stretch a shape along, say, just the y axis, the y coordinate of all of the vertices gets exaggerated, making the object taller.

This doesn't just elongate the model - it also changes the orientation of the faces. Faces that run diagonal to the stretched axis end up tilting further away from that axis. As the model gets taller vertically, its normals start to point out more horizontally.

Diagram illustrating how normals scale opposite the model

(Diagram from this article explaining how the inverse transpose matrix is used for transforming normals. Notice how as the model gets taller, the normal gets flatter.)

So this gives us a conundrum: the y coordinate of the vertices needs to get bigger, but the y coordinate of the normals needs to get smaller.

If we neglect this detail and just use the same model matrix for transforming both the vertices and the normals, the shading we get will be subtly wrong. Things like specular highlights will bunch up on the skinny poles of the object, instead of spreading across its elongated sides.

The inverse transpose of the model view matrix - what you've called the Normal matrix here - computes exactly the transformation we need to adjust the normals correctly. By inverting it, we "undo" the scaling factors and the rotation. By transposing it, we "undo" the undone rotation (the inverse of a rotation matrix is its transpose), getting us back to the rotation we started with, but still with the scaling factors inverted as desired.

\$\endgroup\$
  • 1
    \$\begingroup\$ The one trick to note here is that for just rotation (i.e. no scaling or shearing), is that the 'inverse transpose' gives you back the original matrix. That is why you'll often see normals transformed by the upper 3x3 of a standard 4x4 matrix if the programmer knows it is just a rotation. \$\endgroup\$ – Chuck Walbourn Feb 26 '19 at 4:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.