メインコンテンツまでスキップ

opExtrude: Two-Dimensional to Three-Dimensional SDF Extrusion

Geometric Dimensional Extension Operation​

The opExtrude function transforms a 2D signed distance field into a 3D volume by extruding along the Z-axis. This operation creates cylindrical or prismatic shapes from planar geometry by combining the 2D distance with Z-axis boundary constraints.

Mathematical Foundation​

The extrusion operation combines 2D distance with axial bounds:

dextrude=min⁡(max⁡(d2D,∣pz∣−h),0)+∣max⁡(w⃗,0)∣d_{\text{extrude}} = \min(\max(d_{2D}, |p_z| - h), 0) + |\max(\vec{w}, 0)|

where w⃗=(d2D,∣pz∣−h)\vec{w} = (d_{2D}, |p_z| - h) represents the combined distance vector and hh defines the extrusion height.

This formulation creates smooth transitions at edges while maintaining correct interior and exterior classifications.

Function Signature​

ParameterTypeDescription
pvec33D sample point position
sdffloat2D SDF result at point (p.x, p.y)
hfloatHalf-height of extrusion

Implementation Demonstration​

ライブエディター

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)
              const box = cubeSDF(p, 0.25)
              return opExtrude(p, 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)
}
結果
Loading...