Per vertex shading, otherwise known as Gouraud shading, helps us achieve smooth shading results with relatively low computational demands. The idea is really simple, yet I haven’t seen a lot of information about it on the Internet, so I’ve decided to post about it myself.
Let’s imagine we want to display a simple 3D model using OpenGL. The model is made up from a large number of triangles or quadrilaterals (quads). I’ll refer to both as faces from now on. If you want to do any kind of shading, the first thing you need to do is calculate the normal of each face. A normal is simply a vector that is perpendicular to the face (imagine an arrow pointing outwards from the face). However, since we calculate each normal of face independently from other faces, the boundaries between the faces are very noticeable. This ruins the effect of a smooth surface as shown on the following image of a DC-10. You can very easily see the faces that make up the plane.

DC-10 model without per vertex shading
The process of calculating vertex normals is as follows: after we’ve calculated (and normalized) a normal vector for every surface of our object, we iterate through all the vertexes. For each vertex, we determine all neighbouring polygons. In other words, we have to find all the polygons that contain our given vertex. There are many approaches to this. There is of course a brute force approach where you check every vertex against every polygon. Although this might do for simple object or as part of a preprocess one time calculation, it’s not very practical. A better approach is to store neighbouring information for each polygon. If you can’t afford that, you could also generate a bounding box or a bounding sphere for each face. Looking for neighbouring polygons should be simple afterwards.
Anyway, after we’ve found the neighboring polygons, we have to calculate the average of all of their normal vectors. This is again very simple to do. Just separately sum up all the X, Y and Z values of all neighboring polygons and then divide by the number of such polygons. Save this averaged normal vector to our current vertex, repeat for all the remaining vertexes and you’ve just done your first per vertex shading. When it comes to the actual drawing, use glNormal3f(nx, ny, nz) before each glVertex3f command (with nx, ny and nz obviously being individual values that make up the normal vector). The result? A much smoother looking object. Add couple of textures and you’ve got yourself a nice looking model.

DC-10 model with per vertex shading
As we’ve seen, per vertex shading is very easy to do and offers nice results. However, when working with animated models, per vertex shading (as shown above) is totally useless as it’s simply not fast enough for any real-time animation (short of displaying a rotating cube in empty space). Vertex programming is the magic word when we want more advanced results. If you want to do it using OpenGL, take a look at the NV_vertex_program (or vertex shaders if you fancy DirectX). You should note that any serious shading done today is directly on the GPU. Most other methods are for educational purposes only as they help to explain certain graphical and geometrical principles. A topic for one of my future posts maybe. In the mean time, have fun with the above tips. If I haven’t explained it in enough detail, let me know and I can paste some actual code.
Denis