Fast Phong Shading

Fast Phong Shading


The basic Phong shading technique tends to be very slow. However, it can look really good, and so it has been the subject of much optimisation. It's only possible to optimise the origional algorithm so far. No matter how much Fixed Point maths and lookup tables you throw at it, it still runs too slowly to make it a realistic option for realtime graphics.

A document has been circulating for some time under the name of OTMPHONG.DOC. It suggests that instead of interpolating the normal vector across the polygon, you should interpolate the angle between the light source and the normal. This is a nice idea except for the fact that it doesn't really work. It is essentially a repeat of Gouraud shading, and of little use to anyone.

Except that this gave me an idea which I later discovered people had already suggested. I have heard this explained in several ways, all of which are essentially equivalent. I considered that rather than simply interpolate an angle across the polygon, it might be possible to interpolate two. This would be very similar to interpolating a vector. Now, rather than do some horrid calculations with these two angles, you might as well consider them to be texture coordinates and lookup the result of the calculations in a texture map.

This is really a big step in the life of realtime graphics. No longer must we put up with dodgy Gouraud shading. We can now enjoy the full benefits of Phong shading from the comfort of our home computers. Phong shading is now just linear texture mapping, which, thanks to the likes of Michael Abrash, can be done very quickly indeed.

The Phong Map

It just so happens that the texture map you need is a very simple one. This is a convenient 256x256 texture which you can take and use if you want. I must confess I very rudely stole this image from Tom Hammersley's Graphics Coding Page. I hope he doesn't mind. You may want to generate your own however. It's quite simple to get your program to create one, or you can make various deviations to give different effects. For example, you might try an image with rings of bright colour to give the appearence of a chrome object.

OK, so how to actually do this. I haven't done a vast amount of investigation here, and the only way I have come up with so far has been a teeny bit slow, although I am sure there is a faster method. If anyone knows one, I would be happy to know what it is.

So, for each vertex of the polygon to be rendered, you will need to calculate the coordinates to the Phong Map.

You have a polygon. For this polygon, define two vectors which are at right angles to each other and to the surface normal. Call them V and H. These two vectors represent the (u,v) coordinates of the phong map.

Now we'll look at this polygon at an angle so the vector from the light source to the vertex can be seen. This is vector L.

The aim is to calculate the coordinates (u,v) in terms of V, H and L

The algorithm is a very simple one. If the phong map is 256x256 and centered then:

u = ( V . L ) * 128 + 127
v = ( H . L ) * 128 + 127

do this for each vertex, and then map the Phong map onto it, and there you have one nicely phong shaded polygon.

Since this can be slow, there are various ways you can speed it up if you don't mind a little loss of freedom. If you assume that the light source is at the same place as the camera, then you can ignore the V and H vectors altogether. Instead take the X and Y components of the normal vector, multiply by 128 and add 127 (assuming that is that the magnitude of the normal vector is 1).

Alternatively, you can take the light source as being like an inverse camera. Transform the object as if the light source were the camera, and calculate the phong as in the previous paragraph.


Notes on Fake Phong Shading

As you would probably expect, this method is not perfect. The fact that the Phong Map has a limited resolution means that sometimes the highlights on an object will look a little pixelated. This will not really be noticable though if the object is spinning or moving quickly. If you add bump mapping, the effect will be barely noticable.

One artifact of the technique is that you get the effect of 2 light sources. The first will be where you expected it to be. The other will appear to be on the other side of the object. This is possible to overcome, and I will explain how to do this later, and how to make that extra light a different colour if you want.

If you're really clever with a bump map, you can turn it into a shinyness map too. It is possible to have, say, an object with diffuse bits and chrome bits, all controled by the bump map. I'll get onto this n the next article on Bump Mapping.