2.5 Sample Application: Cartoon Rendering (below)
Read this article shows that you have agreed to the statement
2.5.3 Contour Outlook
To complete the cartoon effect, we also need the outline profile (Silhouette EDGE). This is more complicated than cartoon coloring.
2.5.3.1 representation of the side
Let's represent a side of a grid as a quad group (constructed from two triangles) - see Figure 2.5.
Figure 2.5: Four groups indicating the side
We have two reasons why we choose the four-tuples: We can adjust the thickness of the dimension of the four-way group of dimension, and we can render the degraded four-way groups to hide certain sides, that is, non-contour edges. In Direct3D, we build a quad group from two triangles. Degenerate QUAD is a quadruple group constructed from two degraded triangles. Degenerate Triangle is a zero triangle, or in other words, it is a triangle on the first line. If we pass it into a degraded triangle to the rendering line, the triangle is displayed empty. This is useful, because if we want to hide a specific triangle, we can simply degenerate it without removing it from a triangle list (vertex buffer). Recall that we only need to display the silhouette - instead of each of the grid.
When we first create a while, we specify its four vertices and degrade it, which means that the edge will be hidden (not displayed when rendering).
Figure 2.6: Degraded quadritical groups described by two triangles
Note Two vertices V0 and V1 in Figure 2.6, we set their vertex normal vector to zero vector. Then when we send the vertex of the side, the vertex shader will detect whether the vertex is on the contour edge; if so, the vertex shader will shift the scalar of the vertex position in the direction of the vertex. Observe the vertex of the normal vector to zero, it will not be offset.
Therefore, we finally represent the silhouette edge in a non-degenerate quad, as shown in Figure 2.7.
Figure 2.7: The vertices V2 and V3 located on the contour edge are offset according to their respective vertex nodes N2 and N3. Observe the vertices V0 and V1 remain in its fixed position because its vertex is equal to zero vectors, so there is no offset for them. According to this approach, the four-tuple successful regeneration indicates the silhouette.
Remarks: If we don't set the vertex V0 and V1 of the vertex of V0 and V1 as zero, then the vertices will be offset. However, if the offset describes all four vertices of the silhouette, then we only panicted the degraded quad group. We regenerate four tether groups by maintaining vertices V0 and V1 and only offset vertices V2 and V3.
2.5.3.2 Contour edge test
If the two surfaces Face0 and Face1 share the surface where the side is shared in the direction in which the view is different, the edge is the outline edge. That is, if a surface is Front Facing, the other surface is back facing, then this edge is a silhouette. Figure 2.8 shows an example of a silhouette and a non-contoured edge.
Figure 2.8: In (a), one surface of the shared edge defined by V0 and V1 is front, and the other surface of the shared edge is behind, so the edge is the outline. In (b), the surfaces of the two shared edges defined by V0 and V1 are front, so the edge is not an outline side.
Next, in order to detect if a vertex is on the contour edge, we must understand the normal vector of Face0 and Face1 in each vertex. The vertex data structure of our side is reflected as follows: struct vs_input
{
Position: position;
VECTOR NORMAL: NORMAL0;
Vector Facenormal1: Normal1;
Vector Facenormal2: Normal2;
}
The first two components are very direct, but let's take a look at two extra normal vector, they are Facenormal1 and Facenormal2. These vectors describe the surface normal of the two surfaces, the vertices of the shared edges are located on the shared edge of the two surfaces, both of which are Face0 and Face1.
The actual detection of the mathematics on the shared edge of the shared side. Suppose we are in the view space, making V for an origin vector, pointing to the detection vertex - Figure 2.8, the surface normal of the N0 is Face0 and N1 is the surface normal of Face0, if the following inequality is true, the vertex is in the outline On the side:
(1) (V · N0) (V · N1) <0
If the two-point symbols are different, the inequality is true, so that the left side of the equation is negative. Recall the nature of the points, two points of symbols means that a surface is front and the other is behind.
Now, consider only one triangle sharing in a side, as shown in Figure 2.9, the normal will be stored in Facenormal1.
Figure 2.9: Only one surface of the vertex V0 and V1 definitions share it
We define this edge to always be outlined. To ensure that the vertex shader treats this edge as an outline, we have to let Facenormal2 = -Facenormal1. Therefore, the reverse surface normal and inequality (1) are true, indicating that the side is a silhouette side.
2.5.3.3 generation
The edge of the generated grid is negligible; we simply traverse each surface of the grid and calculate a quad group (degraded, as shown in Figure 2.6) for each surface of the grid.
Note: There are three sides of each surface because each triangle has three sides.
For each side iteration, we may know the two surfaces of the shared edge. One of the surfaces is the triangle of the side. For example, if you want to calculate a side of the first surface, then the first surface shares the edge. Another surface of sharing this side can be found using the neighboring information of the grid.
2.5.4 Contouring the vertex shader code
We now present the vertex shader code that renders the silhouette. The main task of this shader is to determine if the incoming vertex is on the edge of the contour. If so, the vertex shader offset a certain amount of values in the direction of the vertex normal.
// file: Outline.txt
// DESC: Vertex Shader Renders Silhouette Edges.
//
// globals
//
Extern Matrix WorldViewMatrix;
Extern Matrix Projmatrix;
Static Vector Black = {0.0F, 0.0F, 0.0F, 0.0F};
//
// structures
//
Struct vs_INPUT
{
Position: position;
VECTOR NORMAL: NORMAL0;
Vector Facenormal1: Normal1;
Vector Facenormal2: Normal2;
}
Struct vs_output
{
Position: position;
Vector Diffuse: Color;
}
//
// main
//
Vs_output main (vs_input input) {
// Zero Out Each MEMBER in OUTPUT
Vs_output output = (vs_output) 0;
// Transform position to View Space
Input.position = MUL (Input.Position, WorldViewMatrix);
// compute a vector in the direction of the vertex
// from the eye. recall the eye is at the Origin
// in view space - Eye is Just Camera Position.
Vector eyetovertex = input.position;
// Transform Normals to View Space. SET W
// Components to Zero Since We're Transforming Vectors.
// Assume There no scalings in the world
// Matrix as well.
Input.NORMAL.W = 0.0F;
Input.facenormAl1.w = 0.0F;
Input.facenormal2.w = 0.0f;
Input.Normal = MUL (Input.Normal, WorldViewMatrix);
Input.facenormal1 = MUL (Input.Facenormal1, WorldViewMatrix);
Input.facenormal2 = MUL (Input.Facenormal2, WorldViewMatrix);
// compute the cosine of the Angles Between
// The EyetoverTex Vector and The Face Normals.
FLOAT DOT0 = DOT (EyetoverTex, Input.FACenormal1);
FLOAT DOT1 = DOT (EyetoverTex, Input.FACenormal2);
// if cosines area difffficient signs (posient / negative)
// THEN We are on a silhouette Edge. Do The Signs
// Differ?
IF ((dot0 * dot1) <0.0f)
{
// Yes, THIS VERTEX IS ON A Silhouette Edge,
// offset the vertex position by Some Scalar in The
// Direction of the Vertex Normal.
Input.position = 0.1f * Input.Normal;
}
// Transform to Homogeneous CLIP SPACE
Output.position = MUL (Input.position, Projmatrix);
// set Outline Color
Output.diffuse = black;
Return Output;
}