Foliage presets
Plant a scene's terrain with a named plant community in one call:
Plant a scene's terrain with a named plant community in one call:
foliage.preset {scene, preset: "meadow", area: [-100, -100, 100, 100]}
The same from a shell: argus-agent foliage-preset --scene scenes/main.scene.json --preset meadow --area -100,-100,100,100 (--dry-run answers without writing; --help lists the presets).
The presets
| Preset | What it plants | Ground cover it brings |
|---|---|---|
meadow | open grassland, the odd lone oak or birch, clumps of shrubs | meadow |
roadside-verge | shrubs from 2 m off the roads' edge, trees from 8 m, over meadow grass | meadow |
pine-forest | mountain pine, fir and some spruce, snags, a low shrub layer | forest-floor |
broadleaf-wood | oak and birch woodland, a shrub layer, ferns | meadow-forest |
temperate-forest | mixed oak and birch woodland: saplings, a shrub layer, ferns, fallen logs, stumps and standing dead wood | meadow-forest |
meadow-farmland | lone field oaks and birch, hedgerow shrubs in clumps, seeding grass tufts and wildflowers | meadow |
Each preset is data, crates/flora-scatter/presets/<name>.json: terrain scatter ops using only the op's existing fields, the ground-cover preset to pair them with, a variant cap per op and a budget. Every preset keeps off the scene's roads (the edge ground cover leaves bare): the verge's shrubs 2 m and trees 8 m, the others' trees 3 m and shrubs and ferns 1 m.
A project's own presets
A preset of your own is the same data in the project, foliage/presets/<name>.json, and foliage.preset takes its name like a built-in's. define writes the file and plants it in one call:
foliage.preset {scene, preset: "my-wood", area: [0, 0, 200, 200], define: {
summary: "Small spruces over forest floor.",
groundCover: "forest-floor",
ops: [{ op: "scatter", id: "my-wood.trees", name: "my-wood.trees", asset: "spruce.project_small",
perHectare: 40, minSpacingM: 4, scale: [0.9, 1.1], competes: "canopy", collider: "none", cullDistanceM: 200 }]
}}
- The name is lowercase letters, digits and hyphens, and not a built-in's. Every op is a
scatterop whoseidstarts with<name>.. - An op's
assetis a template id (the project's own templates infoliage/templates/first, whichfoliage.generate'ssaveTemplatewrites, then the built-ins), a.foliage.jsonpath, or recipe JSON.assets: [{asset, weight}]mixes several. summary,groundCover(defaultmeadow-forest),areaM,budgetandvariantsare optional. A preset without abudgetis not judged against one: the answer'sbudgetis null and it is neveroverBudget.- After that,
foliage.preset {preset: "my-wood", area}plants it anywhere, and editing the file changes what the next call plants. Reverting the defining call takes the file back with the planting.
Arguments
area:[minX, minZ, maxX, maxZ]in scene metres; it should lie on the scene's terrain.seed: optional, default 1. The same scene, preset, area and seed give the same bytes.scene: optional; the open scene when absent. The scene needs a terrain entity (terrain.create).dryRun: cook and answer, write nothing.
What it writes
- One
foliageentityfp-<preset>at the terrain's origin (a layer lists at most 32 prototypes, so a preset with more addsfp-<preset>-layer-2,-layer-3, ...). Under it, oneinstancedMeshentityfp-<preset>-<n>per (op, model), with its.instancesfile beside the scene. All of them carry the tagfoliage-preset:<preset>. - One glb per model in the scene's
assets/foliage-preset/(<template>.v<variant>.a<age>.glb), declared once as the assetfp-<stem>. The models are shared by every scene in that folder and rewritten only when their bytes change. - The preset's
groundCoveron the terrain, only when it has none. - Trees get colliders (a kart hits them); shrubs and ferns get none. Trees cull at 300 m. Shrubs cull at 150 m in
meadowandroadside-verge, 80 m inpine-forest, and 70 m (ferns too) inbroadleaf-wood: near the camera, the understory is most of a wood's drawn triangles.
Re-running and undo
- A re-run REPLACES that preset's plants in that scene (it finds them by tag); it never plants twice. Other presets and every other entity stay. Two different presets over one area both plant.
- With no editor on the scene it is one change:
revertwith itschangeIdtakes it back, including the models it created. With the scene open in the editor, the editor's undo takes the scene back.
Budget
The answer gives instances, models (each one instanced draw) and triangles (full detail, over every instance) against the preset's budget, scaled to the area. overBudget says what is over. Each budget is 30% above the worst of four seeds over the documented 200 m square:
| Preset | Instances | Models | Triangles |
|---|---|---|---|
meadow | 250 | 11 | 3.8M |
roadside-verge | 267 | 13 | 4.0M |
pine-forest | 332 | 19 | 5.0M |
broadleaf-wood | 597 | 15 | 5.6M |
Draws. A model draws as about two draw groups (measured headless on a kart scene: 88 models added 168 groups), so a preset costs about twice its models in draws. To keep that low, a preset caps the variants each op draws (variants in its file, op id -> cap): trees use 2 of their template's 8 variants, shrubs and ferns 1. The cap folds a placement's variant (v % cap) after the cook, so positions and spacing are the cook's and only fewer models are cooked.
Triangles. GPU time follows the triangles drawn (about 0.4 ms per million on an RTX 3080 at 1080p), so the presets are tuned in their data to draw about 1.5M or fewer from a ground camera: trees grow in the younger half of their template's ages (ageRange 0-0.49), the heaviest templates are a small share of their op's mix, and density is set from the budget table above.