Fig 7.1
Directional Light
Directional lights have direction and colour but no position, an example of a directional light would be something like the sun. All objects in your scene will receive the same light from the same direction. Directional lights do not have range or attenuation attributes. Fig 7.2 below, shows how light is emitted from a directional light.
Fig 7.2
Spotlight
An example of a spot light would be something like a torch. Spotlights have position, direction, colour, attenuation and range. For a spotlight you can define an inner and outer cone each of which has a light value that is blended between the two. You define the cones by specifying their angle, the inner cone's angle is known as Theta and the outer cone's angle is known as Phi. You define how the illumination between a spotlight's inner and outer cone changes by specifying the lights Falloff property. Fig 7.3 below, shows how light is emitted from a spot light.
Fig 7.3
All lights add a computational overhead to your application, some more than others. The light with the least overhead is ambient light, followed by directional lights, then point lights and finally, the lights with the most overhead are spot lights. Think about this when you are deciding what lights to use in your application.
What is a material? Well, a material describes how light is reflected from an object (polygon). You can specify how much light is reflected, this can make the material seem shiny or dull and can give an object colour. There are a number of settings that you can change for a given material, they are listed below:
Diffuse Reflection
This is the amount of diffuse light that the object will reflect. This is a colour value, so you can specify that the object will only reflect red diffuse light. This will make the object look red in colour.
Ambient Reflection
This is the amount of ambient light that the object will reflect. This is a colour value, so you can specify that the object does not reflect ambient light at all. This means that the object will not be seen unless it receives another type of light such as diffuse light.
Specular Reflection and Power
This is the amount of specular light that is reflected. You can use the specular reflection and power settings to create specular highlights which will make the object seem shiny.
Emission
You can also make the object appear to emit light by changing the Emissive property. The object does not acually emit light, therefore other objects in the scene will not be affected by this setting.
What is a Normal? Well, the Normal of a polygon is a perpendicular vector from the face of the polygon. The direction of this vector is determined by the order in which the vertices were defined. Fig 7.4 below, shows the normal for a polygon, the vertices have been defined in a clockwise direction. The Normal of a vertex is usually the average of each of the normals of each polygon that shares that vertex. Fig 7.5 below shows the cross section of four polygons and their normals (light red). It also shows the normals for each of the three vertices (red). Normals are used for a number of things but for this tutorial we will use them for light shading.
Fig 7.4
Fig 7.5
In the code for this tutorial, we will have one point light and we'll set the ambient light level pretty low so that the effects of the point light are more obvious. We will also set the material for our objects to be fairly normal and not too reflective (no specular highlights).
Step 1: Modify FVF and Custom Vertex
The first thing to do is to modify our FVF and custom vertex structure. In the FVF we need to remove the D3DFVF_DIFFUSE flag and replace it with the D3DFVF_NORMAL flag. Then in the custom vertex structure, we need to remove the colour attribute and replace it with a Normal attribute. Notice that the texture attributes and flags are specified last. if you don't specify these values last, you may get some strange effects.
//Define a FVF for our cuboids
#define CUBOID_D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
//Define a custom vertex for our cuboids
struct CUBOID_CUSTOMVERTEX {
FLOAT x, y, z; //Position of vertex in 3D space
FLOAT nx, ny, nz; //Lighting Normal
FLOAT tu, tv; //Texture coordinates
};
Step 2: Creating the lights
We need to add a new method to CGame called InitialiseLights. We will put all of our light setup code here. First of all, we'll setup a point light for our scene. To do this we need to populate a D3DLIGHT8 structure with the correct values. To specify that this is a point light we need to use the D3DLIGHT_POINT constant. If you want a directional light use D3DLIGHT_DIRECTIONAL or for a spot light use D3DLIGHT_SPOT. Next, we need to set what light our light will emit. So we must specify the Diffuse, Ambient and Specular RGB values. Note that the values for each RGB element should be between 0 and 1, where 0 is none and 1 is full. Next is the position in 3D space, which is a simple x, y, z value. Finally we set the lights range and attenuation. By specifying that this light has an attenuation value of 1 means that the light will not fade over distance.
Now that we have specified our light, we need to add it to our scene and enable it. To do this we must assign it to our device's light list. We do this my using the SetLight method passing in the position in the list as the first parameter. This is a zero based list, so the first position is index 0. Then, to enable the light (turn it on), we use the LightEnable method. The first parameter is the lights index in the light list and the second parameter defines if we should turn the light on or off (TRUE = on, FALSE = off).
We then call SetRenderState to make sure that lighting in general is enabled. Finally, we call SetRenderState again to setup the ambient light level for the whole scene.
D3DLIGHT8 d3dLight;
//Initialize the light structure.
ZeroMemory(&d3dLight, sizeof(D3DLIGHT8));
//Set up a white point light at (0, 0, –10).
d3dLight.Type = D3DLIGHT_POINT;
d3dLight.Diffuse.r = 1.0f;
d3dLight.Diffuse.g = 1.0f;
d3dLight.Diffuse.b = 1.0f;
d3dLight.Ambient.r = 0.0f;
d3dLight.Ambient.g = 0.0f;
d3dLight.Ambient.b = 0.0f;
d3dLight.Specular.r = 0.0f;
d3dLight.Specular.g = 0.0f;
d3dLight.Specular.b = 0.0f;
d3dLight.Position.x = 0.0f;
d3dLight.Position.y = 0.0f;
d3dLight.Position.z = –10.0f;
d3dLight.Attenuation0 = 1.0f;
d3dLight.Attenuation1 = 0.0f;
d3dLight.Attenuation2 = 0.0f;
d3dLight.Range = 100.0f;
//Assign the point light to our device in poisition (index) 0
m_pD3DDevice->SetLight(0, &d3dLight);
//Enable our point light in position (index) 0
m_pD3DDevice->LightEnable(0, TRUE);