Problem
In the previous tutorial, you learned how to make the triangle get the correct illumination based on the normal data.
However, blindly applying this method to all triangles will not always achieve the best effect.
If each vertex of a triangle has the same normal direction, the illumination is the same, and all pixels obtain the same illumination. If two adjacent triangles (not in the same plane) Exert illumination as well, then all pixels of one triangle get the same illumination, and all pixels of the other triangle get the other illumination. This makes it easy to see the boundary of the two because the two triangles have different colors.
If the color in the triangle is smooth, you want to get a better effect. To achieve this, the light and shade of a triangle should be smoothly transitioned from one triangle to another.
Solution
The video card calculates the brightness and shade based on the three vertices of the triangle. The brightness of all pixels in a triangle is interpolated. If the normal of the three vertices is the same, all pixels will get the same shade. If the pixels are different, the light and shade of the pixels will be smoothly transitioned in the corner.
Let's take a look at two triangles that share an edge and are composed of six vertices. In this case, the left figure is 6-3. To make sure that the color from one triangle to another can be smoothly transitioned, make sure that the colors of the two borders are the same. This can be achieved by having the shared vertex with the same normal. In the left graph of Figure 6-3, vertices 1 and 4 have the same normal.
Figure 6-3 two triangles that share an edge
Working Principle
In this tutorial, you will use two methods to define two triangles. First, define two triangles with the same normal for all vertices, which leads to the same illumination for all pixels in the triangle. Then, make sure that the normal in the shared vertex is the same, which will produce smooth shading on the triangle boundary.
Each triangle has its own normal.
This method obtains the direction perpendicular to the triangle and stores this direction in the vertex.
the Code below defines the six vertices shown in the left figure 6-3. The three vertices of each triangle have the same normal direction, perpendicular to the triangle. Place the triangle on the left vertically, so its normal direction is left. Place the second triangle horizontally, and the normal is up.
Private void initvertices () {vertices = new vertexpositionnormaltexture [6]; 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, 0,-1), new vector3 (-1, 0, 0), new vector2 (0.5f, 0); vertices [2] = new vertexpositionnormaltexture (New vector3 (0, 0, 0), new vector3 (-1, 0, 0), new vector2 (0.5f, 1); vertices [3] = new vertexpositionnormaltexture (New vector3 (0, 0), new vector3 (0, 1, 0 ), new vector2 (0.5f, 1); vertices [4] = new vertexpositionnormaltexture (New vector3 (0,-1), new vector3 (0, 1, 0 ), new vector2 (0.5f, 1); vertices [5] = new vertexpositionnormaltexture (New vector3 (1, 0), new vector3 (0, 1, 0 ), new vector2 (1, 1); myvertexdeclaration = new vertexdeclaration (device, vertexpositionnormaltexture. vertexelements );}
Then define a light in the lower right direction. Make sure that the direction of the light is normalized:
Vector3 lightdirection = new vector3 (10,-2, 0); lightdirection. normalize (); basiceffect. directionallight0.direction = lightdirection;
Then draw two triangles:
Basiceffect. begin (); foreach (effectpass pass in basiceffect. currenttechnique. passes) {pass. begin (); device. vertexdeclaration = myvertexdeclaration; device. drawuserprimitives <vertexpositionnormaltexture> (primitivetype. trianglelist, vertices, 0, 2); pass. end ();} basiceffect. end ();
See "normalize normal" in Section 6-1 to understand why the light direction needs to be normalized.
The two triangles have an opaque color, as shown in the figure 6-4 on the left. You can easily see the boundary between the two. This is not the expected result when drawing a large object.
Figure 6-4 triangle coloring (left), shared Vertex coloring (right)
Share normal
This time, you will apply the same normal direction on vertex 1 and 4, vertex 2 and 3. The question is which direction should you choose.
To get the smoothest effect, you just need to calculate the average value of the line, as shown in the following code:
private void initvertices () vertices = new vertexpositionnormaltexture [6]; vector3 normal1 = new vector3 (-1, 0, 0); vector3 normal2 = new vector3 (0, 1, 0); vector3 sharednormal = normal1 + normal2; sharednormal. normalize (); vertices [0] = new vertexpositionnormaltexture (New vector3 (0,-1, 0), normal1, new vector2 (0, 1 )); vertices [1] = new vertexpositionnormaltexture (New vector3 (0, 0,-1), sharednormal, new vector2 (0.5f, 0 )); vertices [2] = new vertexpositionnormaltexture (New vector3 (0, 0, 0), sharednormal, new vector2 (0.5f, 1 )); vertices [3] = new vertexpositionnormaltexture (New vector3 (0, 0), sharednormal, new vector2 (0.5f, 1); vertices [4] = new vertexpositionnormaltexture (New vector3 (0, -1), sharednormal, new vector2 (0.5f, 1); vertices [5] = new vertexpositionnormaltexture (New vector3 (1, 0), normal2, new vector2 )); myvertexdeclaration = new vertexdeclaration (device, vertexpositionnormaltexture. vertexelements);
First, find the sum of the two triangles and then normalize the results (see "Normalization normal" in Section 6-1 of the tutorial ). The calculation result points to the upper and left directions.
Then define six vertices. The two vertices on both sides do not share the normal, so the original normal value remains unchanged. The other four vertices that share the normal use the same normal.
Now, when two triangles are drawn, the light and shade will smoothly transition from a vertex on both sides to a shared edge, as shown in the figure 6-4 on the right. It is hard for you to see the joint edges of two triangles, so that you will not find that an object is composed of multiple triangles.
TIPS:Tutorial 5-7 describes how to automatically calculate a shared normal for a large object.
You can also use this method when using indexes (see tutorial 5-3 ).
Code
You can find the Code to define a triangle before the tutorial. The code below is used 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 (10,-2, 0); lightdirection. normalize (); basiceffect. directionallight0.direction = lightdirection; basiceffect. directionallight0.diffusecolor = color. white. tovector3 (); basiceffect. directionallight0.enabled = true; basiceffect. begin (); foreach (effectpass pass in basiceffect. currenttechnique. passes) {pass. begin (); device. vertexdeclaration = myvertexdeclaration; device. drawuserprimitives <vertexpositionnormaltexture> (primitivetype. trianglelist, vertices, 0, 2); pass. end ();} basiceffect. end ();
Note:The texture used in this tutorial has only one opaque color (blue), and you can confirm the final color gradient effect.