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

opRound: Edge Rounding Operation

Geometric Edge Softening for Distance Fields

The opRound operation applies uniform rounding to SDF shapes by subtracting a rounding radius from the distance field. This technique smooths sharp edges and corners, creating more organic and visually pleasing geometry.

Mathematical Foundation

The rounding operation is mathematically straightforward:

drounded=doriginalrd_{\text{rounded}} = d_{\text{original}} - r

where rr is the rounding radius. This operation effectively expands the surface inward by the rounding distance, creating smooth transitions at previously sharp edges.

Function Signature

ParameterTypeDescription
dfloatOriginal SDF distance value
hfloatRounding radius (softening amount)

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 cube = cubeSDF(p, 0.5)
              return opRound(cube, 0.3)
      })
      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)
}