Depth Bias for Shadow Mapping¶

This example shows how to use depth bias (also called "polygon offset") to solve z-fighting and shadow acne artifacts that occur when rendering shadows or coplanar geometry. Depth bias applies a small offset to fragment depth values during rasterization, ensuring consistent depth test results without modifying vertex positions. This is essential for shadow mapping, decals, and overlaid geometry.
The example uses the KDGpuExample helper API for simplified setup.
Overview¶
What this example demonstrates:
- Configuring depth bias in pipeline rasterization state
- Using
biasConstantFactorfor constant depth offset - Using
biasSlopeFactorfor slope-dependent offset - Eliminating z-fighting between coplanar surfaces
- Common depth bias values for shadow mapping
Use cases:
- Shadow mapping (eliminate shadow acne)
- Decals on surfaces (prevent z-fighting)
- Overlaid geometry (coplanar triangles)
- CSG operations (constructive solid geometry)
Vulkan Requirements¶
- Vulkan Version: 1.0+
- Extensions: None (depth bias is core)
- Features:
depthBias(enabled by default on all devices)
Key Concepts¶
Z-Fighting:
When two surfaces occupy the same depth, floating-point precision errors cause flickering as the GPU can't consistently determine which is in front:
1 2 3 | |
This is "z-fighting" and is especially common with:
- Shadow maps (shadow receiver and occluder at same depth)
- Decals projected onto surfaces
- Coplanar geometry (overlapping triangles)
Depth Bias:
Depth bias adds an offset to fragment depth during rasterization, before depth testing:
1 2 | |
constantFactor: Fixed offset in depth unitsslopeFactor: Offset proportional to surface slope (steeper = more bias)clamp: Maximum bias magnitude (prevents excessive offset)
Shadow Acne:
In shadow mapping, shadow acne appears as incorrect self-shadowing:
1 2 3 | |
Depth bias pushes shadow map depth slightly away from light, preventing false self-shadowing.
Choosing Bias Values:
Too little bias → Shadow acne remains Too much bias → "Peter Panning" (shadows detach from objects)
Typical values:
constantFactor: 1.0 to 4.0 (depth units)slopeFactor: 1.0 to 2.0 (slope-dependent)clamp: 0.0 (disabled) or small positive value
Slope factor is crucial for surfaces at grazing angles to light.
Implementation¶
Pipeline with Depth Bias:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
Filename: depth_bias/depth_bias.cpp
Key configuration:
depthBiasEnable = true: Enables depth biasbiasConstantFactor: Constant depth offsetbiasSlopeFactor: Slope-dependent offset (0 if not needed)biasClamp: Maximum bias magnitude
The biased pipeline ensures consistent depth ordering.
Rendering Coplanar Geometry:
In this example:
- Triangle 1 rendered with no depth bias (standard pipeline)
- Triangle 2 rendered with depth bias (pushed forward/back)
Result: No z-fighting, consistent depth ordering.
For Shadow Mapping:
1 2 3 4 5 6 7 8 | |
This pushes shadow map depth away from light, preventing self-shadowing.
Performance Notes¶
Cost:
- Negligible GPU overhead (computed during rasterization)
- No extra memory or bandwidth
- Fully hardware-accelerated
Depth Precision:
- Depth bias doesn't reduce precision
- Careful tuning needed for wide depth ranges
- Consider reverse-Z for better precision distribution
Dynamic Bias:
- Can't change bias per-draw without pipeline switch
- Alternative: Use dynamic state extension (VK_EXT_extended_dynamic_state2)
- Or pre-create pipelines with different bias values
See Also¶
- Depth Texture Sampling - Sampling shadow maps
- Hello Triangle MSAA - Multi-sampled depth buffers
- Depth Bias Spec - Official documentation
- Shadow Mapping - Shadow mapping tutorial
Further Reading¶
- Shadow Acne Solutions - Comprehensive guide
- Cascaded Shadow Maps - Large-scale shadows
- Reverse-Z - Precision optimization
Updated on 2026-03-31 at 00:02:07 +0000