Thursday, March 29, 2012

Part 7: Lighting

For this post, we're going to add basic lighting to the model. This will make the edges pop out and the shape will definitely have a better 3D feel. For this, we will need to add normal data for each vertex. This will allow us to calculate light intensity at each vertex, and the rasterize stage will be able to interpolate those values across the shape. More vertex data means a new attribute, and we'll also need to modify the shaders. Everything else should be unchanged.

I've also compiled what we've done so far, and I put some of the methods in a helper class called GLHelper. Additionally, I dropped the vertex data in a header file. These changes make the Controller's implementation a bit cleaner.

First things first, let's change our CubeVertexData array to incorporate the vertex normals. It would be possible to calculate the normals using the vertex position and a cross product, but we'll keep it simple and just add the data in our array.

We must change the stride since both positions and normals are packed in a single array now. You also need to tell GL where the normals are so that it can pass them to the shader as an attribute.

Since the light must be calculated in eye coordinates, we'll have to split the ModelView and Projection transform matrices. In the shader, we'll transform the positions and the normals to be in eye coordinates, we'll then calculate light, and finally apply the projection matrix.

To transform the normals to eye coordinates, we'll need the Normal Transformation matrix as a uniform, which is calculated using the ModelView transformation matrix. We'll also pass the Light Position as a uniform, that way we can move the light every time we draw if we want to. This is what the uniform loop now looks like:

Finally, here are the modified shaders for basic lighting of our object:

You're right, I've been a bit lazy when pasting my code, and I guess I tried to group pieces that shouldn't be together. I will try to be more clear about where things should go.

As for your second comment, I guess I didn't point it out, but I did some refactors (GLKHelper class) before this post. When I did I thought it would be better to save the number of Uniforms, so I changed my Uniform struct to:

struct{---NumberOfUniforms---struct---{------Name------Location---}}

It's in GLHelper's header file, and NumberOfUniforms is initialized in the CreateProgram method.