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

octahedronSDF: Regular Octahedral Distance Field

Eight-Sided Polyhedron with Dual Precision Methods

The octahedronSDF function family generates signed distance fields for regular octahedral geometry. This implementation provides both a fast approximation and an exact distance calculation, offering flexibility between computational efficiency and mathematical precision.

Mathematical Foundation

The octahedron can be defined as the set of points where the sum of absolute coordinates equals the size parameter:

x+y+z=s|x| + |y| + |z| = s

For the fast approximation:

dfast=(x+y+zs)3d_{\text{fast}} = \frac{(|x| + |y| + |z| - s)}{\sqrt{3}}

where 130.57735027\frac{1}{\sqrt{3}} \approx 0.57735027 provides the correct scaling factor.

For exact distance calculation:

o=min(3pm,0)\vec{o} = \min(3\vec{p} - m, 0) o=max(6p2m3o+(ox+oy+oz),0)\vec{o} = \max(6\vec{p} - 2m - 3\vec{o} + (o_x + o_y + o_z), 0) dexact=psoox+oy+ozd_{\text{exact}} = |\vec{p} - s \cdot \frac{\vec{o}}{o_x + o_y + o_z}|

Function Variants

FunctionMethodDescription
octahedronSDFFast approximationEfficient calculation using scaling factor
octahedronSDFExactExact distancePrecise distance with iterative refinement

Implementation Demonstrations

ライブエディター
const fragment = () => {
      const up = vec3(0, 1, 0)
      const eps = vec3(0.01, 0, 0)
      const eye = rotate3dY(iTime).mul(vec3(4))
      const args = [1.2]
      const march = Fn(([eye, dir]: [Vec3, Vec3]) => {
              const p = eye.toVar()
              const d = octahedronSDF(p, ...args).toVar()
              Loop(32, ({ i }) => {
                      If(d.lessThanEqual(eps.x), () => {
                              const dx = octahedronSDF(p.add(eps.xyy), ...args).sub(d)
                              const dy = octahedronSDF(p.add(eps.yxy), ...args).sub(d)
                              const dz = octahedronSDF(p.add(eps.yyx), ...args).sub(d)
                              return vec4(vec3(dx, dy, dz).normalize().mul(0.5).add(0.5), 1)
                      })
                      p.addAssign(d.mul(dir))
                      d.assign(octahedronSDF(p, ...args))
              })
              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)
}