instances
Trees and a crowd drawn by reference: six tree models placed hundreds of times at any heading, and rats that glide with nothing written to the world.
A wide field with 160 trees and 400 rats. Every tree is one of six models, uploaded once and
placed at any heading; every rat pose is a model of its own (one per variant, clip and frame,
with no heading buckets), placed at the rat's exact position and yaw. So rats glide and turn
smoothly, and nothing is written into the world's bricks as they move. The overlay compares the
GPU memory with what stamping would cost; ?stamp stamps the trees instead.
What it shows
makeInstanceLayer:setStaticfor scenery placed once, and a crowd's dynamic placements committed each frame. Under it are the renderer'saddModelandsetInstances.- Instances at any yaw and at fractional positions, where stamping allows only the eight orientations at whole voxels.
makeCrowd({ instances }): the same crowd helper as the swarm, drawing poses as instances instead of stamping them.blitModelToBricksfor comparison (?stamp), turned in 90° steps.renderer.instanceStats(): models, instances and the GPU bytes they use.- A scene worker: the trees' models are encoded and their static set baked off the main thread, which only adds the encoded models (not with
?stamp, which stamps them instead), and the pipelines compile behind the loading screen withprepare. - A scene cache in production builds: the trees are grown on the main thread, so they have no generator key, and the layer passes
hashModels: true, which looks their encodings up by a hash of their bytes on the worker. The bricks are still sent, so that saves the encode; the bake is read by its own digest. About 1 MB (measured).
The interesting part
const layer = makeInstanceLayer(renderer);
// ... pick spots on dry ground ...
statics.push({ model: t.entity.model, x: Math.round(x), y: ground(x, z) + 1, z: Math.round(z), yaw: rng() * Math.PI * 2, base: t.base });
// ...
layer.setStatic(statics);
// Rats wander between the trees.
const crowd = makeCrowd({ instances: layer, near: 160, farFps: 6, freeze: 900, budgetMs: 5 });Here the palette bases still come from the world's PaletteAllocator, which is fine for a
handful of species. With many, give instances palettes of their own with layer.palettes.of, as
the valley does, and the 256-slot limit no longer applies to them.
URL options
| option | default | effect |
|---|---|---|
?trees= | 160 | number of trees, 0 to 2000 |
?rats= | 400 | number of rats, 0 to 3000 |
?stamp | stamp the trees into the world instead of instancing them | |
?upscale= | an integer of at least 2: a check of the renderer's scaled models, not a pattern to copy. Every other tree is a copy of its model that many times coarser, drawn that many times larger (addModel(src, { scale })), so a blocky tree should have the outline and height of the fine trees of the same model, standing where it was placed. It uploads and places on the main thread, without the scene worker | |
?seed= | instances | a different field |
Plus the common ones, including ?perf.
See also Instances and Instances in the renderer.