Transforming Normals

Published on 7/5/2011

I've been thinking about my problems lighting my scene using directional light (the mentioned sunlight system) for a while now.

The screens of the level editor I've posted have hacked code to get it working correctly. I basically passed the original normals straight on to the pixel shader code instead of transforming them.

This means that all the tiles get the same amount of sunlight. It's obviously a problem when you start to rotate stuff, since the shadow areas will change depending on the orientation. Thus I need to transform the normals. However, doing so resulted in very strange results. Tiles to the left were lit differently from tiles to right. It's actually an age-old problem, and perfectly obvious when you visualise the process of the vertex and pixel shaders.

The problem comes in with using the same matrix as the one for the vertex transformations (which, incidentily, all tutorials do). But, this article explains quite clearly that using the main transform matrix as is, is not correct. Also see my news post about the MATHS :)

As the article explains, if you use the correct distinction between points and vectors, the same transform matrix could apply if you don't do any scaling. Which means you modelled everything correctly at the start. But I did a test, and even though you can declare the input to the vertex shader as float4 for the normal, XNA does NOT pass in a normal with the w component. In the .X files, the normals only have three components, and XNA's vertex structures are based around the Vector3 struct. This means the w component does not exist within the C# space. So it's up to you to set w to zero in the shader code for normals (it seems it's set to 1 by default based on my test results).

The conclusion then, is that XNA does not employ "homogenoeus vectors and matrices" at all. So you have to make it do so, otherwise you won't be able to move your models around your world. Well, you will, but it will all be dark.