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

capsuleSDF: Three-Dimensional Capsule Distance Field

Cylindrical Form with Rounded Endpoints​

The capsuleSDF function computes the signed distance from any 3D point to a capsule shape. A capsule is essentially a cylinder with hemispherical caps, defined by two endpoint positions and a radius value.

Mathematical Foundation​

The capsule SDF operates through line segment projection and distance calculation:

dcapsule=∥pa⃗−ba⃗⋅h∥−rd_{\text{capsule}} = \|\vec{pa} - \vec{ba} \cdot h\| - r

where the projection parameter is computed as:

h=clamp(pa⃗⋅ba⃗ba⃗⋅ba⃗,0,1)h = \text{clamp}\left(\frac{\vec{pa} \cdot \vec{ba}}{\vec{ba} \cdot \vec{ba}}, 0, 1\right)

The vectors are defined as pa⃗=p−a\vec{pa} = p - a and ba⃗=b−a\vec{ba} = b - a, where aa and bb are the capsule endpoints.

Function Signature​

ParameterTypeDescription
pvec3Sample point position
avec3First endpoint of capsule axis
bvec3Second endpoint of capsule axis
rfloatCapsule radius

Implementation Demonstrations​

ライブエディター

const fragment = () => {
      const pos = vec3(uv.x.mul(4).sub(2), uv.y.mul(4).sub(2), 0)
      const startPoint = vec3(-1, -0.5, 0)
      const endPoint = vec3(1, 0.5, 0)
      const radius = 0.3
      const dist = capsuleSDF(pos, startPoint, endPoint, radius)
      const inside = dist.step(0)
      const edge = float(0.02).smoothstep(0, dist.abs())
      const color = inside.mul(0.8).add(edge.mul(0.4))
      return vec4(vec3(color), 1)
}
結果
Loading...
ライブエディター

const fragment = () => {
      const up = vec3(0, 1, 0)
      const eps = vec3(0.01, 0, 0)
      const eye = rotate3dY(iTime).mul(vec3(5))
      const args = [vec3(-1, -1, 0), vec3(1, 1, 0), 0.3]
      const march = Fn(([eye, dir]: [Vec3, Vec3]) => {
              const p = eye.toVar()
              const d = capsuleSDF(p, ...args).toVar()
              Loop(16, ({ i }) => {
                      If(d.lessThanEqual(eps.x), () => {
                              const e = vec3(0.001, 0, 0)
                              const dx = capsuleSDF(p.add(eps.xyy), ...args).sub(d)
                              const dy = capsuleSDF(p.add(eps.yxy), ...args).sub(d)
                              const dz = capsuleSDF(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(capsuleSDF(p, ...args))
              })
              return vec4(0.2, 0.2, 0.2, 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)
}
結果
Loading...