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

planeSDF: Infinite Plane Distance Field

Fundamental Ground Surface with Arbitrary Orientation

The planeSDF function generates signed distance fields for infinite planes. The basic version creates a horizontal plane at y=0, while the normal variant supports arbitrary plane orientation through point-normal specification.

Mathematical Foundation

For a horizontal plane, the distance function is simply:

dplane(p)=pyd_{\text{plane}}(p) = p_y

For an arbitrary plane defined by point P0P_0 and normal vector n\vec{n}:

dplane(p)=np+nP0nd_{\text{plane}}(p) = \frac{\vec{n} \cdot \vec{p} + \vec{n} \cdot P_0}{|\vec{n}|}

This represents the perpendicular distance from point pp to the plane surface.

Function Variants

FunctionParametersDescription
planeSDFpHorizontal plane at y=0
planeSDFNormalp, planePoint, planeNormalArbitrary orientation plane

Complex Scene Demonstration

ライブエディター
const fragment = () => {
      const up = vec3(0, 1, 0)
      const eps = vec3(0.01, 0, 0)
      const eye = rotate3dY(iTime).mul(vec3(6))
      const sceneMap = Fn(([p]: [Vec3]) => {
              const ground = planeSDF(p.add(vec3(0, 2, 0)))
              const cube = cubeSDF(p, 1)
              return ground.min(cube)
      })
      const march = Fn(([eye, dir]: [Vec3, Vec3]) => {
              const p = eye.toVar()
              const d = sceneMap(p).toVar()
              Loop(64, ({ i }) => {
                      If(d.lessThanEqual(eps.x), () => {
                              const dx = sceneMap(p.add(eps.xyy)).sub(d)
                              const dy = sceneMap(p.add(eps.yxy)).sub(d)
                              const dz = sceneMap(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(sceneMap(p))
              })
              return vec4(0.1, 0.2, 0.4, 1)
      })
      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)
}