PDA

View Full Version : A simple question

Lee_Jennifer_82
03-10-2016, 01:36 PM
In vertex shader, vertices are multiplied by MVP (projection*view*model) and passed to the fragment shader.

Why normals are only multiplied by modelview(view*model) instead of MVP?

Is it for proper lighting calculation?

GClements
03-10-2016, 02:19 PM
In vertex shader, vertices are multiplied by MVP (projection*view*model) and passed to the fragment shader.

Why normals are only multiplied by modelview(view*model) instead of MVP?

Is it for proper lighting calculation?
The lighting equations are invariant under affine transformation; rotating and/or translating the vertex positions, normals, light positions, and eye position by the same transformation should have no effect upon the result. This isn't true if the transformation has a projective component. Consequently, neither the normals nor vertex positions used for e.g. specular lighting are transformed by the projection matrix.

In particular, if M is orthonormal, then dot(M*a,M*b) = dot(a,b) for any vectors a and b. Translation doesn't affect direction vectors (with w=0) nor the difference between two vectors: If T is a translation matrix, T*a-T*b = a-b.

This is the main reason why the fixed-function pipeline has separate model-view and projection matrices, and why shaders normally maintain that distinction. The model-view matrix should never contain any projective component; that should only occur in the projection matrix.

And if the model-view matrix contains non-uniform scale or shear components, normals need to be transformed by the inverse-transpose of the model-view matrix. For an orthonormal matrix, the inverse is equal to the transpose, so the normal matrix and model-view matrix are identical. For the combination of an orthonormal matrix and a uniform scale, the inverse and transpose differ only by a scale factor, which isn't relevant if the normals are explicitly normalised in the shader; in the fixed-function pipeline, this can be handed with glEnable(GL_NORMALIZE) or glEnable(GL_RESCALE_NORMAL).