This tutorial is part of a Collection: 01. DirectX 9 - Braynzar Soft Tutorials
2288
views
11. Lighting
Without lighting, your scenes are bland and lack realism. With lighting, you have a more natural scene, you can see the solid form and volume of objects better and get a much more realistic feeling while wondering through your 3 Dimensional world.
Lighting is used to make your scene look more "natural". With lighting enabled, we do not have to directly define the color of our vertices. The color of our vertices will be defined by the material of our object, defined light sources, and the direction of the normals compaired to the direction of the light. In Direct3D, a light source emits three kinds of light components. They are as follows: **Diffuse Light** - This is the general light that is emitted from a light source. It only takes light direction and attitude of a surface to compute. It is reflected off the surface of objects equally in all directions. **Ambient Light** - This is the light reflected off of surfaces. It takes the light that bounces off from surfaces directly in a light sources path and lights up surfaces that are not directly in the path of a light source, so it is used to brighten up the entire scene. **Specular Light** - This is the light that travels sharply in one direction after the light bounces off of a surface, creating a bright shine on a polished surface only seen from some angles. Since this light is only viewed from perspective, the equation that computes this light takes the light direction, attitude of a surface, and the perspective view as components. Since Specular light takes more to compute, Direct3D has the option to enable or disable it. By default it is disabled. To enable Specular Light, you have to set the D3DRS_SPECULARENABLE render state. d3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true); The three light components are represented by the D3DXCOLOR or D3DCOLORVALUE structures. When describing light with the D3DXCOLOR structure, the alpha components are not used. These examples will define a white light: D3DXCOLOR Diffuse(1.0f, 1.0f, 1.0f, 1.0f); D3DXCOLOR Ambient(1.0f, 1.0f, 1.0f, 1.0f); D3DXCOLOR Specular(1.0f, 1.0f, 1.0f, 1.0f); There are three different light sources that Direct3D supplies: **Directional Lights** - This type of light has no source. It only runs in one direction everywhere in your scene. +[http://www.braynzarsoft.net/image/100131][Directional light] **Spot Lights** - This type of light source is a lot like a flashlight. It is shaped like a cone and is defined by two angles, theta and phi. Theta is the angle of the inner cone, while phi is the angle of the outer cone. +[http://www.braynzarsoft.net/image/100132][Spot light] **Point Lights** - This light source would be kinda like the sun. It has a position in space, and emits light in all directions. +[http://www.braynzarsoft.net/image/100133][Point light] For our lighting to work, Direct3D needs to know which way the polygons are facing. A face normal is a vector that describes the direction of the face of a polygon. A vertex normal is a vector which describes which way a vector is pointing. Face normals and vertex normals are not always the same. For example, when you make a sphere using face normals, the lighting will be kind of choppy and not smooth, you will be able to see the triangles or squares which make up the sphere. Using vertex normals, you can average the normals (Normal Averaging) to get a smoother lighting effect on the sphere. Face Normals +[http://www.braynzarsoft.net/image/100134][face normals] Vertex Normals +[http://www.braynzarsoft.net/image/100135][vertex normals] Face Normals on Sphere +[http://www.braynzarsoft.net/image/100136][face normals on sphere] Normal Averaging +[http://www.braynzarsoft.net/image/100137][normal averaging] The color of a surface or object we see is the light that is reflected and not absorbed. If an object is green, that is because the object absorbs all colors except for green. In Direct3D, an objects color is defined by a material. A material is represented by the D3DMATERIAL9 structure. We're going to make a white material, so it reflects all colors. Now we also have to initialize a light source. Lights are represented by the D3DLIGHT9 structure. D3DMATERIAL9 white; D3DLIGHT9 light; The Vertex structure is going to have to be changed. We add 3 new members to define the normal of a vertex(which way the vertex is facing). struct Vertex { FLOAT x, y, z; FLOAT nx, ny, nz; FLOAT u, v; }; We have to change our Flexible Vertex Format to support our new Vertex Structure by adding in D3DFVF_NORMAL. By adding this in, We are telling Direct3D that our Vertex Structure is going to define a normal for each vertex we make. #define VERTEXFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) The next new section of code is going to create a white light. The first line is just going to clear our light structure. This is how the D3DLIGHT9 Structure looks. typedef struct _D3DLIGHT9 { D3DLIGHTTYPE Type; D3DCOLORVALUE Diffuse; D3DCOLORVALUE Specular; D3DCOLORVALUE Ambient; D3DVECTOR Position; D3DVECTOR Direction; float Range; float Falloff; float Attenuation0; float Attenuation1; float Attenuation2; float Theta; float Phi; } D3DLIGHT9; **Type **- Is the type of light source. Can be one of these: D3DLIGHT_POINT, D3DLIGHT_SPOT, D3DLIGHT_DIRECTIONAL **Diffuse** - Defines the diffuse light that will be emitted **Specular **- Defines specular light that will be emitted **Ambient **- Defines the ambient light that will be emitted **Position **- Vector defining where this light is positioned in 3D space. Not used for directional lights. **Direction **- Vector defining where this light source is pointed in 3D space. Not used for spot lights. **Range **- The distance the light emitted from this light source can travel before it dies off. This value has no effect on Directional lights. **Falloff **- Used for spotlights. It describes how the light gets dimmer from the inner cone to the outer cone. Usually set to 1.0f **Attenuation0,1,2 **- Defines how light gets dimmer over a distance. Attenuation0 is a constant falloff, Attenuation1 is a linear falloff, and Attenuation2 is a quadratic falloff. **Theta **- Only used for spotlights. Theta defines the angle of the inner cone in radians. **Phi **- Only used for spotlights. Phi defines the angle of the outer cone in radians. ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); light.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) * 0.2f; light.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) * 0.1f; light.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.7f); Next section of code defines the white material we will be using. The first line just clears our white material structure. The D3DMATERIAL9 structure looks like this: typedef struct _D3DMATERIAL9 { D3DCOLORVALUE Diffuse, Ambient, Specular, Emissive; float Power; } D3DMATERIAL9; **Diffuse **- The amount of Diffuse light this surface reflects. **Ambient **- The amount of Ambient light this surface reflects. **Specular **- The amount of Specular light this surface reflects. **Emissive **- Used to add to the overall color of the surface, making it brighter like its giving off its own light. **Power **- The sharpness of the specular highlights. The higher the value, the sharper the highlights. ZeroMemory(&white, sizeof(white)); white.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); white.Power = 5.0f; Sometimes it is necessary to renormalize normals after translation and other transformations because the normals can get messed up. So thats all this line of code does, it just renormalizes the normals. d3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); Now we enable lighting with this line of code. d3dDevice->SetRenderState(D3DRS_LIGHTING, true); After we initialized a D3DLIGHT9 instance, we need to register our light with an internal list of lights that Direct3D maintains. We do it with this: d3dDevice->SetLight(0, - element in the light list to set, range is 0-maxlights &light); - address of the D3DLIGHT9 structure to set Now our light is set, we can turn it on and off with the next line LightEnable. d3dDevice->LightEnable(0, - The light to turn on or off true); - True turns it on, False turns it off d3dDevice->SetLight(0, &light); d3dDevice->LightEnable(0, true); After all that, we set our material with the following line. d3dDevice->SetMaterial(&white); Thats it for this lesson. If you have any questions or comments, feel free to check out the forum or contact us directly at the bottom of the page, see ya next time! Here's the final code: main.cpp ... ... D3DMATERIAL9 white; //Pointer to store material D3DLIGHT9 light; //Pointer to store light ... ... //The New Vertex structure struct Vertex { FLOAT x, y, z; FLOAT nx, ny, nz; //Vertex Normals FLOAT u, v; }; //The New Flexible Vertex Format #define VERTEXFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) ... ... bool SetupScene(){ //Set up our Scene void* pVoid; d3dDevice->CreateVertexBuffer( 36 * sizeof(Vertex), D3DUSAGE_WRITEONLY, VERTEXFVF, D3DPOOL_MANAGED, &CubeVertexBuffer, 0); Vertex squarevertices[] = { //front face { 1.0f,-1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}, { 1.0f,-1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f}, //right side { 1.0f,-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f}, { 1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, { 1.0f,-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f}, { 1.0f, 1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f}, //left side {-1.0f,-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f, 1.0f}, {-1.0f,-1.0f, 1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {-1.0f,-1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {-1.0f, 1.0f,-1.0f,-1.0f, 0.0f, 0.0f, 1.0f, 0.0f}, //back side {-1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}, { 1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, {-1.0f,-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f}, //top side { 1.0f, 1.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f}, {-1.0f, 1.0f,-1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f}, //bottom side { 1.0f,-1.0f, 1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 1.0f}, {-1.0f,-1.0f, 1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f}, { 1.0f,-1.0f, 1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 1.0f}, {-1.0f,-1.0f,-1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f}, { 1.0f,-1.0f,-1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 0.0f}, }; void* pVoid; CubeVertexBuffer->Lock(0, 0, (void**)&pVoid, 0); //copy the squarevertices[] array into the vertex buffer memcpy(pVoid, squarevertices, sizeof(squarevertices)); CubeVertexBuffer->Unlock(); D3DXCreateTextureFromFile( // Create texture. d3dDevice, "braynzar.jpg", &cubetex); //Create the light ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); light.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) * 0.2f; light.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) * 0.1f; light.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.7f); //Create the material ZeroMemory(&white, sizeof(white)); white.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); white.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); white.Power = 5.0f; d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); d3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); D3DXMATRIX matView; // the view transform matrix D3DXMatrixLookAtLH(&matView, // the camera position &D3DXVECTOR3 (0.0f, 0.0f, 10.0f), // the look-at position &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the up direction &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // set the view transform to matView d3dDevice->SetTransform(D3DTS_VIEW, &matView); // the projection transform matrix D3DXMATRIX matProjection; D3DXMatrixPerspectiveFovLH(&matProjection, D3DXToRadian(45), // the horizontal field of view (FLOAT)Width / (FLOAT)Height, // aspect ratio 1.0f, // the near view-plane 100.0f); // the far view-plane // set the projection d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjection); //Renormalize Normals d3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); d3dDevice->SetRenderState(D3DRS_LIGHTING, true); //Enable Lighting d3dDevice->SetLight(0, &light); //Set the light d3dDevice->LightEnable(0, true); //Enable the light return true; } ... ... bool RenderScene(float timeDelta) //Renders a single frame { if( d3dDevice ) { ... ... d3dDevice->BeginScene(); //Start drawing our scene d3dDevice->SetMaterial(&white); //Set Material d3dDevice->SetTexture(0, cubetex); //set Texture d3dDevice->SetStreamSource(0, CubeVertexBuffer, 0, sizeof(Vertex)); d3dDevice->SetFVF(VERTEXFVF); d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,12); d3dDevice->EndScene(); //Stop drawing our scene ... ... } return true; }
Sign in to comment