Physics engines handle two very different workloads. Rigid bodies need the penetration depth and separation direction queries covered in SDF collision detection . Particle systems and soft-body interactions need the opposite: per-particle queries against complex implicit surfaces, at scales where mesh-based methods would be prohibitively expensive. This article covers the three ways SDFs serve that workload: discrete collision response, continuous force fields, and the level-set representation used in grid-based fluid simulation.
If the sign convention or the gradient is fuzzy, the Signed Distance Fields overview builds both up from first principles. For the high-level picture across the engine, see SDFs in game development .
Particle Collision Response
When a particle enters a volume defined by an SDF (that is, when ), the response logic needs to project the particle back to the surface and reflect its velocity. The SDF provides everything needed in two evaluations:
void resolveParticleCollision(inout vec3 position, inout vec3 velocity,
SDF volume, float bounceFactor) {
float d = evaluateSDF(position, volume);
if (d >= 0.0) return; // Not penetrating
vec3 normal = normalize(gradientSDF(position, volume));
// Push particle back to surface
position -= d * normal;
// Reflect velocity about the surface normal
float vn = dot(velocity, normal);
if (vn < 0.0) {
velocity -= (1.0 + bounceFactor) * vn * normal;
}
}
The gradient gives the surface normal at the nearest boundary point, and multiplying by the negative distance -d projects the particle exactly to the surface. The velocity reflection uses the standard mirror formula with a configurable bounce factor that controls energy loss on impact. A factor of 1.0 preserves all kinetic energy (perfect elastic bounce); 0.0 kills the normal component entirely (the particle slides along the surface).
A worked example shows each line doing real work. Take a sphere SDF of radius 1 at the origin, a particle at with velocity , and a bounce factor of 0.8.
The distance evaluation: , so . The particle is 0.057 units below the surface. The normalized gradient is .
Projection: position -= d * normal adds , giving , whose length is exactly 1. The particle sits on the surface.
Reflection: . Because (the particle was moving inward), the velocity update subtracts from the velocity, giving . The inward component was removed and reversed with a bounce: the particle leaves the surface with a normal component scaled by the bounce factor.
This pattern scales to millions of particles on the GPU because each particle needs only one distance evaluation and one gradient evaluation, both of which are pure arithmetic. There is no acceleration structure to traverse and no triangle to locate. The gradient itself costs more than the distance: a central-difference gradient samples the field six times, or four times with a tetrahedral stencil, so a full collision response is roughly seven field evaluations per particle. That is still trivially cheap compared to locating and testing a triangle.
Two edge cases deserve attention. Particles that enter deeper than their radius in one step (the discrete version of the tunneling problem) need the same sphere casting from the collision spoke, or a cap on the per-step correction so a single violent impact does not teleport the particle to the wrong side of the field. And when the bounce factor is 0, the reflection line is skipped entirely and only the projection runs; this is the common setup for smoke and dust, which should settle and slide rather than ping-pong.
SDF-Based Force Fields
The SDF gradient can also drive continuous forces instead of discrete collision events. A repulsion field keeps particles away from a volume by applying a force proportional to how close they are:
vec3 sdfRepulsionForce(vec3 position, SDF volume, float maxDistance, float strength) {
float d = evaluateSDF(position, volume);
if (d > maxDistance) return vec3(0.0);
// Force falls off linearly from maxDistance to surface,
// then increases linearly for penetration
float forceMagnitude = strength * (1.0 - d / maxDistance);
vec3 direction = normalize(gradientSDF(position, volume));
return forceMagnitude * direction;
}
This creates a soft boundary that particles slide along rather than hitting with a discrete bounce. At the surface itself the force is at full strength, at maxDistance it is zero, and between them it falls off linearly. The same gradient direction that serves collision response now serves as the force direction.
A worked example: a particle 0.5 units outside a surface, with maxDistance = 2.0 and strength = 3.0. The force magnitude is , pushing directly away from the surface. A particle 1.5 units out receives , a quarter of the force. The relationship is a straight line from full force at the surface to nothing at the cutoff radius, which makes the boundary feel soft and predictable.
The force field is useful for wind fields around buildings (the building is a union of box SDFs, and particles feel a push near its faces and edges), magnetic repulsion effects, and keeping smoke particles inside a container defined by CSG operations. Because the force depends only on the field and the point, it composes with any other force (gravity, drag, turbulence) by simple vector addition.
The Fluid Simulation Connection
Distance fields are also central to grid-based fluid simulation, where the same representation appears in two places. In the level-set method, the fluid surface is tracked implicitly as the zero level set of a signed distance function. Each simulation step advects the field with the fluid velocity, then renormalizes it so it stays close to a true distance field; the surface is wherever the field crosses zero. This avoids the topology headaches of tracking an explicit surface mesh through splashes, droplets, and merging bodies of fluid.
The SDF also reappears in the pressure projection step, where the Poisson equation is solved on grid cells classified as fluid, solid, or air by their distance sign. Cells inside solid geometry (negative distance to the solid field) get boundary conditions that push the velocity field out of obstacles. The same field that defines the visible fluid surface also defines where the pressure solve is constrained.
This is a deeper topic than one section can cover, but it is worth knowing that the SDF representation extends seamlessly from real-time game physics into full computational fluid dynamics: same field, same sign convention, same zero level set, just with advection and renormalization added on top.
Summary
At particle scale, the SDF contract replaces search with arithmetic:
- Collision response evaluates the field once for penetration, reads the gradient for the normal, projects the particle to the surface, and reflects the velocity with a configurable bounce.
- Force fields scale the gradient by a falloff function to create soft boundaries that particles slide along instead of bouncing off.
- Fluid simulation tracks the surface as an advected level set and constrains the pressure solve with distance signs.
The penetration math that starts this chain, minimum translation vectors and sphere casts, is the subject of the collision detection deep-dive . The other side of SDF physics, what happens when the environment itself deforms, lives in the destructible terrain deep-dive .