Skip to main content

opIntersection: Boolean Intersection for SDF Combination

Constructive Solid Geometry Through Distance Field Mathematics

The opIntersection function family performs boolean intersection operations on signed distance fields, creating shapes that exist only where multiple objects overlap. This fundamental CSG operation enables complex geometry construction through simple primitive combination.

Mathematical Foundation

Boolean intersection operates through maximum distance selection:

dintersection=max(d1,d2)d_{\text{intersection}} = \max(d_1, d_2)

For smooth intersection with controlled blending:

h=clamp(12d2d12k,0,1)h = \text{clamp}\left(\frac{1}{2} - \frac{d_2 - d_1}{2k}, 0, 1\right) dsmooth=mix(d2,d1,h)+kh(1h)d_{\text{smooth}} = \text{mix}(d_2, d_1, h) + kh(1-h)

where kk controls the blending radius and hh provides the interpolation factor.

Function Variants

FunctionParametersDescription
opIntersectiond1, d2Sharp boolean intersection
opIntersectionSmoothd1, d2, kSmooth intersection with blending parameter

Implementation Demonstration

Live Editor
const fragment = () => {
      const up = vec3(0, 1, 0)
      const eps = vec3(0.01, 0, 0)
      const eye = rotate3dY(iTime).mul(vec3(4))
      const sdf = Fn(([p]: [Vec3]) => {
              const sphere = sphereSDFRadius(p, 1.2)
              const box = cubeSDF(p, 0.8)
              return opIntersection(sphere, box)
      })
      const march = Fn(([eye, dir]: [Vec3, Vec3]) => {
              const p = eye.toVar()
              const d = sdf(p).toVar()
              Loop(16, ({ i }) => {
                      If(d.lessThanEqual(eps.x), () => {
                              const dx = sdf(p.add(eps.xyy)).sub(d)
                              const dy = sdf(p.add(eps.yxy)).sub(d)
                              const dz = sdf(p.add(eps.yyx)).sub(d)
                              const normal = vec3(dx, dy, dz).normalize()
                              const light = vec3(2, 4, 3).sub(p).normalize()
                              const diffuse = normal.dot(light).max(0.1)
                              return vec4(vec3(diffuse.mul(0.8).add(0.2)), 1)
                      })
                      p.addAssign(d.mul(dir))
                      d.assign(sdf(p))
              })
              return vec4(0)
      })
      const z = eye.negate().normalize()
      const x = z.cross(up)
      const y = x.cross(z)
      const scr = vec3(uv.sub(0.5), 2)
      const dir = mat3(x, y, z).mul(scr).normalize()
      return march(eye, dir)
}