Foliage & Biomes¶
Populate whole planets with forests, grass, shrubs and rocks. Placement follows the planet you designed: biome channels from the Terrain Graph decide where each species grows, and the spawner streams instances in around the camera as it moves, from orbit down to the forest floor.
The foliage system has three parts:
| Part | What it is |
|---|---|
| Spawner Generator | A graph (or script) that says how many of each species per km² at every point of the planet. |
| Species | The meshes and their settings: scale, rotation, reach, shadows, collision. |
| Synth | Optional node graphs that generate the plants and their textures: trees, ferns, grass, bark and leaves. |
Biomes¶
Biomes come from the planet's generation (height, moisture, slope, and so on), so vegetation follows the world you designed rather than being painted by hand. Your terrain graph writes four channels into Biome Output; the spawner reads them back with the Biome node. The shipped examples use:
| Channel | Meaning |
|---|---|
| x | Cold (0 warm, 1 frozen) |
| y | Moisture |
| z | Bare rock |
| w | Slope |
- Dense or sparse: control vegetation coverage per biome.
- Biome-driven: distribution keys off the generated biome map, so new terrain you shape automatically re-seeds the right vegetation.
Spawning objects with a Spawner Generator¶
Scatter any mesh (foliage, rocks, props) across the surface with a Spawner Generator asset that compiles a spawn graph into native bytecode.
1. Create the spawner¶
Create a Metaplanets → Spawner Generator asset in the Content Browser.
2. Configure the spawner¶
Pick a mesh, key, scale, and rotation behavior. Options like Align to Terrain Normal keep objects flat on the curved surface.
3. Set the spawn output's key¶
Each Spawn Output node needs a Key. Select the Spawn Output node in the
graph, then change its Key in the Details panel so it matches the key of
the spawner type you set on the spawner (e.g. Cubes). The key is what binds
the output's density to that spawner — if the Spawn Output's key doesn't match
the spawner's, the density you wire in won't reach it.
4. Drive density from a biome¶
Feed a Biome channel (scaled) into the spawner's Density pin so coverage follows your biome mask instead of being a flat constant. Density is in instances per km².
5. Result¶
Compile and assign the spawner to the planet actor's Spawner Generator Asset (Metaplanet → Generation). The surface fills with instances.
A real ecology¶
A full forest uses one Spawn Output per species, each with its own
density formula. This is the shipped S_TemperateForest spawner, with 16
species configs:
Large ecologies are easier to write as PlanetScript. Each
spawn.<Key> = density; line is one Spawn Output. This is an excerpt of
Docs/examples/TemperateForestEcology.ps:
planet TemperateForestEcology {
let b = Biome();
let cold = b.X; let moist = b.Y; let rock = b.Z; let slope = b.W;
let wp = Position().WorldPosition;
let open = (1.0 - SmoothStep(0.78, 0.86, cold)) * (1.0 - rock);
let chill = SmoothStep(0.4, 0.6, cold);
let wet = SmoothStep(0.3, 0.5, moist);
let patch = FBMNoise(Position: wp, Scale: vec(100000.0, 100000.0, 100000.0),
Amplitude: 1.0, Octaves: 4.0, Lacunarity: 2.3, Gain: 0.5);
let canopy = SmoothStep(-0.3, -0.05, patch + 0.6 * (moist - 0.5)) * wet;
let forest = canopy * open;
let gentle = 1.0 - SmoothStep(0.35, 0.65, slope);
let steep = 1.0 - SmoothStep(0.55, 0.85, slope);
spawn.EuropeanBeech = 7000.0 * forest * gentle * (1.0 - chill); // broadleaf in the warm lowlands
spawn.NorwaySpruce = forest * steep * (6000.0 * chill + 150.0); // conifers take over in the cold
spawn.Fern = 90000.0 * forest * steep; // understory under the canopy
spawn.LeafLitter = 400000.0 * forest;
spawn.MeadowGrass = 7.0 * ((1.0 - canopy) * open); // grass in the clearings
spawn.RockA = 600.0 * rock * steep;
}
Build it into a spawner asset with:
UnrealEditor-Cmd MyProject.uproject -run=MetaplanetCreateExamples -createspawner=C:/Eco/MyEcology.ps -spawnername=S_MyEcology -spawnerdest=/Game/Planets
Patterns that make foliage look natural:
- Patchiness: multiply by a large, low-frequency noise (
patchabove) so forests have edges, clearings and meadows instead of uniform cover. - Succession: split one area between species by a smooth gradient (beech in the warm, spruce in the cold) so they mix at the boundary.
- Layers: canopy trees, then understory (ferns, shrubs), then ground cover (litter, grass), each with the canopy as a mask or inverse mask.
- Variants: give a species two meshes (
FernandFern_1) at half the density each. - Height:
TerrainHeight()gives the ground height above sea, for beaches, tree lines and alpine meadows.
Instances are never placed under water: on planets with a water output, the
spawner drops any tree or rock that would stand in a lake, river or sea
(metaplanets.Spawner.WaterClipDepth, default 0.05 m; negative turns it off).
Species settings¶
Each entry in the spawner's Spawner Configs is one species:
| Setting | Default | Notes |
|---|---|---|
| Key | Must match the Spawn Output key. | |
| Mesh | Any static mesh, Nanite or not. | |
| LOD Config | Spawner | Spawner for trees, shrubs and rocks; Grass for dense ground cover (packed in chunks, uses a per-cell density scale instead of per km²). |
| Align To Terrain Normal | on | Tilt with the ground. Use for grass, rocks and shrubs; turn off for trees so they grow upright. |
| Random Yaw / Pitch / Roll | 0 | Ranges in degrees. Typical: yaw ±180, pitch ±3 for plants, ±15 for rocks. |
| Uniform Scale Range | 1–1 | Random size. 0.7–1.3 looks natural. |
| Clumpiness | 0.35 | 0–1. Groups instances into clumps of Clump Size Meters (12) instead of an even scatter. Clump Scale Influence (0.5) makes clump centres bigger. |
| Max Distance (m) | 0 | The species' reach: instances thin out over the last quarter and fade out. Typical: grass 120 m, shrubs 400 m, trees 2–3 km. 0 uses the planet's spawn radius. |
| Cast Shadow | on | |
| Enable Collision | off | Turn on for trees and rocks the player can bump into. |
Reach is the most important performance setting: a species is only generated within its reach, so short-reach grass and long-reach trees can share one spawner without millions of distant grass blades.
Synth: generate plants and textures¶
Synth builds the foliage itself from node graphs, inside the editor, with no external tools. The results are ordinary Unreal assets (static meshes and textures) that you can use anywhere.
| Graph | Prefix | Menu | Produces |
|---|---|---|---|
| Texture Synth | TS_ |
Metaplanets → Texturing | Synth Textures: seamless base colour, normal, roughness, AO, height, opacity. Leaves, needles, fern fronds, grass blades, bark, ground. |
| Plant Synth | PS_ |
Metaplanets → Flora | Synth Plants: trees, shrubs, ferns and grass as static meshes, with LODs or Nanite and an impostor. |
Plant Synth¶
A plant is a growth chain: Trunk → Branches (limbs) → Branches (boughs) → Branches (twigs) → Leaves → Output. Each stage has pins for count, angle, length, taper, gravity and so on; Scale, Merge, Ribs and Parameter nodes help build more complex plants.
Leaf shapes include Broadleaf, Needle, Frond, Blade, Pad, Cap, Bulb, Spine, Tendril and Petals as geometry, plus Card (textured): a drooping, folded card that shows one cell of a Texture Synth leaf atlas. Textured cards are what make canopies look photographic.
- Create Metaplanets → Flora → Plant Synth. It starts as a broadleaf tree.
- Edit it in the Preview tab (lit 3D view with branch, leaf and triangle counts; Preview Seed shows other individuals).
- Compile rebuilds every Synth Plant made from the graph. Create 4 Variations makes seeds 0–3.
- Right-click a Synth Plant → Synth Plant Settings… to set the seed, parameter overrides, Nanite or LOD count, impostor, and the bark and leaf materials.
Texture Synth¶
Node families: generators, filters, height (Erode, Height To Normal, AO, Curvature), colour and parameters. The organic nodes do most of the work:
- Leaf Shape: ovate, elliptic, lanceolate, lobed, palmate, cordate, needle spray, fern frond and grass blades, as 1, 4 or 16 variants in an atlas. Cluster mode draws a whole leafy twig per cell.
- Bark: smooth, fissured, plated and birch.
Create Texture Set writes T_<Name>_BaseColor, _Normal, _ORM
(R = AO, G = roughness, B = metallic) and _Height. The same sets also give
surfaces their close-up ground detail.
Textured plant workflow¶
- Texture Synth leaf and bark graphs → Create Texture Set.
- Material instances of
M_MetaplanetLeafCard(masked, two-sided) andM_MetaplanetBark(moss on upward-facing bark). - A Plant Synth with Card (textured) leaves.
- Assign the instances as the plant's leaf and bark materials.
The temperate forest kit¶
Ready to use in Metaplanets/Flora/Temperate: European Beech, English Oak,
Silver Birch, Norway Spruce, Fern, Leaf Litter and Meadow Grass, two
variants each, with their texture sets and materials. S_TemperateForest
places them.
| Species | Reach | Notes |
|---|---|---|
| European Beech | 2.5 km | Dense broadleaf canopy. |
| English Oak | 2.5 km | Wide crowns, sparser. |
| Silver Birch | 2 km | Light, pale trunks; forest edges. |
| Norway Spruce | 3 km | Cold and steep ground. |
| Fern | 150 m | Understory. |
| Leaf Litter | 45 m | Ground cover under trees. |
| Meadow Grass | 120 m | Grass (per-cell density). |
The plugin also includes Nanite starter plants (Broadleaf, Conifer, Shrub,
Palm, Acacia, Saguaro, Barrel Cactus, Prickly Pear, Agave, grass clumps and a
few alien plants) and Plant/Texture Synth sources for a jungle kit (jungle
tree, kapok, palm, tree fern, cycad, elephant ear, jungle grass) in
Docs/examples/plantsynth and Docs/examples/texturesynth, which you build
yourself.
Impostors and LODs¶
Forests reach the horizon through impostors: when a plant is far away, it is drawn as a single card that shows the tree from the nearest of 64 baked directions.
- Every non-Nanite Synth Plant gets an octahedral impostor with depth as its last LOD (Impostor Frames 8, so 8 × 8 views; Impostor Resolution 2048). The depth makes impostors cast correct shadows, meet the ground properly and stay stable as the camera moves.
- All foliage materials cross-fade between LODs and into the impostor (dithered transitions), so there is no popping.
- Leaves deep inside or low in a crown are darkened (crown AO), so distant impostor forests match the mesh trees in front of them.
- Impostor material parameters:
CrownInnerAO,CrownSelfShadow,CoverageBoost. Leaf cards:CrownInnerAO,CrownLowAO.
Impostors work on every supported engine version. For Nanite plants instead, see Nanite.
Runtime behaviour¶
- Streaming: foliage is baked in cells around the camera and re-baked as you move. Grass layouts are fixed per cell, so grass never reshuffles; only the blades at the edge of the reach fade in or out.
- Seated on the drawn ground: as terrain refines, trees and rocks within 4 km and grass within 250 m are moved onto the ground as it is actually drawn, so nothing floats over hollows. Tall plants on very steep drawn ground (over 55°) are hidden.
- Swap the ecology at runtime: call Set Spawner Generator on the planet actor (Blueprint or C++, works in shipping builds) to change a world's vegetation, for example after a climate change in your game. Terrain and caches are untouched; visible tiles re-spawn.
Console variables¶
| Variable | Default | Effect |
|---|---|---|
metaplanets.Spawner.ReachScale |
1 | Scales every tree, shrub and rock species' reach. 2 for cinematics. |
metaplanets.Spawner.GrassReachScale |
1 | Same for grass and ground scatter. Cost grows with the square. |
metaplanets.Spawner.CastShadows |
1 | Master switch for foliage shadows. |
metaplanets.Spawner.ScatterShadows |
1 | Grass, litter and understory cast shadows too. |
metaplanets.Spawner.ScatterShadowDistanceMeters |
0 | Limit grass shadows to this distance (0 = no limit). |
metaplanets.Spawner.ShadowsStatic |
0 | 1 caches every species' shadows as static: faster, but shadows don't sway. |
metaplanets.Spawner.WindMaxMeters |
0 | Stop wind animation beyond a distance. Not for species with impostors. |
metaplanets.SpawnerDistanceFieldLighting |
1 | Trees and shrubs darken the sky light around them (Lumen sky occlusion, DFAO). Costs ~15–20% on dense jungle. |
metaplanets.Spawner.TreeMaxSlopeDegrees |
55 | Hide tall plants on steeper drawn ground (0 = off). |
metaplanets.Spawner.ReseatRadiusMeters |
4000 | Re-seat trees and rocks on the drawn ground within this radius (0 = off). |
metaplanets.GrassReseatRadiusMeters |
250 | Same for grass. |
metaplanets.Spawner.SeatIdleMoveMeters |
20 | Re-seat only after tiles change or the camera moves this far. |
metaplanets.Spawner.Clumping |
1 | 0 disables clumping. |
metaplanets.Spawner.WaterClipDepth |
0.05 | Keep plants out of water deeper than this (negative = off). |
See Performance for frame-time guidance on dense forests.