3D with shading
In the two previous tutorials from the series we saw how to create a basic 3D environment made up of dots. This, although quite fun to play with for a few minutes is never really going to become a proper game. In this tutorial we are going to see how it is possible to create filled shapes and shade them for realism. There is an example at the bottom using matrices with the shading.Shading and Polygons
Adding polygons is the easy part as all we have to do is keep the corners of the polygon grouped together using a method so that we can draw it as one shape. Each point is manipulated as before. We should also create a color value for this shape as our world is not really going to be very interesting with just one colour everywhere. Our goal at hand is to create a realistic three dimensional world as nothing is more interesting than real life.To draw the polygons we have to reach for a tool outside of Visual Basic. We will be using Windows API's for this. An API is one of the many functions which are combined together to make Windows. We will just be using the polygon API for this project which is quite simple. A good list of API's is found on AllAPI.net.
To define an API, more specifically, the API we will be using, we use this code:
Private Declare Function Polygon Lib "gdi32" _
(ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long
Private Type POINTAPI
X As Long
Y As Long
End Type
The function uses this type to hold it's data so we have to define it as well. The function has three pieces of data that must be passed into it. The first one is a reference to an object. This is easy to get as it will be your object's property (if your drawing object is a picturebox or form). The lppoint will be the first item in your array of values for the polygon. nCount is simply the number of points in your polygon. Be careful to make sure you array is big enough for the nCount value as API's can crash you system if abused.
The next step is to sort the polygons into the right order. This is easily done by using a quicksort or similar. I just lifted my sort off something else so I work go through the details of sorting here. I usually sort by finding the average of the z points of the polygon and using that as the depth indicator.
Now we are onto the more advanced bit, the shading. I first did the shading by keeping the lighting effect fixed from the front. i.e. just comparing the angle of the face with the Z axis. This did not look very good as the shading did not change when you moved the camera. I changed the coding so that the camera is the light source.
First we need to work out the normal of out plane. This a the line which is perpendicular to the plane. To get this we use some vector algebra. The thing to remember with vectors is that they only have a size and direction, not a position. We need three points to work out the normal, each with X, Y and Z coordinates.
NormalX = ((y1 - y0) * (z2 - z0)) - ((z1 - z0) * (y2 - y0))
NormalY = ((z1 - z0) * (x2 - x0)) - ((x1 - x0) * (z2 - z0))
NormalZ = ((x1 - x0) * (y2 - y0)) - ((y1 - y0) * (x2 - x0))
Now we have the normal we have to find the angle between this vector and our camera's vector. The camera's vector is easily worked out by just finding the center of the shape (You are at 0,0 so the vector is from 0,0 the the object).
Now we have the two vectors we just need to find the angle between them. This is easily done by more vector algebra.
Shade =
(NormalX * midx + NormalY * midy + NormalZ * midz)
____________________________________________________________
Sqr(midx ^ 2 + midy ^ 2 + midz ^ 2) * Sqr(NormalX ^ 2 + NormalY ^ 2 + NormalZ ^ 2)
This is displayed in shorter algebra.
Shade =
Normal . mid
______________
|normal| * |mid|
|vector| is just the length of the vector. We can easily use pythagoras's theorem for this. The dot product just multiplies each dimension of the vector.
The result we end up with is the cosine of the angle but we have no need to convert it to degrees as it works fine just as it is.
Now you just multiply the color by the shade (assuming you are working in RGB) and hey presto you have a shading algorithm. You may want to lessen the intensity of the shading to make it a bit more realistic.

Download the source code for this tutorial.
previous:3D matrices
© Jonathan Waller 2005; QuantumState Visual Basic




