Accurately calculating reach (distance propagation) within shaders involves efficiently measuring and utilizing fragment distances.
Core Distance Calculation
Fragment shaders primarily measure distance between the current fragment and a specific point (e.g., UV coordinates). Utilize:
- Euclidean Distance:
float dist = distance(*, targetUV);
Most common and intuitive. - Absolute Distance:
float dist = abs(*.x - targetUV.x) + abs(*.y - targetUV.y);
Faster, approximate for Manhattan-like effects. - Squared Euclidean:
float distSq = dot(deltaUV, deltaUV);
Avoids the expensivesqrt
, ideal for comparisons or scaled effects.
Sampling for Influence
Determine reach impact using the calculated distance:

- Linear Falloff:
float influence = saturate(1.0 - dist / maxReach);
- Non-Linear Falloff:
float influence = saturate(1.0 - pow(dist / maxReach, exponent));
(Adjustexponent
for curve shape). - Smoothstep:
float influence = smoothstep(maxReach, 0.0, dist);
Creates smoother transitions at the boundaries.
Practical Considerations
- Normalization: Normalize UV coordinates when working in screen/texture space for consistent distance scaling.
- Precision & Filtering: Distance calculations near discontinuities or using
discard
can cause aliasing. Use MIP filtering judiciously or analytical anti-aliasing techniques where applicable. - Coordinate Space: Choose the most relevant space (World Space, UV Space, Screen Space) for your effect. Transform points accurately into the same space before measuring distance.
- Performance: Minimize vector operations inside loops. Pre-calculate values outside loops where possible. Favor squared distance for comparisons.
Alternative Techniques
- Distance Fields: Precompute a Signed Distance Field (SDF) texture representing distances from a surface. Sample this texture in the shader to achieve very precise reach effects with minimal calculation cost per fragment.
- Compute Shaders: For highly complex propagation requiring iterative analysis or data sharing between pixels, offload calculation to a compute shader and pass the results to rendering shaders.