Surfaces are illuminated in your Direct3D application by the lights you create and position. You can use the IDirect3DLight interface to get and set lights. You can create an IDirect3DLight interface by calling the IDirect3D2::CreateLight method.
Lighting is only one of the variables controlling the final appearance of a visible element in a scene. The properties of a surface (including how it reflects light) are determined by materials, which are discussed in Materials. The shading of a surface defines how color is interpreted across a triangle; this is determined by the D3DRENDERSTATE_SHADEMODE render state, in the D3DRENDERSTATETYPE enumerated type. Finally, any texture that has been applied to a visible element also interacts with the lighting to change the object's appearance.
The simplest light type is an ambient light. An ambient light illuminates everything in the scene, regardless of the orientation, position, and surface characteristics of the objects in the scene. Because an ambient light illuminates a scene with equal strength everywhere, the position and orientation of the frame it is attached to are inconsequential. Multiple ambient light sources are combined within a scene.
The color and intensity of the current ambient light are states of the lighting module you can set. You can change the ambient light by using the D3DLIGHTSTATE_AMBIENT member of the D3DLIGHTSTATETYPE enumerated type.
Direct3D supports four specialized light types in addition to ambient lights. These are defined by the D3DLIGHTTYPE enumerated type. You can specify these light types and their capabilities by calling the IDirect3DLight::SetLight method and modifying the values in the D3DLIGHT2 structure.
Point | A light source that radiates equally in all directions from its origin. Point light sources require the system to calculate a new lighting vector for every facet or normal they illuminate, and so are computationally more expensive than a parallel point light source. They produce a more faithful lighting effect than parallel point light sources, however. |
Spotlight | A light source that emits a cone of light. Only objects within the cone are illuminated. The cone produces light of two degrees of intensity, with a central brightly lit section (the umbra) that acts as a point source, and a surrounding dimly lit section (the penumbra) that merges with the surrounding deep shadow. You can specify the angles of each of these two sections by modifying members of the D3DLIGHT2 structure. |
Directional | A light source that is attached to a frame but appears to illuminate all objects with equal intensity, as if it were at an infinite distance from the objects. Directional light has orientation but no position. It is commonly used to simulate distant light sources, such as the sun. It is the best choice of light to use for maximum rendering speed. |
Parallel point | A light source that illuminates objects with parallel light, but the orientation of the light is taken from the position of the light source. For example, two meshes on either side of a parallel point light source are lit on the side that faces the position of the source. The parallel point light source offers similar rendering-speed performance to the directional light source. |
You use the D3DCOLORVALUE structure to specify the color of your lights. For more information, see Colored Lights in the Colors and Fog section.
Your application can use as many lights as the device supports. To find out how many lights a device supports, call the IDirect3DDevice2::GetCaps method and examine the D3DLIGHTINGCAPS structure.
Lighting is computationally intensive. By being careful about how you set up your lighting, you can achieve significant performance gains in your application. For detailed lighting performance information, see Lighting Tips in the Performance Optimization section.
To use a light, you first need to create a D3DLIGHT2 structure and a pointer to a light object.
D3DLIGHT2 light; // Structure defining the light
LPDIRECT3DLIGHT lpD3DLight; // Object pointer for the light
When you have done this, you need to fill in the D3DLIGHT2 structure. The following example defines a white point light whose range is set to 10.0.
memset(&light, 0, sizeof(D3DLIGHT2)); // clear memory
light.dwSize = sizeof(D3DLIGHT2); // required
light.dltType = D3DLIGHT_POINT;
light.dvPosition.x = 0.0f; // set position
light.dvPosition.y = 10.0f;
light.dvPosition.z = 0.0f;
light.dcvColor.r = 1.0f; // set color to white
light.dcvColor.g = 1.0f;
light.dcvColor.b = 1.0f;
light.dvAttenuation0 = 0.0; // set linear attenuation
light.dvAttenuation1 = 1.0;
light.dvAttenuation2 = 0.0;
light.dvRange = 10.0f; // set maximum range
light.dwFlags = D3DLIGHT_ACTIVE; // enable light
The next step is to call the IDirect3D2::CreateLight method to create the light object. For this you need a valid LPDIRECT3D2 interface pointer, lpD3D2.
if ((err = lpD3D2->CreateLight(&lpD3DLight, NULL) != D3D_OK)
return err;
When you have created the light object, you use the D3DLIGHT2 structure you have already filled in to set its properties. Calling the IDirect3DLight::SetLight method associates the D3DLIGHT2 structure with the light object you just created.
if ((err = lpD3DLight->SetLight((D3DLIGHT *)&light)) != D3D_OK)
return err;
Finally, you should call the IDirect3DViewport2::AddLight method to add this light to your current viewport. (Each light source is bound to a single viewport.)
if ((err = lpView->AddLight(lpD3DLight)) != D3D_OK)
return err;
At this point you have a new light working with the current viewport. If you need to make changes to the light's values, simply update the D3DLIGHT2 structure and call the IDirect3DLight::SetLight method again.
After you are finished working with the light, you should call the IDirect3DViewport2::DeleteLight method to remove the light from the viewport, and then call the IDirect3DLight::Release method.
if (lpView) {
lpView->DeleteLight(lpD3DLight);
}
RELEASE(lpD3DLight);