DirectX Computational Graphics

Domain Shaders

Domain shaders are a crucial component of the tessellation pipeline in DirectX. They work in conjunction with hull shaders to generate new vertices from a patch, allowing for dynamic level of detail and intricate geometric detail on the fly.

Role in Tessellation

Tessellation is a hardware-accelerated technique that subdivides a mesh's primitives (like triangles or quads) into smaller primitives. This process is typically controlled by two programmable shader stages:

How Domain Shaders Work

A domain shader executes for each vertex that needs to be generated within a tessellated patch. It receives:

Using these inputs, the domain shader calculates the position of a new vertex in object space. This output vertex is then passed to the rasterizer for further processing.

Key Functionality and Benefits

Example Domain Shader (HLSL)

This is a simplified example of a domain shader that might be used to tessellate a quad.

// Define the output structure for the domain shader struct DS_OUTPUT { float4 Position : SV_POSITION; // Clip-space position float2 Tex : TEXCOORD0; // Texture coordinates }; // Define the input structure for the domain shader // This structure receives data from the hull shader struct DS_INPUT { float3 DomainCoordinates : SV_DOMAIN; // Barycentric coordinates (u, v, w) float4 ControlPoint : POSITION; // Control point data float2 Tex : TEXCOORD0; // Texture coordinates from control point }; // Assume PatchConstantHS is defined in Hull Shader output // Domain Shader function DS_OUTPUT DomainShader(float4 patchDistance : SV_DOMAIN, const OutputPatch tri, // Assuming a quad (4 control points) float4 patchConstants[1] : PATCHCONSTANT) // Patch constants from Hull Shader { DS_OUTPUT result; // Simplified example: Interpolate position and texture coordinates // In a real scenario, you'd use patchDistance and patchConstants to perform complex calculations // Linear interpolation of position result.Position = tri[0].ControlPoint * (1.0f - patchDistance.x - patchDistance.y) + tri[1].ControlPoint * patchDistance.x + tri[2].ControlPoint * patchDistance.y; // For quads, you'd need more complex interpolation based on patchDistance.x and patch.y // Linear interpolation of texture coordinates result.Tex = tri[0].Tex * (1.0f - patchDistance.x - patchDistance.y) + tri[1].Tex * patchDistance.x + tri[2].Tex * patchDistance.y; // Transform to clip space (typically done by vertex shader, but shown here for completeness if it's the end) // In a full pipeline, this would be handled by the VS or subsequent stages. // For a tessellated pipeline, the domain shader output is often in object or world space, // and then transformed by a subsequent vertex shader stage. // Let's assume it's outputting world space for simplicity here. // The SV_POSITION semantic typically expects clip-space coordinates. // This highlights that the exact stage and its output space can vary. // For demonstration, let's assume the domain shader outputs world space and a final VS handles the projection. // If this were the final output stage before rasterization, transformation to clip-space would be required. // Example transformation to clip space (if this were the final stage) // This requires projection matrix from constants or uniforms // result.Position = mul(WorldViewProjectionMatrix, result.Position); // result.Position.w = 1.0f; // Ensure w is 1 for perspective division return result; }
Note: The exact structure and semantics of input/output can vary based on the tessellation primitive type (triangles, quads, or polygons) and how the hull shader is configured. The example above uses simplified interpolation for illustration.

Pipeline Integration

The domain shader is executed after the hull shader and before the geometry shader (if present) or rasterizer. The tessellation pipeline typically looks like this:

  1. Input Assembler: Feeds vertex data into the pipeline.
  2. Vertex Shader: Processes individual vertices.
  3. Hull Shader: Orchestrates tessellation, outputs patch constants and control points.
  4. Tessellator: Hardware stage that uses hull shader output to generate tessellation factors and domain coordinates.
  5. Domain Shader: Generates new vertices for the tessellated primitives.
  6. Geometry Shader (Optional): Further processes primitives.
  7. Rasterizer: Converts primitives into pixels.
  8. Pixel Shader: Colors the pixels.

Further Reading