Sdf Basics
A Signed Distance Field maps every point in space to its shortest signed distance to the nearest surface. Negative values indicate interior, positive values indicate exterior, and zero marks the boundary.
Signed Distance Field:
1# Signed Distance Field concept2# For any point P in space, SDF(P) returns:3# negative -> P is inside the shape4# zero -> P is on the surface5# positive -> P is outside the shape67def sdf_example(point, center, radius):8 """Signed distance from point to sphere surface."""9 import math10 dx = point[0] - center[0]11 dy = point[1] - center[1]12 dz = point[2] - center[2]13 dist = math.sqrt(dx*dx + dy*dy + dz*dz)14 return dist - radius # negative inside, positive outside
The sphere SDF is the simplest primitive: distance from the center minus the radius. The isosurface at distance zero forms a perfect sphere.
Sphere SDF:
1# Sphere SDF2def sdf_sphere(point, center, radius):3 """Returns signed distance from point to sphere surface."""4 import math5 dx = point[0] - center[0]6 dy = point[1] - center[1]7 dz = point[2] - center[2]8 return math.sqrt(dx*dx + dy*dy + dz*dz) - radius
The box SDF uses absolute-value symmetry and component-wise clamping to compute exact signed distance to an axis-aligned box.
Box SDF:
1# Box SDF (axis-aligned)2def sdf_box(point, center, half_extents):3 """Signed distance from point to axis-aligned box."""4 import math5 # Compute distance per axis from center, subtract half-extents6 dx = abs(point[0] - center[0]) - half_extents[0]7 dy = abs(point[1] - center[1]) - half_extents[1]8 dz = abs(point[2] - center[2]) - half_extents[2]910 # Outside distance: length of positive components11 outside = math.sqrt(max(dx, 0)**2 + max(dy, 0)**2 + max(dz, 0)**2)12 # Inside distance: largest negative component13 inside = min(max(dx, max(dy, dz)), 0.0)1415 return outside + inside
The torus SDF reduces a 3D problem to 2D by projecting onto the plane of revolution, then computing distance from the ring centerline.
Torus SDF:
1# Torus SDF2def sdf_torus(point, major_radius, minor_radius):3 """Signed distance to a torus centered at origin, axis along Y."""4 import math5 # Project point onto XZ plane6 qx = math.sqrt(point[0]**2 + point[2]**2) - major_radius7 qy = point[1]8 return math.sqrt(qx*qx + qy*qy) - minor_radius
To evaluate an SDF on a transformed shape, we inverse-transform the query point back into the primitive's local coordinate frame.
SDF Transform:
1# Rigid transform for SDF evaluation2import numpy as np34def sdf_transformed(point, sdf_fn, translation, rotation_matrix):5 """Evaluate SDF by inverse-transforming the query point."""6 # Inverse transform: undo translation, then undo rotation7 p_local = rotation_matrix.T @ (np.array(point) - np.array(translation))8 return sdf_fn(p_local)910# Key insight: instead of transforming the shape,11# inverse-transform the query point into local space.
Uniform scaling preserves SDF accuracy by dividing the query point and multiplying the result. Non-uniform scale breaks exactness and requires conservative approximation.
SDF Scale:
1# Non-uniform scale for SDF2def sdf_scaled(point, sdf_fn, scale_factors):3 """Evaluate SDF on non-uniformly scaled shape.45 Warning: Non-uniform scale breaks exact distance.6 Compensate by dividing result by max scale factor.7 """8 import numpy as np9 s = np.array(scale_factors)10 p_local = np.array(point) / s11 # Approximate correction for non-uniform scale12 return sdf_fn(p_local) * min(s)
The gradient of an SDF at a surface point gives the outward surface normal. We approximate it numerically using central finite differences.
SDF Gradient:
1# Normal estimation via central differences (gradient of SDF)2def sdf_normal(sdf_fn, point, eps=1e-4):3 """Compute surface normal using finite differences."""4 nx = sdf_fn([point[0]+eps, point[1], point[2]]) - \5 sdf_fn([point[0]-eps, point[1], point[2]])6 ny = sdf_fn([point[0], point[1]+eps, point[2]]) - \7 sdf_fn([point[0], point[1]-eps, point[2]])8 nz = sdf_fn([point[0], point[1], point[2]+eps]) - \9 sdf_fn([point[0], point[1], point[2]-eps])1011 import math12 length = math.sqrt(nx*nx + ny*ny + nz*nz)13 return [nx/length, ny/length, nz/length]
To find the closest surface point, iteratively step along the negative gradient by the SDF value until convergence to the zero isosurface.
SDF Projection:
1# Surface projection using SDF gradient descent2def project_to_surface(sdf_fn, start_point, max_iter=20, eps=1e-4):3 """Project a point onto the zero isosurface via gradient descent."""4 p = list(start_point)5 for _ in range(max_iter):6 d = sdf_fn(p)7 if abs(d) < eps:8 break9 n = sdf_normal(sdf_fn, p, eps)10 # Step along negative gradient by distance value11 p = [p[i] - d * n[i] for i in range(3)]12 return p