Gouraud shading is a method for linearly interpolating a colour or shade across a polygon. It was invented by Gouraud in 1971. It is a very simple and effective method of adding a curved feel to a polygon that would otherwise appear flat. It can also be used to depth que a scene, giving the appearance of objects in the distance becoming obscured by mist. I suggest you also read the page on light sourcing if you do not already know the principles.
On the left is a curved surface rendered using flat shaded polygons, the other is Gouraud shaded. It is quite clearly smoother and more attractive and well worth spending the time to code.
Unlike a flat shaded polygon, you can specfy a different shade for each vertex of a polygon, the rendering engine then smoothly interpolates the shade across the surface. The technique is very similar to the standard scan converting, and can be handled very quickly with integer maths.
Some points to note though: It is best to restrict gouraud shading to three sided polygons. Sometimes polygons may not look quite as you expect when they have more than three vertices with very different shades.
Now, before the horizontal strip is rendered to the screen, some small adjustments need to be made. It will help to have a picture here to clarify what's going on.
So, how to make this adjustment. Firstly calculate the gradient of shade across the line as usual:
Gradient = (Bs - As) / (Bx - Ax)
Where As = shade at A, and Ax is the X value of A. Now calculate the exact value of the shade at C:
Cs = As + (1-frac(Ax))*Gradient
So, now you need to be able to render a strip of Gouraud polygon to the screen. This involves calculating the shade of each pixel and writing it to the screen. This is a simple process, since the shade changes linearly across the scanline. The process can be demonsrtated by a little pseudocode.
Shade = Cs loop X from Cx to Dx plot pixel at (X,Y) with colour Shade Shade = Shade + Gradient End of X loopAs usual, it's possible to reall crank up the speed of this algorithm by writing it in machine code. The algorithm given below will only really work on a PC in an 8-bit screen mode, but of course there are other methods for other platforms. Please note that this method is not perfect and will not produce perfect results where the rate of change of shade across a polygon is very small. But it is fine for most cases and faster than a Breshenham type mothod.
This method relies on the fact that the x86 series chips have 16 bit registers that can be treated as two 8 bit registers. In this implementation, the highest 8 bits of a regester are used as the integer part of the shade being interpolated, and the lower 8 bits are used as the fractional part.
This inner loop given just renders one horizontal strip of a polygon in an 8 bit screen mode. It uses 32 bit memory pointers. Because of the fact that it uses a fixed point value for the shade, it is possible to assign non-integer values for the shade values of the vertices, making for slightly more accurate rendering.
The routine requires a little setup code to begin with:
length = Dx - Cx + 1 ScreenPtr = y*ScreenWidth + CxNow the inner loop:
CX = length AX = Cs * 256 BX = Gradient EDI = ScreenPtr top: mov [edi], ah ;write the pixel to the screen inc edi ;next pixel add ax, bx ;update shade dec cx ;decrement counter jnz top ;loop if more pixels
Imagine you have a large polygon, lit by a light near it's center. The light intensity at each
vertex will be quite low, because they are far from the light. The polygon will be rendered
quite dark, but this is wrong, because it's centre should be brightly lit. You can see this
happening in the game Descent. Firing flares around, especially into corners, causes the
surroundings to light up. But try firing a flare into the middle of a large flat wall or floor,
and you will see that it has very little effect.
However, if you are using a large number of small polygons, with a relatively distant light source, Gouraud shading can look quite acceptable. Infact, the smaller the polygons, the closer it comes to Phong shading.