Builtin Library
README.md
sdf.mesh (procNode)
A shape contoured into a closed triangle mesh by dual contouring on a uniform grid: one vertex per cell the surface passes through, placed where the surface normals around it agree, so a box comes back with its edges and corners intact; every grid edge the surface crosses bridges the four cells around it with a quad, which makes the result watertight. The cost is the resolution cubed, and the planned sample count is checked against max_samples before anything is allocated.
Inputs
sdf(Sdf): The shape being contoured.resolution(Float, default 32): How many cells span the longest side of the domain; the other two get however many the same cell size gives them. It decides both fidelity and cost, and the cost is its cube: 32 is 36 thousand samples, 64 is 275 thousand, 128 is 2.1 million. A feature thinner than one cell is missed. Below 2 is refused.bounds(Record, optional): The box contoured, as{ min, max }. Unwired, the shape's own bounds are used. It is needed for a shape that has none (sdf.plane, an infinite sdf.repeat) and to contour part of a larger one.padding(Float, default 0.05): Clear space added around the box inside the domain, in metres. The surface must not reach the domain wall, where a crossing edge has fewer than four cells around it and the mesh would be open, so a shape that still runs into the wall is refused.iso(Float, default 0.0): Which level of the field becomes the surface, in metres. 0 is the shape itself; a positive value contours the surface offset outward by that much, a negative one inward.vertex_placement(String, default "qef"): Where each cell's vertex goes: "qef" solves for the point that best fits the surface normals around the cell, which keeps sharp edges and corners; "centroid" averages the crossings on the cell's edges, which reads no normals and rounds every feature off.max_samples(Float, default 2000000): How many grid corners the contour may sample. A request past this is refused.
Outputs
geometry(Geometry): the closed triangle mesh, with a point normalNfrom sdf.gradient.info(Record):samples,cells,cellSize,divisions(cells per axis, a Vec3),bounds(the contoured domain as{ min, max }),crossingCells,quads,vertexCount,triangleCountandwall(how many lattice corners inside the shape sit on the domain wall, 0 for a cook that succeeds).
A call answers both as a record by output name: g.sdf.mesh({ ... }).geometry.
A shape with no bounds and no bounds given is refused, as is a domain with no extent and a surface that reaches the domain wall (raise padding or pass bounds holding the whole shape).
Example
local shape = g.sdf.union({ a = g.sdf.box({ size = vector.create(1, 1, 1) }), b = g.sdf.sphere({ radius = 0.6, center = vector.create(0, 0.5, 0) }), blend = 0.1 })
local mesh = g.sdf.mesh({ sdf = shape, resolution = 24 }).geometry