@vshaders/sdf
v0.2.0
Published
Signed distance field primitives and operators as pure WGSL modules, importable from vgpu shaders
Downloads
305
Maintainers
Readme
@vshaders/sdf
Signed distance field primitives and operators as pure WGSL modules, importable from vgpu shaders:
import { sdCircle } from "@vshaders/sdf/2d";
import { opSmoothUnion } from "@vshaders/sdf/ops";
@fragment fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
let p = position.xy / 512.0 - vec2f(0.5);
let d = opSmoothUnion(sdCircle(p - vec2f(0.15, 0.0), 0.2), sdCircle(p + vec2f(0.15, 0.0), 0.2), 0.1);
return vec4f(vec3f(smoothstep(0.01, -0.01, d)), 1.0);
}Every module is pure WGSL — functions only, no bindings, no entry points — so vgpu's resolver can prune whatever you don't import. Distances follow the usual convention: negative inside, zero on the boundary, positive outside, in the same units as p.
@vshaders/sdf/2d
Shapes centered at the origin; translate by evaluating at (p - center).
sdCircle(p: vec2f, radius: f32) -> f32sdBox2(p: vec2f, halfSize: vec2f) -> f32— exact distance, including corners.sdRoundedBox2(p: vec2f, halfSize: vec2f, cornerRadius: f32) -> f32—halfSizeis the box's outer half-extent;cornerRadiusmust not exceedmin(halfSize.x, halfSize.y).sdSegment2(p: vec2f, start: vec2f, end: vec2f) -> f32— distance to the line segment; a zero-length segment degrades to distance-to-point.sdRing(p: vec2f, radius: f32, halfThickness: f32) -> f32— annulus around the origin.sdHalfPlane(p: vec2f, normal: vec2f, offset: f32) -> f32—normalmust be unit length.
@vshaders/sdf/3d
sdSphere(p: vec3f, radius: f32) -> f32sdBox3(p: vec3f, halfSize: vec3f) -> f32— exact distance, including edges and corners.sdRoundedBox3(p: vec3f, halfSize: vec3f, cornerRadius: f32) -> f32sdTorus(p: vec3f, majorRadius: f32, minorRadius: f32) -> f32— ring in the XZ plane.sdCapsule3(p: vec3f, start: vec3f, end: vec3f, radius: f32) -> f32— a zero-length capsule degrades to a sphere atstart.sdCylinderY(p: vec3f, radius: f32, halfHeight: f32) -> f32— finite cylinder along Y.sdPlane(p: vec3f, normal: vec3f, offset: f32) -> f32—normalmust be unit length.
@vshaders/sdf/ops
Boolean operators take distances already evaluated at the same point. Smooth variants blend over a band of smoothness world units; smoothness <= 0 degrades to the sharp operator instead of dividing by zero.
opUnion(d1: f32, d2: f32) -> f32opIntersect(d1: f32, d2: f32) -> f32opSubtract(base: f32, cut: f32) -> f32— removescutfrombase.opSmoothUnion(d1: f32, d2: f32, smoothness: f32) -> f32— polynomial smooth minimum.opSmoothIntersect(d1: f32, d2: f32, smoothness: f32) -> f32opSmoothSubtract(base: f32, cut: f32, smoothness: f32) -> f32opRound(d: f32, radius: f32) -> f32— grow outward byradius, rounding corners.opOnion(d: f32, halfThickness: f32) -> f32— hollow into a shell.repeat2(p: vec2f, period: vec2f) -> vec2f,repeat3(p: vec3f, period: vec3f) -> vec3f— infinite domain repetition. Apply topbefore evaluating a distance function; a period component<= 0leaves that axis unrepeated. Note the repeated field is only exact for shapes smaller than half the period.
Provenance
Exact box/sphere/segment/torus/cylinder distances and the polynomial smooth minimum are standard published constructions from the computer graphics literature (Hart's sphere tracing lineage; the smooth-minimum polynomial form as popularized in Inigo Quilez's articles). All WGSL implementations here are original transcriptions of those published formulas, with explicit edge-case guards (zero-length segments, non-positive smoothness or period) in the argument ranges the formulas leave undefined.
Verifying
npx vgpu check path/to/your-entry-shader.wgslresolves the import graph, validates the composed shader, and prints its reflection.
License
MIT
