Problem
In the first two tutorials, we calculated the brightness and shade of each vertex. We need to perform Interpolation on this value for each pixel of the triangle. Therefore, this is called the vertex-by-vertex illumination (Per-vertex lighting, also called the Highlord coloring and the Highlord light Gouraud shading ).
In some cases, vertex-by-vertex illumination does not produce the best results. In particular, when using a large triangle or a sharp edge or both of them, the expected results are often not obtained.
For example, there are three faces on the left.CubeBody. The right side of the image shows how the shared normal is defined. In this example, the light direction is represented by four arrows.
Figure 6-5 vertex shader pairs per-Pixel Lighting
Follow the top of the cube, corresponding to the line segment between vertex 2 and vertex 4 in the right graph. The brightness of vertex 2 and vertices 4 is calculated using Vertex-by-vertex illumination. There is not much light in vertex 4, because the normal of vertex 4 is almost perpendicular to the light direction, we think it is 20% light. Vertex 2 emits much light, because its normal direction is almost the same as the light direction, we set it to 80% light. In vertex-by-vertex illumination, the pixels in the triangle are interpolated, and all pixels between the two vertices receive illumination between 20% and 80%. In this way, no pixel can obtain 100% illumination.
However, the direction of a pixel between vertex 2 and vertex 4 is exactly the same as that of the light! This Normal is displayed in the right image of Figure 6-5. Obviously, this pixel should get 100% of the illumination, but with vertices-by-vertex illumination, This pixel can only get a illumination value between 20% and 80%.
Solution
Vertex-by-vertex illumination only calculates the precise brightness of the vertex, while the brightness of the pixel between the vertex is obtained through interpolation.
With pixel-by-pixel illumination, you can perform interpolation on the normal lines of all pixels so that you can calculate the exact brightness of each pixel.
Working Principle
Basiceffect makes it easy to use pixel-by-pixel illumination. When setting the basiceffect parameter, you only need to add the followingCodeRow:
Basiceffect. preferperpixellighting = true;
Note:To enable pixel-by-pixel shader to work, you must have a graphics card that supports more than 2.0 of shader. You can use the following code to check the video card support:
Graphicsdevice. graphicsdevicecapabilities. maxpixelshaderprofile> = shaderprofile. ps_2_0
Code
The following code creates the vertex shown in the left figure 6-5. Because some normal may no longer be in unit length, make sure that they are normalized at the end:
Private void initvertices () {vertices = new vertexpositionnormaltexture [8]; vertices [0] = new vertexpositionnormaltexture (New vector3 (0,-1, 0), new vector3 (-1, 0, 0), new vector2 (0, 1); vertices [1] = new vertexpositionnormaltexture (New vector3 (0,-1,-1), new vector3 (-1, 0, 0), new vector2 (0, 0); vertices [2] = new vertexpositionnormaltexture (New vector3 (0, 0, 0), new vector3 (-1, 1, 0), new vector2 (0.33f, 1); vertices [3] = new vertexpositionnormaltexture (New vector3 (0, 0,-1), new vector3 (-1, 1, 0), new vector2 (0.33f, 0); vertices [4] = new vertexpositionnormaltexture (New vector3 (1, 0, 0), new vector3 (1, 1, 0 ), new vector2 (0.66f, 1); vertices [5] = new vertexpositionnormaltexture (New vector3 (1, 0,-1), new vector3 (1, 1, 0 ), new vector2 (0.66f, 0); vertices [6] = new vertexpositionnormaltexture (New vector3 (1,-1, 0), new vector3 (1, 0, 0 ), new vector2 (1, 1); vertices [7] = new vertexpositionnormaltexture (New vector3 (1,-1,-1), new vector3 (1, 0, 0 ), new vector2 (1, 0); For (INT I = 0; I <vertices. length; I ++) vertices [I]. normal. normalize (); myvertexdeclaration = new vertexdeclaration (device, vertexpositionnormaltexture. vertexelements );}
Read "Normalization normal" in 6-1 to understand why the final for loop is required.
Note:Because xNa does not provide a vertex structure that contains 3d positions, colors, and baselines, this tutorial uses a blue texture to make the color of each pixel the same. In this way, all the changes in the color you see will be affected by the light.
Then you can use pixel-by-pixel illumination to draw a triangle:
Basiceffect. world = matrix. identity; basiceffect. view = fpscam. viewmatrix; basiceffect. projection = fpscam. projectionmatrix; basiceffect. texture = bluetexture; basiceffect. textureenabled = true; basiceffect. lightingenabled = true; vector3 lightdirection = new vector3 (3,-10, 0); lightdirection. normalize (); basiceffect. directionallight0.direction = lightdirection; basiceffect. directionallight0.diffusecolor = color. white. tovector3 (); basiceffect. directionallight0.enabled = true; basiceffect. preferperpixellighting = true; basiceffect. begin (); foreach (effectpass pass in basiceffect. currenttechnique. passes) {pass. begin (); device. vertexdeclaration = myvertexdeclaration; device. drawuserprimitives <vertexpositionnormaltexture> (primitivetype. trianglestrip, vertices, 0, 6); pass. end ();} basiceffect. end ();