Shader Examples for DirectX Computational Graphics

This section provides a collection of shader examples and tutorials for developing computational graphics applications using DirectX. Shaders are essential for modern graphics pipelines, allowing for highly customizable visual effects and complex computations on the GPU.

Getting Started with DirectX Shaders

Before diving into specific examples, it's recommended to understand the basics of shader programming. DirectX typically uses High-Level Shading Language (HLSL) for writing shaders. Familiarize yourself with:

Basic Shader Examples

Vertex Shader - Simple Transformation

A fundamental vertex shader that performs basic transformations (world, view, projection) on vertex data.

// Input vertex structure struct VS_INPUT { float4 Position : POSITION; float4 Color : COLOR0; }; // Output vertex structure struct VS_OUTPUT { float4 Position : SV_POSITION; float4 Color : COLOR0; }; // Constant buffer for transformation matrices cbuffer ModelViewProjection : register(b0) { matrix WorldViewProjection; }; VS_OUTPUT main(VS_INPUT input) { VS_OUTPUT output = (VS_OUTPUT)0; // Transform vertex position output.Position = mul(input.Position, WorldViewProjection); output.Color = input.Color; return output; }

Pixel Shader - Solid Color Output

A basic pixel shader that outputs a solid color, often used for debugging or as a fallback.

// Output structure for pixel shader struct PS_OUTPUT { float4 Color : SV_TARGET; }; PS_OUTPUT main() { PS_OUTPUT output; output.Color = float4(1.0f, 0.0f, 1.0f, 1.0f); // Magenta color return output; }

Advanced Shader Techniques

Pixel Shader - Phong Illumination Model

Implements the Phong illumination model for realistic lighting, including ambient, diffuse, and specular components.

struct VS_OUTPUT { float4 Position : SV_POSITION; float3 Normal : NORMAL; float3 WorldPos : TEXCOORD0; }; struct PS_OUTPUT { float4 Color : SV_TARGET; }; cbuffer LightProperties : register(b1) { float3 LightDirection; float3 CameraPosition; float3 LightColor; float AmbientStrength; float SpecularStrength; }; float4 main(VS_OUTPUT input) : SV_TARGET { float3 normal = normalize(input.Normal); float3 worldPos = input.WorldPos; float3 lightDir = normalize(LightDirection); float3 viewDir = normalize(CameraPosition - worldPos); // Ambient float3 ambient = LightColor * AmbientStrength; // Diffuse float diff = max(dot(normal, lightDir), 0.0f); float3 diffuse = LightColor * diff; // Specular float3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0f), 32); // Shininess factor float3 specular = LightColor * spec * SpecularStrength; float3 finalColor = ambient + diffuse + specular; return float4(finalColor, 1.0f); }

Geometry Shader - Instancing

Demonstrates how to use a geometry shader to output multiple primitives (e.g., instances of a mesh) from a single input primitive.

Note: Geometry shaders are less common in modern rendering but useful for specific effects.

struct VS_OUTPUT { float4 Position : SV_POSITION; }; struct GS_OUTPUT { float4 Position : SV_POSITION; }; [maxvertexcount(3)] // Output up to 3 vertices (a triangle) void main(triangle VS_OUTPUT input[3], inout PrimitiveStream output) { GS_OUTPUT p; // Pass through the first vertex of the input triangle p.Position = input[0].Position; output.Append(p); output.RestartStrip(); // Start a new primitive strip // Example: outputting points instead of a triangle p.Position = input[0].Position; output.Append(p); p.Position = input[1].Position; output.Append(p); p.Position = input[2].Position; output.Append(p); output.RestartStrip(); }

Compute Shader - Image Processing (Blur)

A compute shader example for performing image processing tasks, such as applying a Gaussian blur filter.

// Texture representing the input image RWTexture2D SourceTexture : register(u0); // Texture to store the blurred output RWTexture2D DestTexture : register(u1); // Sampler for texture access SamplerState SamplerLinear : register(s0); // Thread group size static const uint3 ThreadGroupSize = uint3(8, 8, 1); [numthreads(ThreadGroupSize.x, ThreadGroupSize.y, ThreadGroupSize.z)] void CSMain(uint3 DTid : SV_DispatchThreadID) { // Pixel coordinates uint2 texelCoord = DTid.xy; uint2 textureSize; SourceTexture.GetDimensions(textureSize.x, textureSize.y); if (texelCoord.x >= textureSize.x || texelCoord.y >= textureSize.y) { return; // Out of bounds } // Simple box blur (replace with Gaussian for better results) float4 sum = 0.0f; for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { uint2 sampleCoord = texelCoord + uint2(x, y); // Clamp coordinates to stay within texture bounds sampleCoord.x = clamp(sampleCoord.x, 0, textureSize.x - 1); sampleCoord.y = clamp(sampleCoord.y, 0, textureSize.y - 1); sum += SourceTexture[sampleCoord]; } } // Average the samples and write to the destination texture DestTexture[texelCoord] = sum / 9.0f; }

Further Resources

Explore the following links for more in-depth information and advanced techniques: