How Does the Distance Function Work in GLSL?
In OpenGL Shading Language (GLSL), the distance()
function calculates the Euclidean spatial separation between two points
across arbitrary vector dimensions. This article explores the
mathematical formula behind the operation, its underlying hardware
execution on modern graphics processing units, syntax variations across
floating-point types, and optimization techniques such as avoiding
unnecessary square root calculations.
Mathematical Formulation
The distance() function computes the straight-line
Euclidean distance between two points, \(P_0\) and \(P_1\). Mathematically, it evaluates the
length of the displacement vector formed by subtracting one point from
the other:
\[\text{distance}(P_0, P_1) = \Vert{}P_0 - P_1\Vert{}\]
For two \(n\)-dimensional points \(P_0 = (x_0, y_0, \dots)\) and \(P_1 = (x_1, y_1, \dots)\), the distance is expanded using the Pythagorean theorem:
\[\text{distance}(P_0, P_1) = \sqrt{\sum_{i=1}^{n} (P_{0,i} - P_{1,i})^2}\]
In terms of vector operations, this calculation is equivalent to taking the square root of the dot product of the difference vector with itself:
\[\text{distance}(P_0, P_1) = \sqrt{(P_0 - P_1) \cdot (P_0 - P_1)}\]
GLSL Function Signatures
GLSL provides built-in overloads for scalar and vector floating-point
types under the genType classification:
float distance(float p0, float p1): Absolute difference between two 1D scalar values, equivalent toabs(p0 - p1).float distance(vec2 p0, vec2 p1): 2D planar Euclidean distance.float distance(vec3 p0, vec3 p1): 3D spatial Euclidean distance.float distance(vec4 p0, vec4 p1): 4D hyper-spatial Euclidean distance.
GLSL also provides double-precision overloads (genDType)
returning double when using precision qualifiers or
extensions that support 64-bit floating-point math (dvec2,
dvec3, dvec4).
// Example usage in a fragment shader
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
vec2 center = vec2(0.5, 0.5);
// Calculate 2D distance to screen center
float dist = distance(uv, center);GPU Execution and Hardware Implementation
Graphics processing units are optimized for parallel vector math.
When a shader executes distance(p0, p1), the compiler
translates the instruction into a tight sequence of low-level SIMD
(Single Instruction, Multiple Data) operations:
- Vector Subtraction: A component-wise subtraction instruction computes the difference vector \(\Delta = P_0 - P_1\).
- Dot Product / Fused Multiply-Add (FMA): Modern GPU
architectures feature dedicated hardware instructions (such as
DP2,DP3, orDP4) that multiply corresponding components and sum the results in minimal clock cycles. - Square Root: The GPU calculates the square root of
the scalar dot product using dedicated Special Function Units (SFUs),
typically through reciprocal square root instructions (
RSQ) followed by a multiplication step.
Performance Optimization: Squared Distance
While the distance() function is hardware-accelerated,
the square root operation remains computationally more expensive than
basic arithmetic. In scenarios where you only need to compare
distances—such as collision detection, proximity tests, or circular
discard masks—computing the squared distance avoids the square root
entirely.
// Standard approach (includes square root)
if (distance(fragPos, lightPos) < radius) {
// Inside light radius
}
// Optimized approach (avoids square root)
vec3 diff = fragPos - lightPos;
if (dot(diff, diff) < radius * radius) {
// Inside light radius
}Using dot(diff, diff) calculates \(\Delta \cdot \Delta =
\Vert{}\Delta\Vert{}^2\), yielding identical boolean comparison
results while eliminating the square root instruction across millions of
fragment shader invocations.
Common Applications in Shaders
Spatial distance computation serves as a fundamental building block in real-time computer graphics pipelines:
- Point Light Attenuation: Simulating inverse-square light decay based on the distance between a surface fragment and a point light source.
- Signed Distance Fields (SDFs): Evaluating geometric boundaries, raymarching volumetric primitives, and rendering resolution-independent procedural shapes.
- Radial Gradients and Vignettes: Producing smooth circular transitions and screen-space post-processing effects.
- Proximity Blending and Fog: Determining depth-based atmospheric scattering and fragment fog density relative to the camera position.