Skip to main content

expand: AABB Uniform Expansion Operation

Symmetric Margin Addition for Bounding Box Inflation

The AABB expand function creates a new bounding box by uniformly expanding the original box along all axes. This operation adds a constant margin to each face while maintaining the box's center position.

Given an AABB with bounds [bmin,bmax][\vec{b_{\min}}, \vec{b_{\max}}] and expansion value ϵ\epsilon, the expanded box is calculated as:

bmin=bminϵbmax=bmax+ϵ\begin{align} \vec{b'_{\min}} &= \vec{b_{\min}} - \epsilon \\ \vec{b'_{\max}} &= \vec{b_{\max}} + \epsilon \end{align}

The expansion value applies uniformly to all dimensions, creating symmetric growth around the original volume.

Geometric Properties

The expansion operation preserves several geometric relationships:

  • Center Invariance: The centroid remains unchanged
  • Proportional Growth: Each dimension increases by 2ϵ2\epsilon
  • Volume Scaling: New volume V=(dx+2ϵ)(dy+2ϵ)(dz+2ϵ)V' = (d_x + 2\epsilon)(d_y + 2\epsilon)(d_z + 2\epsilon)

Applications

AABB expansion serves multiple computational purposes:

  • Collision Detection: Safety margins for broad-phase collision filtering
  • Spatial Queries: Tolerance zones for approximate geometric operations
  • Level of Detail: Progressive quality boundaries for rendering optimization
  • Memory Management: Buffer zones for dynamic object allocation
Live Editor
const fragment = () => Scope(() => {
      const t = iTime.mul(0.5)
      const p = uv.mul(5).sub(2.5)
      const originalBox = AABB({
              minBounds: vec3(t.sin().mul(0.6).sub(0.4), t.mul(1.2).cos().mul(0.5).sub(0.3), 0),
              maxBounds: vec3(t.mul(0.9).sin().mul(0.7).add(0.3), t.mul(0.8).cos().mul(0.6).add(0.4), 0)
      })
      const expansionValue = iTime.mul(2).sin().mul(0.3).add(0.4)
      const expandedBox = expand(originalBox, expansionValue)
      const pos = vec3(p, 0)
      const inOriginal = aabbContain(originalBox, pos)
      const inExpanded = aabbContain(expandedBox, pos)
      const inMargin = inExpanded.and(inOriginal.not())
      const originalColor = vec3(0.8, 0.2, 0.1)
      const marginColor = vec3(0.2, 0.6, 0.9)
      const outsideColor = vec3(0.1, 0.1, 0.2)
      const color = outsideColor.select(marginColor.select(originalColor, inOriginal), inExpanded)
      const origEdge = p.x.sub(originalBox.minBounds.x).abs()
                  .min(p.x.sub(originalBox.maxBounds.x).abs())
                  .min(p.y.sub(originalBox.minBounds.y).abs()
                  .min(p.y.sub(originalBox.maxBounds.y).abs()))
      const expEdge = p.x.sub(expandedBox.minBounds.x).abs()
                 .min(p.x.sub(expandedBox.maxBounds.x).abs())
                 .min(p.y.sub(expandedBox.minBounds.y).abs()
                 .min(p.y.sub(expandedBox.maxBounds.y).abs()))
      const wireframe = smoothstep(0.02, 0.04, origEdge).oneMinus().add(smoothstep(0.01, 0.03, expEdge).oneMinus().mul(0.5))
      return vec4(color.add(wireframe.mul(0.3)), 1)
})