Builtin Library
- ..
- README.md2.5 KB
- bindings.yaml1.8 KB
- shader.wgsl7.4 KB
README.md
terrain_scatter_place
Turns one tile's density channel into instance transforms in the shared pool
renderer.mesh.drawInstanced reads.
One thread per candidate site, not per cell.
Sites are world-anchored
The sites are a grid of spacing world metres running from the field's minimum
corner. A site belongs to exactly one tile — the one its centre falls in — so
the same field produces the same sites whatever the tiling, whatever the
resolution, and however much of the field is being re-evaluated.
A site carries an instance with probability density * spacing^2. That is what
makes the density channel mean instances per square metre: summed over the
sites of an area, the expected count is the integral of the density over it.
One site carries at most one instance, so 1 / spacing^2 is the densest cover
a spacing can express. terrainScatter derives the spacing from the density
the rule actually reaches rather than letting a caller find that ceiling by
hitting it.
Determinism
Acceptance, the jitter inside the site, the yaw and the scale are all hashes of the site's integer grid indices and the seed. The instance a site carries is therefore the same instance every run: a reload does not reshuffle a forest, and re-evaluating one corner of the field leaves the rest of the population exactly where it stood.
Slots in the pool are handed out by an atomic, so which slot an instance lands in varies between runs. The set of instances and each one's matrix do not.
Overflow is a resize, not a short forest
When the accepted count runs past capacity the counter keeps counting and the
extra instances are not written. The total it reports is what the caller grows
the pool to before running the pass again, which is how a population that grew
past its reservation ends up complete rather than silently clipped.
The matrix layout
Column-major 4x4, four vec4 columns per instance, tightly packed — the layout
a vertex shader reads as array<mat4x4<f32>>. Columns 0..2 are the basis
scaled by the instance's scale; column 3 is the translation.
The op contract's mask
This kernel carries no op_mask / op_common. Those bind the mask every op
that writes GROUND is scaled by, and this one writes instance transforms. Where
a population may grow is already decided by the density channel it reads, and
terrain_scatter_density is where a mask shapes that. The separation is on
purpose.