Previously, we used tessellation to subdivide a triangle or a quadrilateral. The generated subdivision points are within a triangle or a quadrilateral plane. In this tutorial, we will take a look at the PN triangles (point normal triangles) method and subdivide a triangle into a curved surface. For details about PN triangles, see: 2001 paper by vlachos et al. Next we will briefly introduce PN triangles:
As we all know, we usually use the besell function to represent a smooth surface. The besell function is a polynomial function. The surface it represents is also called the besell surface. For details about the besell surface, go to the Wiki.Bezr Surface.
Pn triangle is a special besell surface, which is expressed:
U, V, W are the center of gravity coordinates, bxyz is the control point, where u + V + W = 1, the position of the control point is as follows, it can be seen that b003, b030, b300 is the three vertex control points of a triangle. Based on the positions and directions of these three control points, we can calculate the positions of other control points.
The Pn triangles method is calculated using the following method:
Next we will add PN triangle support based on mytutoriald3d_54 and generate a surface using a triangle. First, modify the meshclass class to add the normal attribute to the vertex structure of the triangle patch, because it is required to calculate the control point.
Struct vertextype
{
D3dxvector3 position;
D3dxvector3 normal;
D3dxvector4 color;
};
...
// Create a clockwise triangle and a left-hand rule
// Set vertex data
Vertices [0]. Position = d3dxvector3 (4.0f, 0.0f,-2.0f); // bottom left
Vertices [0]. Normal = d3dxvector3 (-1.0f, 1.0f, 0.0f );
Vertices [0]. Color = d3dxvector4 (1.0f, 1.0f, 0.0f, 1.0f );
Vertices [1]. Position = d3dxvector3 (6.0f, 0.0f, 4.0f); // medium to high.
Vertices [1]. Normal = d3dxvector3 (0.0f, 1.0f, 1.0f );
Vertices [1]. Color = d3dxvector4 (0.0f, 1.0f, 0.0f, 1.0f );
Vertices [2]. Position = d3dxvector3 (8.0f, 0.0f,-2.0f); // bottom right
Vertices [2]. Normal = d3dxvector3 (1.0f, 1.0f, 0.0f );
Vertices [2]. Color = d3dxvector4 (0.0f, 1.0f, 1.0f, 1.0f );
Next, modify the tessshaderclass class, modify the vertex layout, and add normal support:
Polygonlayout [1]. semanticname = "normal ";
Polygonlayout [1]. semanticindex = 0;
Polygonlayout [1]. format = dxgi_format_r32g32b32_float;
Polygonlayout [1]. inputslot = 0;
Polygonlayout [1]. alignedbyteoffset = 12;
Polygonlayout [1]. inputslotclass = d3d11_input_per_vertex_data;
Polygonlayout [1]. instancedatasteprate = 0;
The next step is the modification of the shader file, which is also the most critical part. Let's take a look at each shader file. In vs, it is basically pass through, and pass the vertex attribute to HS, compared with the previous one, HS adds the code for generating new control points:
Constantoutputtype colorpatchconstantfunction (inputpatch {
Constantoutputtype output;
// Set the subdivision factor of the three edges.
Output. Edges [0] = tessellationamount;
Output. Edges [1] = tessellationamount;
Output. Edges [2] = tessellationamount;
// Set the subdivision factor in the Triangle
Output. Inside = tessellationamount;
// The Position of the three control vertices in PN triangle, which is the same as the original control point of the triangle patch.
Float3 f3b003 = inputpatch [0]. position;
Float3 f3b030 = inputpatch [1]. position;
Float3 f3b300 = inputpatch [2]. position;
// Normal
Float3 f3n002 = inputpatch [0]. normal;
Float3 f3n020 = inputpatch [1]. normal;
Float3 f3n200 = inputpatch [2]. normal;
// Calculate edge control points and central control points based on the formula
Output. f3b210 = (2.0f * f3b003) + f3b030-(dot (f3b030-f3b003), f3n002) * f3n002)/3.0f;
Output. f3b120 = (2.0f * f3b030) + f3b003-(dot (f3b003-f3b030), f3n020) * f3n020)/3.0f;
Output. f3b021 = (2.0f * f3b030) + f3b300-(dot (f3b300-f3b030), f3n020) * f3n020)/3.0f;
Output. f3b012 = (2.0f * f3b300) + f3b030-(dot (f3b030-f3b300), f3n200) * f3n200)/3.0f;
Output. f3b102 = (2.0f * f3b300) + f3b003-(dot (f3b003-f3b300), f3n200) * f3n200)/3.0f;
Output. f3b201 = (2.0f * f3b003) + f3b300-(dot (f3b300-f3b003), f3n002) * f3n002)/3.0f;
Float3 f3e = (output. f3b210 + output. f3b120 + output. f3b021 + output. f3b012 + output. f3b102 + output. f3b201)/6.0f;
Float3 f3v = (f3b003 + f3b030 + f3b300)/3.0f;
Output. f3b111 = f3e + (f3e-f3v)/2.0f );
// Calculate the normal control point
Float fv12 = 2.0f * dot (f3b030-f3b003, f3n002 + f3n020)/DOT (f3b030-f3b003, f3b030-f3b003 );
Output. f3n110 = normalize (f3n002 + f3n020-fv12 * (f3b030-f3b003 ));
Float fv23 = 2.0f * dot (f3b300-f3b030, f3n020 + f3n200)/DOT (f3b300-f3b030, f3b300-f3b030 );
Output. f3n011 = normalize (f3n020 + f3n200-fv23 * (f3b300-f3b030 ));
Float fv31 = 2.0f * dot (f3b003-f3b300, f3n200 + f3n002)/DOT (f3b003-f3b300, f3b003-f3b300 );
Output. f3n101 = normalize (f3n200 + f3n002-fv31 * (f3b003-f3b300 ));
Return output;
}
In ds, a new control point is generated based on the PN triangle formula:
// Center of gravity Coordinate
Float Fu = uvwcoord. X;
Float FV = uvwcoord. Y;
Float fw = uvwcoord. Z;
// Pre-calculate required values
Float fuu = fu * Fu;
Float fvv = FV * FV;
Float fww = fw * Fw;
Float fuu3 = fuu * 3.0f;
Float fvv3 = fvv * 3.0f;
Float fww3 = fww * 3.0f;
// Calculate the vertex position after subdivision based on the formula and the center of gravity Coordinate
Float3 f3position = Patch [0]. Position * fww * Fw +
Patch [1]. Position * fuu * Fu +
Patch [2]. Position * fvv * FV +
Input. f3b210 * fww3 * Fu +
Input. f3b120 * Fw * fuu3 +
Input. f3b201 * fww3 * FV +
Input. f3b021 * fuu3 * FV +
Input. f3b102 * Fw * fvv3 +
Input. f3b012 * Fu * fvv3 +
Input. f3b111 * 6.0f * Fw * Fu * FV;
// Calculate the position of the new vertex in the world coordinate system
Output. Position = MUL (float4 (f3position, 1.0f), worldmatrix );
Output. Position = MUL (output. Position, viewmatrix );
Output. Position = MUL (output. Position, projectionmatrix );
// Calculate the normal direction
Float3 f3normal = Patch [0]. Normal * fww +
Patch [1]. Normal * fuu +
Patch [2]. Normal * fvv +
Input. f3n110 * Fw * Fu +
Input. f3n011 * Fu * FV +
Input. f3n101 * Fw * FV;
// Normalization
F3normal = normalize (f3normal );
Output. Normal = f3normal;
// The new vertex color is also the color combination of each Control Point
Output. Color = uvwcoord. x * Patch [0]. color + uvwcoord. y * Patch [1]. color + uvwcoord. z * Patch [2]. color;
After the program is executed, the interface is shown as follows. Tess factor ranges from 1 to 6. As the subdivision factor increases, the closer the triangle is to the surface.
Complete code can be found:
Project File mytutoriald3d11_59
Download Code:
Provided later