OpenGL Normal Vector Transformation

Related Topics: OpenGL Transformation, OpenGL Matrix, Plane Equation


This page explains why transforming a normal vector from object space to eye space is;

When lighting is enabled in OpenGL, the normal vectors are used to determine how much light is received at the specified vertex or surface. This lighting processing is performed at eye coordinate space, therefore, normal vectors in object coordinates are also transformed to eye coordinates with GL_MODELVIEW matrix.

However, normal vectors are transformed in different way as vertices do. We cannot simply multiply GL_MODELVIEW matrix and normal vectors. Consider a normal vector (1,0,0) for a vertex (0,0,0). If GL_MODELVIEW matrix is simply translating 2 unit up along Y-axis, then the vertex coordinates will be (0,2,0). But, the normal vector should remain same as (1,0,0), not (1,2,0).

In order to understand how normal vectors are transformed to eye space, think the normals as coefficients of plane equations, which are perpendicular to the planes.

OpenGL Normal Vector
OpenGL Surface Normal Vector

Imagine a triangle polygon with 3 vertices; v1-v2-v3, and the normal of this surface is 4D normal vector as a homogeneous plane. (For Euclidean space, the normal is 3D normal vector.) If we think of the triangle as a homogeneous plane, then the plane equation becomes;
plane equation in 4D

Since 3 vertices lie on this plane, the plane equation is also true when we substitute these vertices to the equation. For example, for a vector on a plane, it satisfies;
a vector on plane equation

The equivalent matrix form of the plane equation is;
matrix form of plane equation

The plane equation is multiplying the transposed normal (nT) and the vertex (v) together. You can read "The vertex v in object space lies on the plane with the normal normal vector n".

Now, we modify the above equation to acquire normal vector transformation formula by inserting GL_MODELVIEW matrix M-1M in between nT and v ;
(Note that the following equation is still equivalent to the above because M-1M is identity matrix.)
matrix form of plane equation

As you can see, the right part of the above equation view matrix is the vertex in eye space because it is transformed by MODELVIEW matrix M, and the left part normal transform is going to be the normal vector in eye space because this plane equation is also transformed.

It reads the above equation as "The transformed vertex view matrix lies on the transformed plane in eye space with the transformed normal normal transform".

Therefore, transforming a normal from object space to eye space with GL_MODELVIEW matrix M is;
Transforming Normal

Or, by converting pre-multiplication to post-multiplication form, we get;
Transforming normals

Case Study: Translation Only

Suppose a normal vector is (0, 0, 1) and the matrix has only translation part, moving to (1, 2, 3). The translation matrix, its inverse and transpose matrix inverse and transpose matrix and transformed normal would be;
translation matrix,     inverse matrix,     inverse transpose matrix

transformed normal

The normal vector remains unchanged (0, 0, 1) after translation. Therefore, it works as supposed to be if the matrix has translation only. Note that nw component is changed to -3, but it doesn't affect the direction and length of the normal vector.

Case Study: Rotation Only

If the transform matrix contains rotation only, the normal vectors are also rotated same as vertices do. The following is the matrix rotating 30 degree along X-axis, and transforming a normal vector (0, 0, 1) multiplying by the inverse and transpose matrix should become (0, -0.5, 0.866).
translation matrix, inverse matrix, inverse transpose matrix

transformed normal

Note that the rotation-only matrix is unchanged after invert and transposed because it is an orthogonal matrix. (The inverse matrix is equal to the transpose matrix) Therefore, we don't need to compute the inverse and transpose process if the matrix has rotation only. We can multiply the transform matrix directly for normal vectors.

Case Study: Scaling Only

Consider tramsforming a normal vector (0, 0.6, 0.8) by scaling (2, 4, 5). The transform matrix and the transformed normal with the inverse and transpose matrix follow;
translation matrix, inverse matrix, inverse transpose matrix

transformed normal

Note that the transformed normal vector is not unit length any more, plus its direction is also changed because of non-uniform scaling. Therefore, we need to re-normalize the normal vector in order to make it unit length.

What would be the result if the scale factor is -1, for example, scaling by (1, 1, -1)? See the visual result here.


Transforming a normal vector from object space to eye space multiplying by inverse and transpose matrix would work if the transform matrix contains translation and rotation. However, if the transform has scaling, the normal vector must be re-normalized to make it unit length.

Since a rotation-only matrix is orthogonal (the inverse matrix and transpose matrix are same, so the original matrx and the inverse then transpose matrx are also identical), we can skip the process to invert and to transpose the matrix.

To optimize the performance of normal transformations, it would be better to define a separate matrix for the normal vectors, which is only containing the rotation parts from GL_MODELVIEW matrix (ignoring translation and scaling), and use this matrix to transform normal vectors from object space to eye space without computing inverse and transpose.

Hide Comments
comments powered by Disqus