Lighting

[Previous] [Next]

Unlike interfaces in earlier versions of DirectX, the IDirect3DDevice7 interface doesn't use COM objects to represent each light. Methods such as IDirect3DDevice7::SetLight now use the D3DLIGHT7 structure to describe a set of lighting properties rather than the lighting semantics that previous versions of the device interface used.

In Direct3D, the light model approximates real-world lighting by calculating the mathematical interaction of a surface's color and the color of light reflecting off that surface. The result of this computation is used as the color to apply to the surface when rendered to the screen. In real life, light bounces (reflects) off thousands of surfaces before it reaches the eye. With each reflection, some of the light is absorbed by the surface it bounces off, some is scattered randomly, and the rest hits the next surface or the eye. This real-life effect of light bouncing until it is seen or it attenuates to 0 is what raytracing algorithms attempt to simulate. Although raytracers create very realistic scenes that approximate what we see in nature, no real-time program can perform these computations (yet). Direct3D uses a simpler approach to provide real-time lighting for performance reasons. In Direct3D, light is defined as the red, green, and blue components that combine to create a specific light color. If you enable lighting in your application, as Direct3D rasterizes a scene in its final stage of rendering, it computes the color of each vertex as a combination of the following:

  • The current material color and the texels in an associated texture map
  • The diffuse and specular components associated with the vertex
  • The color and intensity of the light generated by any light objects in the scene
  • The scene's ambient light level

The diffuse reflectance of a material is the most important component in determining the color of a vertex. Because diffuse light is directional, the angle of incidence for diffuse lights controls the intensity of the reflected light. The diffuse reflection is greatest when the light hits a vertex parallel to the vertex normal. As this angle is increased, the diffuse reflectance decreases. The specular reflection creates highlights on an object's surface, making the object appear shiny.

If you use Direct3D lighting and materials and pass unlit vertices to it, Direct3D performs lighting computations for you. Remember that materials are used to describe how light reflects off surfaces. A polygon's material possesses properties that affect how the polygon reflects the light it receives. A reflectance trait that defines how the material reflects ambient light, as well as other traits that define the material's specular and diffuse reflectance, can be set by our software.

In Direct3D, two light types, direct light and ambient light, are used to describe how light will be reflected. Although you can write your own lighting computations, Direct3D has built-in algorithms that do an excellent job and save you a great deal of time. If you do choose to turn off lighting for vertices that include normals, you would set the D3DRENDERSTATE_LIGHTING render state to FALSE.

You need to consider one important thing when you're using Direct3D's lighting: in Direct3D, lighting is computed only per vertex, not per pixel. Thus, if you shine a spotlight on the middle of a large triangle, it's not going to look pretty. (In fact, this characteristic makes spotlights almost useless unless you happen to have dense vertex distribution.) Many programmers bypass this problem via light mapping, by which the lighting is calculated, often in advance, independently of vertex positions. It is then stored in a sort of monochrome low-resolution texture map that is applied on top of the object's regular texture. Light mapping is a lot more work but it can create much more sophisticated lighting effects because lighting isn't limited to being per vertex.

Ambient Light

Ambient light is light that has no determinable direction or source because it's been scattered so many times. This light produces low-intensity illumination everywhere in a scene. It contains only color and intensity and doesn't add to specular reflection. It is also independent of any light-generating objects that you've placed in your scene.

In previous versions of DirectX, we specified light states and render states. In DirectX 7, all states are render states. You set the ambient light level with a call to the IDirect3DDevice7::SetRenderState method, specifying D3DRENDERSTATE_AMBIENT as the dwRenderStateType parameter and the desired RGBA color as the dwRenderState parameter, as follows:

 // lpD3DDevice is a valid pointer to an IDirect3DDevice7 interface. // // Set the ambient light. D3DCOLOR d3dclrAmbientLightColor = D3DRGBA(1.0f,1.0f,1.0f,1.0f); lpD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT,                             d3dclrAmbientLightColor); 

Each RGBA color component value used to define an ambient light can range from 0 through 255. The D3DRGBA macro creates an RGBA D3DCOLOR value from the red, green, blue, and alpha components you specify. This macro is defined as follows:

 #define D3DRGBA (r, g, b, a) \      ((((long)((a) * 255)) << 24) |      (((long)((r) * 255)) << 16) |      (((long)((g) * 255)) << 8) |      (long)((b) * 255)) 

Direct Light

Whereas ambient light adds simple, general lighting to a scene, direct light simulates light coming from a particular location or direction. This light interacts with a surface's material and changes the surface's color. Direct3D uses its direction when computing Gouraud and other shading. To simplify computation, when a direct light is reflected, it doesn't affect the ambient light level of the scene.

To create a direct light, just define a variable of type D3DLIGHT7 and fill its members. The following code illustrates how to create a point light and fill the diffuse, ambient, and specular RGB values to a value of 1.0. By setting the dvPosition.x, dvPosition.y, and dvPosition.z values, you position the light in the scene.

 // // m_pd3dDevice is a valid pointer to an IDirect3DDevice7 // interface. // D3DLIGHT7 d3dLight; HRESULT   hr; // // Initialize the structure. // ZeroMemory(&d3dLight, sizeof(D3DLIGHT7)); // // Set up for a white point light. // d3dLight.dltType = D3DLIGHT_POINT; d3dLight.dcvDiffuse.r = 1.0f; d3dLight.dcvDiffuse.g = 1.0f; d3dLight.dcvDiffuse.b = 1.0f; d3dLight.dcvAmbient.r = 1.0f; d3dLight.dcvAmbient.g = 1.0f; d3dLight.dcvAmbient.b = 1.0f; d3dLight.dcvSpecular.r = 1.0f; d3dLight.dcvSpecular.g = 1.0f; d3dLight.dcvSpecular.b = 1.0f;   // Position the point light high in the scene and behind the // viewer. These coordinates are in world space, so the // viewer can be anywhere in world space too.  // For the purposes of this example, assume the viewer // is at the origin of world space. d3dLight.dvPosition.x = 0.0f; d3dLight.dvPosition.y = 1000.0f; d3dLight.dvPosition.z = -100.0f;   // Don't attenuate. d3dLight.dvAttenuation0 = 1.0f;  d3dLight.dvRange = D3DLIGHT_RANGE_MAX; // Set the property information for the first light. hr = m_pd3dDevice->SetLight(0, d3dLight); if (FAILED(hr)) {     // Code to handle the error goes here. } 

Color for Lights and Materials

In Direct3D, color is described using four components: red (R), green (G), blue (B), and alpha (A). The D3DCOLORVALUE structure holds the values for each component describing a particular color. Each of its members holds a floating-point value that usually ranges between 0.0 through 1.0 inclusive.

When defining a color for a light, the color values represent the amount of each light component the light emits. Lights use only the three RGB components, and not the A component. A value of 0.0 for an RGB component is equivalent to off, and a value of 1.0 indicates a value of fully on. Combining these values produces a final color for a light. An RGB triplet value of (1.0, 1.0, 1.0) defines a bright white light, (0.0, 0.0, 0.0) defines a light that emits no light, (0.0, 0.0, 1.0) defines a bright blue light, and (1.0, 0.0, 1.0) defines a bright purple light. Other combinations produce other colors of light.

Beyond the typical 0.0 through 1.0 range of values, Direct3D also allows you to specify negative values for the light's color components, so you can create dark lights, which are used to remove light from a scene. Additionally, you can set values greater than 1.0 to define a very bright light.

When describing a color for a material, the color component values define the amount of each light component that is reflected by a surface that uses the material. For example, a material with RGB values of (1.0, 1.0, 1.0) reflects all the light that hits it, and a material with RGB values of (0.0, 0.0, 0.0) reflects no light. So if you shine a red light on an object with a blue material, the object won't be affected by the light.

Types of Lights

Direct3D provides three types of direct lights: directional lights, point lights, and spotlights.

The D3DLIGHTTYPE enumerated type is used to define the light type. This enumerated type is used with the D3DLIGHT7 structure.

 typedef enum _D3DLIGHTTYPE {      D3DLIGHT_POINT         = 1,      D3DLIGHT_SPOT          = 2,      D3DLIGHT_DIRECTIONAL   = 3,      D3DLIGHT_FORCE_DWORD   = 0x7fffffff,  } D3DLIGHTTYPE; 

  • D3DLIGHT_POINT Light is a point source. The light has a position in space and radiates light in all directions.
  • D3DLIGHT_SPOT Light is a spotlight source. This light is something like a point light except that the illumination is limited to a cone. This light type has a direction and several other parameters that determine the shape of the cone it produces. For information about these parameters, see the D3DLIGHT7 structure.
  • D3DLIGHT_DIRECTIONAL Light is a directional source. Using this light type is equivalent to using a point light source at an infinite distance.
  • D3DLIGHT_FORCE_DWORD Forces this enumerated type to be 32 bits.

Directional Lights

Directional lights represent lights that are at an effectively infinite distance (for example, the sun) and thus have only color and direction, not position. These lights give off parallel light so that all the light they produce moves through a scene in the same direction. These lights are not affected by attenuation or range. Because of this, Direct3D uses only the color and direction you define for computing vertex colors. These lights are the least computationally intensive lights available in Direct3D, so using them strategically can help accelerate your applications.

Point Lights

Point lights are lights that give off light in all directions equally from a particular point, as shown in Figure 5-8.

Figure 5-8 Point light

The point light's position in world space and the coordinates of a vertex being lit are used to compute a vector defining the light's direction and the distance the light has traveled. These are also used, along with the vertex normal, to compute how the light affects the illumination of a surface. An example of a point light is a standard light bulb. These light types are affected by attenuation and range, and they illuminate any 3D object meshes they affect.

Spotlights

Spotlights are used to simulate real-world lights that have both a point of origin and a direction, such as a desk lamp or a car's headlights. In Direct3D, spotlights produce a light as illustrated in Figure 5-9.

The light that a spotlight emits is composed of a bright inner cone and a larger outer cone, with the light intensity diminishing between the two. Spotlights are affected by falloff (light attenuation that occurs between a spotlight's inner and outer cones), attenuation, and range, which, together with the distance light travels to each vertex, are used in the computation of lighting effects for objects in a scene.

Spotlights are the most computationally expensive of the Direct3D Immediate Mode lights, so you should use these only when you find the realistic lighting that spotlights produce important enough to your application to be worth the computational cost.

click to view at full size.

Figure 5-9 Spotlight

Light Properties

You use light properties to define a light's type and color and, for some lights, also the position, direction, attenuation, range, and spotlight effects. These properties control how the light illuminates the contents of a scene. The D3DLIGHT7 structure is used to describe the light properties for all the available light types.

Here's the D3DLIGHT7 structure you use for defining the light type:

 typedef struct _D3DLIGHT7 {     D3DLIGHTTYPE    dltType;                 D3DCOLORVALUE   dcvDiffuse;              D3DCOLORVALUE   dcvSpecular;             D3DCOLORVALUE   dcvAmbient;              D3DVECTOR       dvPosition;              D3DVECTOR       dvDirection;             D3DVALUE        dvRange;                 D3DVALUE        dvFalloff;               D3DVALUE        dvAttenuation0;          D3DVALUE        dvAttenuation1;          D3DVALUE        dvAttenuation2;          D3DVALUE        dvTheta;                 D3DVALUE        dvPhi;               } D3DLIGHT7, *LPD3DLIGHT7; 

ParameterDescription
dltTypeType of the light source. This value is one of the members of the D3DLIGHTTYPE enumerated type.
dcvDiffuseDiffuse color emitted by the light. This member is a D3DCOLORVALUE structure.
dcvSpecularSpecular color emitted by the light. This member is a D3DCOLORVALUE structure.
dcvAmbientAmbient color emitted by the light. This member is a D3DCOLORVALUE structure.
dvPositionPosition of the light in world space. This member has no meaning for directional lights.
dvDirectionDirection the light is pointing in world space. This member has meaning only for directional and spotlights. This vector doesn't need to be normalized, but it should have a nonzero length.
dvRangeDistance beyond which the light has no effect. The maximum allowable value for this member is D3DLIGHT_RANGE_MAX, which is defined as the square root of FLT_MAX. This member doesn't affect directional lights.
dvFalloffDecrease in illumination between a spotlight's inner cone (the angle specified by the dvTheta member) and the outer edge of the outer cone (the angle specified by the dvPhi member). The effect of falloff on the lighting is subtle. Furthermore, a small performance penalty is incurred by shaping the falloff curve. For these reasons, most developers set this value to 1.0.
dvAttenuation0, dvAttenuation1, and dvAttenuation2Values specifying how the light intensity changes over distance. (Attenuation doesn't affect directional lights.) These members represent a light's constant, linear, and quadratic attenuation factors. Valid values for these members range from 0.0 to infinity, inclusive.
dvThetaAngle, in radians, of a spotlight's inner cone—that is, the fully illuminated spotlight cone. This value must be between 0 and the value specified by the dvPhi member.
dvPhiAngle, in radians, defining the outer edge of the spotlight's outer cone. The spotlight doesn't light points outside this cone. This value must be between 0 and pi.

Light Attenuation

Attenuation is how a light's intensity decreases as it reaches the maximum distance you define with the range property. Three of the D3DLIGHT7 structure members—dvAttenuation0, dvAttenuation1, and dvAttenuation2—define the light attenuation effects. These members usually range from 0.0 through 1.0 and are used to define the constant, linear, and quadratic attenuation for a light. If you set the dvAttenuation1 member to 1.0 and the dvAttenuation0 and dvAttenuation2 members to 0.0, the light intensity will attenuate evenly over distance from maximum intensity at the source to zero intensity at the maximum range.

Light Color

You set the color of a light by using the color property in the dcvDiffuse, dcvSpecular, and dcvAmbient members of the D3DLIGHT7 structure. These members specify RGBA color defining the diffuse, specular, and ambient colors for the object. The dcvDiffuse variable defines the diffuse color emitted by the light, the dcvSpecular variable the specular color, and the dcvAmbient variable the ambient color.

As mentioned earlier, the RGB values typically range from 0.0 through 1.0 (the alpha value is unused), but you can specify numbers below 0.0 for dark lights or greater than 1.0 for very bright lights.

Light Direction

You use this property to define the direction that light emitted by the object travels. Only directional lights and spotlights use it. The direction is defined using a D3DVECTOR structure in the dvDirection member of the light's D3DLIGHT7 structure. The direction vector is the distance from an origin. As an example, an overhead light could be defined using a directional light with a direction of <0,-1,0>.

Light Position

You define the light position by using a D3DVECTOR structure in the dvPosition member of the D3DLIGHT7 structure. The coordinates are defined in world space. Remember that directional lights don't use the position property because the light hits all objects at the same angle.

Light Range

You use the light range property to define the distance (in world space) at which the meshes are no longer affected by the light an object emits. The dvRange member defines the light's maximum range in world space. You typically set this range to the maximum possible value, D3DLIGHT_RANGE_MAX. Directional lights don't use the range property.

Light Type

You use the light type property to define the Direct3D light object type. You set the light type with a value from the D3DLIGHTTYPE enumeration in the dltType member of the light's D3DLIGHT7 structure. This light can be any of the three types described earlier: directional lights, point lights, and spotlights.

Spotlight Properties

Only spotlights use the final three properties in the D3DLIGHT7 structure: dvFalloff, dvTheta, and dvPhi. You use these members to define the size of a spotlight's inner and outer cones and to indicate how light decreases between them. (Refer to Figure 5-9 to see how spotlights emit light.)

The dvFalloff member defines how the light intensity decreases between the outer edge of the inner cone and the inner edge of the outer cone. Setting dvFalloff to 1.0 causes the falloff to transition evenly between the two cones. The dvTheta value describes the radian angle of the spotlight's inner cone. The dvPhi value describes the angle for the outer cone.

Setting the Light's Properties

To set the preceding properties for a direct light you've created, you use the IDirect3DDevice7::SetLight method. Here's the function declaration for this method:

 HRESULT IDirect3DDevice7::SetLight(     DWORD dwLightIndex,      LPD3DLIGHT7 lpLight ); 

The IDirect3DDevice7::SetLight method has a parameter, lpLight, which is the address of a D3DLIGHT7 structure used to set the current light data. You set the light's properties by filling a D3DLIGHT7 structure and then calling the IDirect3DDevice7::SetLight method with the address of a filled D3DLIGHT7 structure. The dwLightIndex parameter defines the index that specifies which light in the scene you're working with.

The following code segment shows how to set up properties for a white point light that doesn't attenuate over distance. It then uses the IDirect3DDevice7::SetLight method to enable these new properties.

 //  g_lpd3dDev variable is a valid pointer to an IDirect3DDevice7  //  interface. D3DLIGHT7 d3dLight; HRESULT   hr;     // Initialize the structure. ZeroMemory(&d3dLight, sizeof(D3DLIGHT7)); // Set up for a white point light. d3dLight.dltType = D3DLIGHT_POINT;     d3dLight.dcvDiffuse.r = 1.0f;     d3dLight.dcvDiffuse.g = 1.0f;     d3dLight.dcvDiffuse.b = 1.0f;     d3dLight.dcvAmbient.r = 1.0f;     d3dLight.dcvAmbient.g = 1.0f;     d3dLight.dcvAmbient.b = 1.0f;    d3dLight.dcvSpecular.r = 1.0f;     d3dLight.dcvSpecular.g = 1.0f;   d3dLight.dcvSpecular.b = 1.0f;      // Set the light high and behind the viewer (who is at // (0.0,0.0,0.0) _ world space origin.    // These coordinates are in world space, so     // the viewer could be anywhere in world space.     d3dLight.dvPosition.x = 0.0f;     d3dLight.dvPosition.y = 1000.0f;  d3dLight.dvPosition.z = -100.0f;      // Don't have the light attenuate.    d3dLight.dvAttenuation0 = 1.0f;      d3dLight.dvRange = D3DLIGHT_RANGE_MAX;      // Set the property information for the first light-_index  0. hr = g_lpd3dDev->SetLight(0, d3dLight);     if (FAILED(hr))     {     // Code to handle the error goes here. } 

Retrieving Light Properties

Once a light has been created, you can acquire the set of lighting properties the device uses for it by using its IDirect3DDevice7::GetLight method. You can then use and modify the light as needed. Here's the function declaration for this method:

 HRESULT IDirect3DDevice7::GetLight(     DWORD dwLightIndex,     LPD3DLIGHT7 lpLight ); 

ParameterDescription
dwLightIndexZero-based index of the lighting property set to be retrieved
lpLightThe address of a D3DLIGHT7 structure that will be filled with the retrieved lighting-parameter set

This method takes the index of the light you want information about and the address of a D3DLIGHT7 structure. Here's an example of getting the first light we defined:

 // // g_lpd3dDev variable is a valid pointer to an IDirect3DDevice7 // interface. // HRESULT hr; D3DLIGHT7 light;      // Get the property information for the first light. hr = g_lpd3dDev->GetLight(0, &light); if (FAILED(hr)) {     // Handle your error here. } 

Enabling and Disabling the Lighting Engine

Direct3D defaults to performing lighting calculations on all vertices, even those that don't contain a vertex normal. (Note that this behavior differs from that of earlier versions of Direct3D, which lit only vertices that contained vertex normals.) You can enable lighting by setting the D3DRENDERSTATE_LIGHTING render state to TRUE or disable it by setting D3DRENDERSTATE_LIGHTING to FALSE.

Enabling and Disabling a Light

Once the lights have been created and placed in the scene, you can enable or disable each set of lighting parameters within a device by using the IDirect3DDevice7::LightEnable method, which is defined as follows:

 HRESULT LightEnable(      DWORD dwLightIndex,     BOOL bEnable ); 

ParameterDescription
dwLightIndexZero-based index of the set of lighting parameters that are the target of this method.
bEnableValue indicating whether the set of lighting parameters is being enabled or disabled. Set this parameter to TRUE to enable lighting with the parameters at the specified index or FALSE to disable it.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net