-
The Tessellation PipelineCS/게임 프로그래밍 2024. 2. 12. 02:30
Introduction
Tessellation
- Connect small pieces without gaps and overlapping to form a single surface.
- Means of representing a non-linear mathematical surface.
- NURBS (non-uniform rational basis splines) : generalized mathematical from for smooth curved surfaces.
- Subdivision surface; SubD
- Recursively divided the triangle until the ideal surface is no longer well expressed.
- Possible to approximate a smooth higher-order surface with a very large number of small triangles.
Why is tessellation useful
- The mathematical definition of a surface is sufficient with the coefficients, input parameters for the function, reducing memory storage and I/O bandwidth.
- Scalability : able to dynamically adjust the level of detail of the surface based on fixed inputs.
- One code path can be applied to various configurations.
- Should be noted that it may increase other types of costs, such as evaluating functions defining higher-order surfaces in real time.
Tessellation and the Direct3D Pipeline
Input Assembler
- Primitive topology configured in the device : D3D11_PRIMITIVE_TOPOLOGY_n_CONTROL_POINT_PATCHLIST (n : 1~32)
- Read $n$ indexes from the index buffer.
- Select vertices corresponding to the indices from the vertex buffer.
Vertex Shader
- The general use in tessellation : animation
- Vertex skinning : transform a model according to the frameworks determined by skeletal animation.
- Perform the task of transform a model space vertex data into world space.
Hull Shader
- Main function
- Executed once per declared control point.
- Up to 128 scalar values (float4 * 32) can be output.
- Total output per patch cannot exceed 3968 scalars (4KB)
- Patch constant function
- Executed once per each patch.
- Calculate values shared by all control points of a given patch.
- Logically calculate values that do not correspond to the attributes of each control point.
- Need to ouptut an array of SV_TessFactor and SV_InsideTessFactor values.
- Up to 128 scalar values (float4 * 32) can be output.
- Both functions have access to all vertices
- that are output by the vertex shader.
- that are considered to belong to a given primitive.
Fixed Function Tessellator
- Everything is fixed except for SV_TessFactor and SV_InsideTessFactor.
- The control points output by the hull shader stage are not used at all.
- The output of the tessellator is a set of weights corresponding to the primitive topology declared in the hull shader stage.
Domain Shader
- Each call in the domain shader proceeds independently of each other.
- Each call has access to all control points and patch-specific constants output by the hull shader stage.
- Create entirely new, renderable vertices using
- points extracted from primitives provided by the tessllator and
- control points provided by the hull shader.
Geometry Shader
- Know nothing about the current tessellation unless the domain shader has provided the information about the control mesh to the vertex-specific attributes.
Rasterizer and Pixel Shader
- The rasterizer has no idea that tessellation occur in the previous stages.
Parameters for Tessellation
- Measures to be considered when determining the level of amplification.
- Quality and performance : inversely proportional to each other.
- A simple example
- Black arrow : line segment produced by the Direct3D 11 pipeline to approximate the surface.
- Green arrow : ideal curves for artists and designers to display on the screen.
- Definition of tessellation parameters
// Example of the patch constant function struct HS_PER_PATCH_OUTPUT { float edgeTessellation[3] : SV_TessFactor; float insideTessellation[1] : SV_InsideTessFactor; }; HS_PER_PATCH_OUTPUT hsPerPatch(InputPatch<VS_OUTPUT, 3> ip, uint PatchID : SV_PrimitiveID) { HS_PER_PATCH_OUTPUT o = (HS_PER_PATCH_OUTPUT)0; o.edgeTessellation[0] = o.edgeTessellation[1] = o.edgeTessellation[2] = 2.0f; o.insideTessellation[0] = 2.0f; return o; }
// Primitives for tessellation // Line -> SV_TessFactor : 2 / SV_InsideTessFactor : 0 struct HS_PER_PATCH_OUTPUT { float edgeTessellation[2] : SV_TessFactor; // ...other values }; // Triangle -> SV_TessFactor : 3 / SV_InsideTessFactor : 1 struct HS_PER_PATCH_OUTPUT { float edgeTessellation[3] : SV_TessFactor; float insideTessellation[1] : SV_InsideTessFactor; // ...other values }; // Quadrilateral -> SV_TessFactor : 4 / SV_InsideTessFactor : 2 struct HS_PER_PATCH_OUTPUT { float edgeTessellation[4] : SV_TessFactor; float insideTessellation[2] : SV_InsideTessFactor; // ...other values };
HLSL Sub-functions
- *** : Min / Max / Avg
- The last three parameters of the functions are for output.
// Apply to squares with two inside tessellation coefficients independent of each other void ProcessQuadTessFactors***( float4 RawEdgeFactors, float InsideScale, float4 RoundedEdgeTessFactors, float2 RoundedInsideTessFactors, float2 UnroundedInsideTessFactors ); // Apply to squares with two same inside tessellation coefficients void Process2DQuadTessFactors***( float4 RawEdgeFactors, float2 InsideScale, float4 RoundedEdgeTessFactors, float2 RoundedInsideTessFactors, float2 UnroundedInsideTessFactors ); // Apply to all triangles void ProcessTriTessFactors***( float3 RawEdgeFactors, float InsideScale, float3 RoundedEdgeTessFactors, float RoundedInsideTessFactor, float UnroundedInsideTessFactor );
Effects of Parameters
- If any of the coefficients for the primitive are less than or equal to 0, or NaN, the primitive is excluded from processing.
- Edge factor
- Determine how small the edges of a primitive are to be divided.
- The tessellation coefficients of the edges shared by the two adjacent primitives should be same.
- Water-tightness requirements
- Tessellator always produce the same result for the same input.
- On any edge, the sample positions are symmetrical with respect to the center of the edge.
- Force adjacent fragments to use the same tessellation coefficients for the shared edge.
- Inside tessellation factor
- Determine how small the inside of a primitive is to be divided.
- The number of inside factor for quad : 2 / for triangle : 1.
- Partitioning method
- Partitioning method is specified as a attribute of the main function of the hull shader.
- The value specifying the partitioning method is declared as a compile-time constant, so that it will be the same for all patches being rendered with this particular hull shader.
- The factors are specified as float values by the constant function.
- integer : round up all floaintg-point values up to their nearest integer in 1 ~ 64.
- fractional_even : round up to the nearest even number in 2 ~ 64. (2, 4, 6, 8, 10, ...)
- fractional_odd : round up to the nearest odd number in 1 ~ 64. (1, 3, 5, 7, 9, ...)
- pow2 : round up according to the $2^n$ series. (n : 0 ~ 7)
- LOD transitions and the risk of popping
- Popping : a sudden jump where new geometry is added to the final output.
- Popping can be very noticeable to the viewer.
- Temporal considerations are important as this visual artifact is almost always caused by inputs changing through time. (across multiple frames in an animation)
- Important to think about the selection of tessellation factors with regard to how they change through time, rather than as a single, isolated per-frame factor.
'CS > 게임 프로그래밍' 카테고리의 다른 글
Multithreaded Rendering (1) 2024.03.29 The Computation Pipeline (0) 2024.03.19 The Rendering Pipeline - After Tessellation (0) 2024.02.05 The Rendering Pipeline - Before Tessellation (0) 2024.02.04 The Rendering Pipeline - Background (0) 2024.02.04