Scatter Multi
App: apps/scatter_multi/
Verifies two things about multiple GPU-instanced meshes in one frame — the orange field on the left and the cyan field on the right each render independently, at their own transforms, in their own shader’s colour.
- PLM-257 — before the per-draw instance-SSBO sub-allocation, both instanced meshes wrote the shared instance buffer at offset 0, so only the last-submitted one rendered. PLM-257 gives each draw its own sub-region, so both fields render (the fix behind the “one GPU-instanced mesh per frame” limit once called out on Grass Field / Scatter Demo).
- PLM-264 — each field’s prototype mesh carries its own per-mesh instancing shader
(
blade_aorange,blade_bcyan) while the active shader is a non-instancingplainshader. Before the fix, an instanced draw dropped the prototype’s per-mesh shader and fell back to the active shader, which applies an identity transform → every blade collapsed onto the origin. Now each field uses its own shader: two distinct colours at their transforms.
Run from root
Section titled “Run from root”% ./plume3d scatter_multiA raised camera looks across both fields. The demo captures a screenshot at frame 60 — printing
each mesh’s visibleCount — and exits at frame 80. A pile at the origin, or one colour across
both fields, means a regression.
What it does
Section titled “What it does”-
Loads a non-instancing
plainshader first (so it becomes the active/fallback shader) and both per-mesh instancing shaders:Graphics.loadShader("shaders/plain") // active fallback — NON-instancing (identity transform)Graphics.loadShader("shaders/blade_a") // per-mesh instancing shader (orange), for the LEFT fieldGraphics.loadShader("shaders/blade_b") // per-mesh instancing shader (cyan), for the RIGHT field -
Creates two GPU-instanced meshes, each from a crossed-quad blade prototype that carries its own per-mesh shader (the 3-arg
newMesh— this is the PLM-264 path), with per-instance frustum culling on:var greenBlade = Graphics.newMesh(bladeVerts(...), "triangles", "shaders/blade_a")_green = _scene.createInstancedMesh("green")_green.setMesh(greenBlade)_green.useGpuInstancing = true_green.setCullingEnabled(true)// … the blue field is the same with "shaders/blade_b" … -
Fills each field with a jittered grid over its own half of the world via
addInstanceColored+setInstanceParams— the orange field over the left half[-22,-1], the cyan field over the right half[1,22]. -
Sets a global wind (
Graphics.setWind) both blade shaders read, and draws the scene (_scene.draw()submits both instanced meshes, each into its own SSBO sub-region and with its own per-mesh shader).
- InstancedMesh —
createInstancedMesh,setMesh,useGpuInstancing,setCullingEnabled,addInstanceColored,setInstanceParams,instanceCount,visibleCount. - Scene —
createInstancedMesh,addNode,addCamera. - Graphics —
loadShader,newMesh(both the 2-arg and the 3-arg per-mesh-shader form),setWind.
- Two instanced meshes, two SSBO sub-regions. The per-draw sub-allocation (PLM-257) is what
lets a scene submit several GPU-instanced prototypes in one frame — the prerequisite for
multi-prototype scatter (several foliage types, or a Blender blend that bakes more than one
scatter prototype via
BlendResult.instantiateScatter). - Each instanced mesh can carry its own shader. Passing a shader to
newMeshsets the prototype’s per-mesh shader, and the instanced draw now honours it (PLM-264) — so a scene can mix instanced fields with different shaders (e.g. rain and snow as separate meshes), not just one shared active shader. The shader must be an instancing shader (declares the set-2 instance SSBO and appliesinstanceData[SV_InstanceID].transform); a non-instancing shader ignores the per-instance transform and collapses the field to the origin — which is exactly what theplainactive shader would do here if the fix regressed. visibleCountis a per-mesh diagnostic — the number that mesh drew last frame; it equals itsinstanceCountwith culling off and drops as its blades leave the frustum.
See InstancedMesh for the full instancing surface, the Grass Field example for a single enhanced-instancing field, and the Blend Scatter Demo for baked Blender scatter as instanced draws.