Signed Distance Fields: A Visual Introduction

EN NL ES PT-BR


Signed distance fields (SDFs) answer the question that matters most in procedural graphics: where is the nearest surface, and which side am I on? Knowing the distance to the surface at any point is what makes ray marching, collision checks, and shape composition work with simple arithmetic instead of expensive geometry processing. Instead of storing triangles or curve segments directly, you store a function and evaluate it wherever you need information. That makes SDFs a natural fit for procedural graphics, where shapes are often created, combined, and animated mathematically.

What a Single Number Can Tell You

For any point in space, an SDF returns a signed scalar value d(p)d(\mathbf{p}) at position p\mathbf{p}:

  • positive outside the shape
  • zero on the surface
  • negative inside the shape

The absolute value d(p)|d(\mathbf{p})| is the shortest distance to the boundary, and the sign tells which side you are on. If d(p)=0.12d(\mathbf{p}) = -0.12, the point is 0.12 units inside the shape. If d(p)=0.12d(\mathbf{p}) = 0.12, it is 0.12 units outside. At zero, you are on the surface. One number gives you both a side label and a distance.

That means one scalar field stores more than a binary mask. Negative values trace contours inside the shape, zero marks the boundary itself, and positive values trace contours outside.

Inside Surface Outside

In the explorer, hover over the heatmap to inspect the signed distance at any point. The readout shows the value (negative inside, positive outside) and labels each location as Inside, Surface, or Outside. The zero-contour, the shape boundary itself, is always visible as a crisp black line. Use the dropdown to switch between shapes: Circle, Box, Rounded Box, Line Segment, Capsule, and Regular Polygon all work the same way even though the geometry changes. Each shape displays its SDF formula above the parameter sliders, so you can connect the math to the field as you adjust radius, width, or rounding.

Because the SDF encodes distance at every point, you can offset the surface by a fixed amount just by subtracting a margin value. That creates a collision buffer, an inset for bevels, or an expanded shell without changing the original shape. The same field that defines the surface also answers how far away everything else is, which is why SDFs appear across rendering, physics, and isosurface extraction pipelines with no format conversion in between.

Formulas for Primitive Shapes

Every SDF scene starts from simple building blocks. Each primitive has a compact formula, and once you understand how a few of them work, the pattern behind all the others becomes clear.

The circle is the natural starting point:

d(p)=pcrd(\mathbf{p}) = \|\mathbf{p} - \mathbf{c}\| - r

The term pc\|\mathbf{p} - \mathbf{c}\| measures the Euclidean distance from the sample point p\mathbf{p} to the circle center c\mathbf{c}. Subtracting the radius rr shifts the zero crossing outward to the circle boundary. When the point lies exactly on the boundary, the distance to the center equals rr and the formula returns zero. Outside the circle, the distance to the center exceeds rr, so the result is positive. Inside, it is smaller than rr, so the result is negative and its magnitude tells you how far inward the point sits.

In code, the circle formula is a one-liner:

float circleSDF(vec2 p, vec2 center, float r) {
    return length(p - center) - r;
}

The box builds on the same idea but uses component-wise distance logic. For a box centered at c\mathbf{c} with half-size b\mathbf{b}:

q=pcbd(p)=max(q,0)+min(max(qx,qy),0)\begin{aligned} \mathbf{q} &= |\mathbf{p} - \mathbf{c}| - \mathbf{b} \\ d(\mathbf{p}) &= \|\max(\mathbf{q}, 0)\| + \min(\max(q_x, q_y), 0) \end{aligned}

The first step shifts the point into the box’s local coordinate frame and subtracts the half-extents. If every component of q\mathbf{q} is negative, the point is inside the box. The second step computes the final distance: max(q,0)\|\max(\mathbf{q}, 0)\| gives the Euclidean distance from the outside (zero when inside), and min(max(qx,qy),0)\min(\max(q_x, q_y), 0) gives the penetration depth while inside (zero when outside). Adding them together produces one signed value that follows the SDF contract everywhere: positive outside, negative inside, zero on the surface.

In code:

float boxSDF(vec2 p, vec2 center, vec2 halfSize) {
    vec2 q = abs(p - center) - halfSize;
    return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0);
}

The two terms on the last line correspond directly to the outside and inside cases from the explanation above. When the point is outside, max(q.x, q.y) is positive and the min term is zero. When the point is inside, max(q, 0.0) is zero and the min term carries the negative penetration depth.

The same circle formula generalizes directly to three dimensions: swap the 2D length for a 3D length and the radius stays the same. The result is the signed distance field for a sphere , one of the few shapes with an exact distance everywhere in space and the natural starting point for building more complex SDF scenes.

For a comprehensive reference covering triangles, capsules, toruses, and many other shapes, see Iñigo Quilez’s distance function catalog.

Combining Shapes with Constructive Solid Geometry

A single SDF primitive is rarely enough. Most scenes are built by combining several fields. This strategy of building complex shapes from simpler ones with boolean-like operations is called constructive solid geometry (CSG). With SDFs, CSG is just a few min and max operations on distance values rather than the complicated mesh-cutting algorithms that triangle-based booleans require.

The standard CSG operators for SDFs are:

  • union: min(a, b)
  • intersection: max(a, b)
  • subtraction (A minus B): max(a, -b)

The union case is the most important starting point. At any sample point, the closest surface controls the combined field value, so the minimum distance is the correct result. In subtraction mode max(dA, -dB), points inside B flip sign and carve space out of A. This is how holes, cutouts, and negative-space forms are built in constructive SDF modeling. It is also how real-time destructible terrain works: carving a crater is a single subtraction, and each deformation just adds one more term to the CSG tree.

0.50
0 primitives
Inside Outside

The visualization starts in Subtraction mode: the ring carves a rounded hole out of the box. The color map shows the signed distance field across the whole space: blue outside, red inside, with a bright contour on the zero surface. Switch to Union to see the two shapes merge along their closest edges, then to Intersection to see only the overlapping region preserved. The hover readout shows the exact signed distance at any point, reinforcing that each operation is simply evaluating a math expression on the two fields. Add more primitives with the palette buttons and drag them into overlapping positions to see how more complex fields compose.

Smooth Blending

Hard min and max produce sharp CSG boundaries. For many visual styles that is what you want. For organic transitions, smooth variants are common. One popular option is smooth minimum (smin) with parameter kk:

h=clamp(0.5+0.5bak,0,1),smin(a,b,k)=mix(b,a,h)kh(1h)h = \mathrm{clamp}\left(0.5 + 0.5\frac{b-a}{k}, 0, 1\right), \quad \mathrm{smin}(a,b,k) = \mathrm{mix}(b,a,h) - k h(1-h)

As kk increases, the blend region widens. As k0k \to 0, behavior approaches hard min. The same idea extends to smooth subtraction and smooth intersection variants.

0.50
0 primitives
Inside Outside

Here the operation is set to Smooth Union from the start. The two shapes overlap with a softened boundary where they meet. Drag the blend slider upward to widen the blend region, or switch back to Union to compare the sharp join side by side with the smooth version. The hover readout shows how the combined distance value changes as the kk parameter softens the transition.

This is the main reason SDF scene code stays compact. A whole scene graph can collapse into one function that returns one scalar. You can evaluate that same function for rendering, collision checks, masking, and effects.

Smooth composition is powerful, but it changes local curvature and sometimes field quality. If your pipeline depends on strict distance guarantees for long ray steps, aggressive smoothing can require tighter thresholds or more conservative step logic.

Domain Transforms and Repetition

Another major SDF strength is domain transformation. Instead of changing the shape function itself, you transform input coordinates before evaluation:

  1. Translation: evaluate at pt\mathbf{p} - \mathbf{t}
  2. Rotation: evaluate at R1pR^{-1}\mathbf{p}, where R1R^{-1} is the inverse of the rotation matrix (applying the opposite rotation to the input point)
  3. Scale: evaluate at p/s\mathbf{p}/s and rescale distance by ss
  4. Repetition: wrap coordinates with mod or fract to repeat a shape in a grid

These transformations let one primitive definition create many instances. For example, a single circle SDF can become a grid of circles by feeding the input coordinates through a mod operation that tiles them across space. This is one reason SDFs are common in shader-based procedural scenes where concise scene definitions are important.

Domain operations also combine naturally with noise modulation. You can use value, Perlin, and fractal noise to perturb coordinates or distances for rocky, molten, or cloud-like surfaces while keeping a function-first modeling workflow.

Baked Fields: Sampling Geometry into a Grid

Not every shape arrives as a tidy formula. Font glyphs, destructible terrain, scanned models, and artist-authored polygon meshes all need SDFs but lack closed-form expressions. For geometry like that, the field must be computed and stored rather than derived analytically.

The process is called baking: pre-compute signed distances at each point of a regular grid, save the samples, and interpolate between them to answer future queries. It trades compute-at-query-time for compute-once-read-many, and exact distance for approximate distance.

Inside Outside Surface

Press play to watch the per-cell evaluation: each grid point finds its nearest polygon edge and records a signed distance. The color overlay shows bilinear interpolation reconstructing the field from those discrete samples. At low resolution the zero-contour visibly deviates from the true edges and corners round off. Raising the resolution shrinks the error, but doubling it costs 4× the samples in 2D and 8× in 3D.

Once baked, the same downstream techniques still apply. CSG operations, surface normals, and ray marching all consume the same scalar values regardless of whether a formula or a grid produced them, though interpolated fields need wider step safety margins because they do not preserve the exact distance guarantee. For a deeper look at resolution choices, interpolation artifacts, adaptive sampling, and production applications like Valve’s SDF text rendering and Unreal Engine 5 mesh distance fields, see the baked signed distance fields article.

Surface Normals from the SDF Gradient

Once a ray marcher or other query finds a surface point, the next question is usually which direction that surface faces. Surface normals are essential for lighting, reflections, and collision response: they tell you how light bounces off the surface and which way objects should slide when they touch.

An SDF can answer this without storing a separate normal buffer. Because the field encodes distance at every point, the direction in which distance increases most quickly always points away from the nearest surface. Near the boundary, that direction is the outward-facing surface normal. Mathematically, the gradient d(p)\nabla d(\mathbf{p}) gives this direction.

Gradient arrow Surface normal

The visualization overlays gradient arrows on the SDF heatmap. Every arrow points in the direction of f\nabla f at its sample location, and you can see the pattern immediately: all arrows radiate outward from the nearest surface, regardless of shape. Hover anywhere over the field and a probe appears with the signed distance, gradient direction, and gradient magnitude at that exact point. The readout labels the arrow as a surface normal whenever the cursor is near the zero-contour, making the gradient-to-normal relationship explicit. Click to pin the probe in place, then switch between circle, box, rounded box, line segment, and a composite union of two circles to confirm that normals emerge from the field structure the same way across every shape.

Notice that the gradient magnitude stays at or near 1 across the whole field. This is the eikonal property (f=1|\nabla f| = 1) that makes exact SDFs special: the gradient direction is already a unit vector. When the probe sits on the zero-isosurface, the arrow lies exactly perpendicular to the surface boundary. That perpendicular direction is the surface normal, and because the gradient magnitude is 1, no separate normalization step is needed beyond dividing by the finite-difference constant.

In practice, gradients are estimated numerically using finite differences, which means sampling the SDF at points slightly offset in each axis and measuring how much the distance changes:

d(p)[d(p+εx)d(pεx)d(p+εy)d(pεy)]\nabla d(\mathbf{p}) \approx \begin{bmatrix} d(\mathbf{p}+\varepsilon_x)-d(\mathbf{p}-\varepsilon_x) \\ d(\mathbf{p}+\varepsilon_y)-d(\mathbf{p}-\varepsilon_y) \end{bmatrix}

The orange dots around the probe show exactly these sample points: two along the x-axis at ±ε\pm\varepsilon and two along the y-axis, each labeled with the distance value sampled there. Drag the ε\varepsilon slider to see the tradeoff. At very small ε\varepsilon (0.001), the stencil points crowd close to the probe and the gradient can become noisy. At larger ε\varepsilon (0.5), the stencil spreads wide and the gradient smooths out but may misalign from the true surface normal near tight corners or high-curvature regions. The default ε=0.01\varepsilon = 0.01 balances accuracy and stability for most analytical SDFs.

After computing both components, normalize the resulting vector before feeding it into lighting calculations. This is central in field rendering because there is no explicit mesh normal buffer to query. The same SDF that locates the surface also estimates its orientation for diffuse and specular lighting, reflections, or ambient effects.

Field Quality and Distance Guarantees

Not every signed distance field is an exact distance field. An SDF derived from a formula (like the circle or box examples earlier) returns the true Euclidean distance to the nearest surface. A field baked from a mesh, a smoothed CSG blend, or a distance estimator from a noise function might return a value that is signed and roughly distance-like but is not a strict upper bound on how far a ray can safely step.

The distinction matters because downstream techniques depend on the strength of the distance guarantee. Sphere tracing and sphere casting are provably safe only when the field never overestimates the distance. If a field under-predicts distance (returns 0.2 when the true distance is 0.5), the marcher takes smaller steps than necessary but still converges. If it over-predicts (returns 0.5 when the true distance is 0.2), the marcher can step through a thin wall or narrow feature entirely.

In practice, exact analytical SDFs are preferred when safety margins matter, such as collision detection or long camera rays. Smoothed CSG blends, baked grids, and noise-modulated surfaces all relax the exact-distance guarantee to varying degrees. The ray marching article covers how to manage step safety, epsilon thresholds, and step limits when working with looser distance estimators.

Where SDFs Fit in a Rendering Pipeline

SDFs are best viewed as a geometry representation option, not a universal replacement for meshes. They are excellent when shapes are procedural, deformable, or composition-heavy. Meshes remain strong when you need artist-authored topology, UV workflows, and direct hardware triangle acceleration.

A practical hybrid pipeline typically works like this: rasterize the main scene geometry (characters, buildings, terrain) as triangles, then use SDFs for specific effects that benefit from distance queries. For example:

  • Soft shadows and ambient occlusion can be computed by evaluating an SDF of the static environment as a post-process or during lighting, even though the visible surfaces themselves were rasterized.
  • Decals and procedural details (scorch marks, bullet holes, puddles) can be projected onto rasterized surfaces by evaluating an SDF to determine placement and blending.
  • Volumetric effects like fog, smoke, and light shafts use distance fields to find how far a ray can travel through empty space before hitting a surface, regardless of whether that surface was rasterized or ray-marched.
  • Collision and physics queries against static level geometry use a baked SDF grid while the dynamic objects that query it are standard rigid-body meshes. The same field representation that guides rendering also answers penetration depth, separation direction, and continuous collision queries, with applications that extend into AI pathfinding and real-time soft shadows. For an overview of how these techniques fit together in a game engine, see signed distance fields in game development .

The key insight is that SDF evaluation and triangle rasterization operate in separate passes that feed each other. You can rasterize a character with traditional GPU hardware, then sample a distance field in the fragment shader to add soft self-shadowing from the environment. You can render a particle system as screen-facing quads, then use an SDF in the vertex shader to repel particles from procedural surfaces. The representations coexist because they answer different questions: triangles answer “what color is this pixel?” and SDFs answer “how far is the nearest surface from this point?”

If you want the complete traversal context, ray marching with signed distance fields covers the iterative hit search in detail. For stage-level GPU context, vertex and fragment shaders in the graphics pipeline is useful background.

Summary

Signed distance fields encode shape as a scalar function with two strong guarantees: distance magnitude and inside/outside sign. From that single representation, you can:

  1. march rays with distance-guided safe steps
  2. compose scenes with min and max operators
  3. estimate normals from finite-difference gradients
  4. apply domain transforms to build complex procedural layouts

That combination of compact modeling and reusable evaluation logic is why SDFs remain a core tool in procedural graphics. Once the field contract is clear, many techniques that look advanced become variations of the same loop: evaluate distance, move or shade using that result, repeat.