# Microsoft XNA Game Studio Creator’s Guide- P14

Chia sẻ: Cong Thanh | Ngày: | Loại File: PDF | Số trang:30

0
46
lượt xem
7

## Microsoft XNA Game Studio Creator’s Guide- P14

Mô tả tài liệu

Microsoft XNA Game Studio Creator’s Guide- P14:The release of the XNA platform and specifically the ability for anyone to write Xbox 360 console games was truly a major progression in the game-programming world. Before XNA, it was simply too complicated and costly for a student, software hobbyist, or independent game developer to gain access to a decent development kit for a major console platform.

Chủ đề:

Bình luận(0)

Lưu

## Nội dung Text: Microsoft XNA Game Studio Creator’s Guide- P14

1. 368 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE float3 unitDirection = normalize(lightDirection); // L // (N.L) - dot product of surface normal and light direction float cosine = dot(unitNormal, unitDirection); // R = 2*(N.L)*N – L float3 reflection = normalize(2*cosine*unitNormal - unitDirection); // (R.V)^n specular reflection. float specularLevel = pow(dot(reflection, unitDirection), 2); specularColor = color*intensity*specularLevel; return specularColor; } The diffuse light is simply the dot product between the light direction vector and the object being lit. The dot product approaches 1 for full intensity with the direct- ness of the light to the surface. When this calculation is done in the pixel shader, the result is interpolated between pixels to produce a nice, smooth-looking light. As you move the camera closer to the wall, the light radiates brightly and fizzles outward from the point that is directly in front of the camera. Diffuse light is modeled by the following equation: Diffuse Color * Diffuse Intensity * N.L To make the light fade from the center even more dramatic, the light intensity is scaled with a fallOff variable. fallOff is the inverted exponent of the scaled dis- d tance, d, between the light and pixel. exp(d) equals e where e is approximately 2.718281828. Because N.L = cos α, as the angle between the surface normal and light vector de- creases, cos α approaches 1 and diffuse light increases. Shining a light directly at a surface normal generates a brighter reflection than a light shone at an angle away from the normal vector. PointLightDiffuse() calculates the color added by the diffuse light: float4 PointLightDiffuse(VStoPS IN){ // unit direction of light vector L float3 lightDirection = normalize(lightPosition - IN.transformedPosition); // brightest angle between L and N = 0 float diffuseLevel = dot(lightDirection, IN.normal); // get distance from light to pixel float distance = distance(lightPosition, IN.transformedPosition);
2. C H A P T E R 2 2 369 Lighting // compute a falloff for the lighting float scale = 0.2f; float fallOff = clamp(1.0f / exp(distance * scale), 0, 1); // adjust the light intensity based on the falloff lightIntensity *= fallOff; // point light diffuse*intensity and color return diffuseLevel * lightIntensity * color; } The point light vertex shader receives the vertex position, texture, and normal data. The position in the window is generated by multiplying the position by the WVP matrix so that each vertex can be seen properly by the camera. transformedPosition is calculated by normalizing the product of the position and World matrix, so this unit vector can be used in the specular and diffuse lighting calculations. The normal vector is also transformed with the World matrix and is then normalized for the specular and diffuse calculations. Ambient light is uniform across the entire surface, so this calculation is performed in the vertex shader to save a little processing time: void VertexShader(in VSinput IN, out VStoPS OUT){ OUT.position = mul(IN.position, wvpMatrix); OUT.transformedPosition = mul(IN.position, worldMatrix); OUT.normal = normalize(mul(IN.normal, (float3x3)worldMatrix)); OUT.UV = IN.UV; OUT.ambientColor = AmbientLight(); } The pixel shader combines the different lights together and blends them with the texture for each pixel. The sum of the ambient, specular, and diffuse light component vectors is equivalent to the combination of different lighting components in Phong’s reflection model. void PixelShader(in VStoPS IN, out PSoutput OUT){ float4 diffuseColor = PointLightDiffuse(IN); float4 specularColor = SpecularLight(IN); OUT.color = tex2D(textureSampler,IN.UV) *(IN.ambientColor+specularColor+diffuseColor); }
4. C H A P T E R 2 2 371 Lighting this possible, assign the effect parameters to their corresponding shader variables from Initialize(): lightEffectWVP = lightEffect.Parameters["wvpMatrix"]; lightEffectWorld = lightEffect.Parameters["worldMatrix"]; lightEffectPosition = lightEffect.Parameters["lightPosition"]; lightEffectIntensity = lightEffect.Parameters["lightIntensity"]; lightEffectTexture = lightEffect.Parameters["textureImage"]; lightEffectColor = lightEffect.Parameters["color"]; The LightingShader() method is needed in the game class to apply the PointLightPS.fx shader while drawing with vertices while using an index buffer: private void LightingShader(PrimitiveType primitiveType){ // avoid drawing back face for large amounts of vertices graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace; lightEffect.Begin(); lightEffect.Techniques[0].Passes[0].Begin(); // 5: draw object - select vertex type, primitive type, index, & draw graphics.GraphicsDevice.VertexDeclaration = positionNormalTexture; graphics.GraphicsDevice.Indices = indexBuffer; graphics.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); // draw grid one row at a time for (int Z = 0; Z < NUM_ROWS - 1; Z++){ graphics.GraphicsDevice.DrawIndexedPrimitives( primitiveType, // primitive Z * NUM_COLS, // start point in vertex 0, // vertex buffer offset NUM_COLS * NUM_ROWS, // total verts in vertex buffer 0, // start point in index buffer 2 * (NUM_COLS - 1)); // end point in index buffer } // end shader lightEffect.Techniques[0].Passes[0].End(); lightEffect.End(); // disable back face culling graphics.GraphicsDevice.RenderState.CullMode = CullMode.None; }
5. 372 MICROSOFT XNA GAME STUDIO CREATOR’S GUIDE Most of the code used to draw the primitive surface has been explained in previous chapters. This includes transforming the object and drawing the vertices using an in- dex buffer reference. Also, the shader’s effect parameters are used here to move the point light with the camera, to set the diffuse light intensity, and to set the texture value. In step 4 of the code, the global variables in the shader are assigned values for the WVP matrix and the World matrix. This combination allows you to generate light in the view space and then to render the objects based on the World matrix. Re- place the existing version of DrawIndexedGrid() with the following code to draw the surfaces with the point light shader: private void DrawIndexedGrid(string surfaceName){ // 1: declare matrices Matrix world, translate, rotateX, scale, rotateY; // 2: initialize matrices translate = Matrix.CreateTranslation(0.0f, -3.6f, 0.0f); scale = Matrix.CreateScale(0.8f, 0.8f, 0.8f); rotateY = Matrix.CreateRotationY(0.0f); rotateX = Matrix.CreateRotationX(0.0f); if (surfaceName == "wall"){ // set parameters for wall rotateX = Matrix.CreateRotationX(MathHelper.Pi/2.0f); translate = Matrix.CreateTranslation(0.0f, 9.20f, -12.8f); lightEffectTexture.SetValue(wallTexture); } else if (surfaceName == "ground") // set parameters for ground lightEffectTexture.SetValue(floorTexture); // 3: build cumulative world matrix using I.S.R.O.T. sequence // identity, scale, rotate, orbit(translate & rotate), translate world = scale * rotateX * rotateY * translate; // 4: pass parameters to shader lightEffectWVP.SetValue(world*cam.viewMatrix*cam.projectionMatrix); lightEffectWorld.SetValue(world); lightEffectPosition.SetValue(new Vector4(cam.position, 1.0f)); lightEffectIntensity.SetValue(2.0f); lightEffectColor.SetValue(new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // 5: draw object - select vertex type, primitive type, index, and draw LightingShader(PrimitiveType.TriangleStrip); }
8. C H A P T E R 2 2 375 Lighting To view a stationary point light, in your XNA code, set the position of the light to a constant value. (Or you could continue to move the light with your camera if you prefer.) You can make the position of the point light stationary by replacing the in- struction that moves the light with the camera in DrawIndexedGrid(): lightEffectPosition.SetValue(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); When you run this version of the code, you will still see the point light. It will not be defined as much as the pixel shader point light, but you may notice a performance boost when running it. A simple lighting system, such as a lone directional light or the sun, can add depth to your game and reveal the details in your environment. Point light can add intrigu- ing details for night-time or indoor settings. As you can see, the effect is quite bril- liant. C HAPTER 22 REVIEW EXERCISES To get the most from this chapter, try out these chapter review exercises. 1. Complete the step-by-step examples presented in this chapter, if you have not already done so. 2. After completing the directional light demonstration using the BasicEffect object, try reducing the number of vertices that are stored in the vertex buffer by lowering the number of rows and columns to two each. Run the demo again (after this change has been made) and notice how the specular detail diminishes. Then, increase the total number of vertices for rows and columns to 50 each. Notice how the specular lighting’s effect improves with more vertices. 3. Using the directional light example, change the Y value of the normal in the vertex buffer from +1 to –1. Notice how everything turns black. Explain why this happens. 4. What is a useful intensity level for ambient light during daytime settings in the directional light demo? What is a useful intensity level for ambient light during evening settings in the directional light demo?