diego.martinez
diego.martinez

Reputation: 1051

normal matrix for non uniform scaling

Im trying to calculate the normal matrix for my GLSL shaders on OpenGL 2.0.

The theory is : a normal matrix is the top left 3x3 matrix of the ModelView, transposed and inverted.

It seems to be correct as I have been rendering my scenes correctly, until I imported a model from maya and found non-uniform scales. Loaded models have a weird lighting, while my procedural ones are correct, so I put my money on the normal matrix calculation.

How is it computed with non uniform scale?

Upvotes: 3

Views: 4208

Answers (2)

Jacajack
Jacajack

Reputation: 779

I would just like to add a practical example to Reto Koradi's answer.

Let's assume you already have a 4x4 model matrix and want to use it to transform normals as well. You can start by deducing scale in each axis by taking length of the 3 first columns of that matrix. If you now divide each column by its corresponding scaling factor, the matrix will no longer affect model's scale, because the basis vectors will have unit length.

As you pointed out, normals have to be scaled by the inverse of the scale in each axis. Fortunately, we have already derived the scale in the first step, so we can divide the columns again.

All that effectively means that if you want to derive transform matrix for normals from your model matrix, all you need to do is to divide each of its first three columns by their lengths squared (which can be rewritten as dot products). In GLSL you would write:

mat3 mat_n = mat3(mat_model);
mat_n[0] /= dot(mat_n[0], mat_n[0]);
mat_n[1] /= dot(mat_n[1], mat_n[1]);
mat_n[2] /= dot(mat_n[2], mat_n[2]);
vec3 new_normal = normalize(mat_n * normal);

Upvotes: 1

Reto Koradi
Reto Koradi

Reputation: 54642

You already figured out that you need the transposed inverted matrix for transforming the normals. For a scaling matrix, that's easy to calculate.

A non-uniform 3x3 scaling matrix looks like this:

[ sx  0   0  ]
[ 0   sy  0  ]
[ 0   0   sz ]

with sx, sy and sz being the scaling factors for the 3 coordinate directions.

The inverse of this is:

[ 1 / sx  0       0      ]
[ 0       1 / sy  0      ]
[ 0       0       1 / sz ]

Transposing it changes nothing, so this is already your normal transformation matrix.

Note that, unlike for example a rotation, this transformation matrix will not keep vectors normalized when it is applied to a normalized vector. So after applying this matrix in your shader, you will have to re-normalize the result before using it for lighting calculations.

Upvotes: 4

Related Questions