Forest

Forest is the scene object responsible for rendering, culling, collision, and wind interaction for forest items in a level.

The Forest system is designed for very large numbers of repeated static objects, such as:

  • Trees
  • Bushes
  • Rocks
  • Grass clumps
  • Logs
  • Small natural props
  • Repeated scatter assets

Forest items are usually more efficient than placing thousands of individual TSStatic objects. For repeated vegetation and scatter assets, use the Forest system whenever possible.


Relationship to forest files

The Forest object does not usually store individual item placement directly inside items.level.json.

Instead, it loads forest placement files from the level folder:

levels/<levelName>/forest/*.forest4.json

Forest item type definitions are stored separately in:

levels/<levelName>/art/forest/managedItemData.json

The two systems work together:

File / Object Purpose
Forest object Scene object that loads and manages forest data.
managedItemData.json Defines forest item types, such as tree/rock/bush definitions.
*.forest4.json Stores placed forest instances.
ForestItemData Runtime/editor object representing one forest item type.
ForestWindEmitter Applies wind to nearby/global forest items.
ForestBrush / ForestBrushElement Editor-only brush setup for painting forest items.

For the file format itself, see Forest Data (.forest4.json) and managedItemData.json .


Basic Forest object

A typical level has one Forest object, usually named:

theForest

Example:

{
  "class": "Forest",
  "name": "theForest",
  "position": [0, 0, 0],
  "rotationMatrix": [1, 0, 0, 0, 1, 0, 0, 0, 1],
  "scale": [1, 1, 1],
  "lodReflectScalar": 2
}

The Forest object uses global bounds and its transform position is not normally meaningful for item placement.

Forest items are stored in forest data files. Moving the Forest object is not how you move forest items.

Important Forest fields

Field Type Description
dataFile string Legacy source forest data file field. Hidden/no serialization in modern usage.
lodReflectScalar number LOD scalar used when rendering forest into reflections.

lodReflectScalar

"lodReflectScalar": 2

lodReflectScalar changes the far clip / LOD behavior when the forest is rendered in reflection passes.

Higher values can make forest reflections use lower detail or cull differently, improving reflection performance.

This is mainly a performance/quality control for reflected forests.


Loading behavior

When the Forest object is added to the scene, it:

  1. Sets global bounds.
  2. Adds itself to the scene.
  3. Searches for forest placement files.
  4. Loads modern .forest4.json files if available.
  5. Falls back to older formats if necessary.
  6. Preloads forest item data.
  7. Builds internal spatial cells and render batches as needed.

Modern files are preferred:

*.forest4.json

Older formats are deprecated:

*.forest
*.forest.json

If old files are found, the engine logs warnings asking the level author to resave and remove old files.


Multiple forest files

Modern forest data is usually split by forest item type.

Example:

levels/example/forest/oak_large.forest4.json
levels/example/forest/pine_small.forest4.json
levels/example/forest/rock_large.forest4.json

When saving, the Forest system groups items by their ForestItemData internal name and writes one .forest4.json file per type.

Unused forest files may be deleted or backed up when saving, depending on whether any forest items remain.


Forest cells

Forest items are organized into spatial cells.

The cell system is used for:

  • Fast lookup
  • Culling
  • Rendering batches
  • Collision
  • Raycasts
  • Editor selection
  • Wind queries

Cells can subdivide when they contain too many items. This forms a spatial hierarchy, allowing the engine to quickly skip areas outside the camera view or query region.


Buckets and spatial lookup

Forest data uses top-level buckets based on item position. Each bucket contains a ForestCell.

When adding an item:

  1. The item position is converted into a bucket key.
  2. A bucket/cell is found or created.
  3. The item is inserted into that cell.
  4. If the cell has too many items, it splits into subcells.

This makes queries faster than scanning every forest item in the level.


Item lookup

Forest items can be found by:

  • Internal forest key
  • UID
  • Position/bucket
  • Box query
  • Radius query
  • Frustum query
  • Polygon query

This is used by:

  • Rendering
  • Collision
  • Selection
  • Brush editing
  • Biome tools
  • Wind updates
  • Scripting/tools

ForestItemData

ForestItemData defines one forest item type.

It includes:

  • Shape file
  • Collision settings
  • Placement radius
  • Wind settings
  • Terrain alignment settings
  • Annotation

Important fields:

Field Description
shapeFile Shape used by this forest item type.
collidable Whether items of this type contribute collision.
radius Placement radius used to avoid crowding.
snapRotationToTerrain Aligns placed items to the surface normal.
windScale Overall wind influence.
trunkBendScale Trunk bend amount.
branchAmp Branch wind amplitude.
detailAmp Leaf/frond/detail wind amplitude.
detailFreq Leaf/frond/detail wind frequency.
mass Used by wind spring simulation.
rigidity Resistance to wind force.
tightnessCoefficient Resistance to bending.
dampingCoefficient Damps oscillation over time.
annotation Annotation/debug classification.

Shape loading

Each ForestItemData references a shape:

"shapeFile": "/levels/example/art/shapes/trees/oak_large.dae"

The shape is loaded once and shared by all items of that type.

This is one of the main reasons Forest is efficient for repeated assets.


Rendering

Forest rendering is optimized for many repeated instances.

The renderer:

  1. Finds visible forest cells.
  2. Culls cells outside the camera/frustum.
  3. Groups visible items by type.
  4. Chooses LOD per item.
  5. Uses instancing/batching for repeated items.
  6. Uses imposters/billboards where possible.

When the Scene Static Manager is enabled, forest rendering may be routed through that optimized path.


Forest vs TSStatic

Use Forest for many repeated objects.

Use TSStatic for individually placed objects.

Use case Recommended
Thousands of trees Forest
Repeated rocks/bushes Forest
Grass/vegetation scatter Forest / GroundCover depending use
Single building TSStatic
Unique bridge TSStatic
Manually placed prop TSStatic
Object needing custom transform/material behavior TSStatic
Forest is usually the most lightweight option for large numbers of repeated static objects. TSStatic is better for individual placed meshes.

LOD and billboards

Forest items use the LODs stored in their shape files.

At render time, the engine estimates the item’s screen-space size and chooses an appropriate detail level. If the lowest detail is a billboard/imposter, the item can be rendered as a batched imposter.

A whole forest cell may be rendered as imposter batches if the largest item in the cell can be billboarded at the current distance.

This improves performance significantly for distant vegetation.


Imposter batching

Forest cells can build imposter batches.

A batch groups items that share the same last-detail/imposter type.

This reduces draw overhead for distant forests.

Batching is used when:

  • The item type supports a billboard/imposter detail.
  • The cell is far enough away.
  • Imposters are not disabled.

Debug settings can force or disable imposters internally:

Forest::smForceImposters
Forest::smDisableImposters

Reflection rendering

Forest uses lodReflectScalar to adjust rendering in reflection passes.

In reflections, forest detail may be reduced or culled sooner to improve performance.

This is important because rendering forests into reflection passes can be expensive.


Collision

Forest can provide collision for forest items if their ForestItemData is collidable.

The collision system:

  1. Queries forest cells near the collision area.
  2. Finds relevant forest items.
  3. Uses each item’s collision details.
  4. Builds or reuses cached collision data per shape.
  5. Adds transformed collision meshes to physics.

Collision data is cached by shape file to avoid rebuilding the same collision repeatedly for every item.

Collidable forest items can become expensive if the shape collision is too complex or the item density is very high.

Raycasts

Forest supports raycasts against forest items.

Raycasts can use:

  • Collision/LOS details
  • Rendered mesh detail, when requested

This is used by:

  • Selection
  • Collision queries
  • Gameplay raycasts
  • Editor tools

If the ray hits a forest item, the returned object is the Forest object, and additional internal item data may be used by tools.


Decals

Forest does not support decal projection in the same way terrain and static meshes do.

For decal poly list queries, Forest returns false.

PLC_Decal → false

This means road decals and other projected decals should not rely on forest item geometry as decal receivers.


Wind

Forest items can react to wind if their shape/material setup supports it.

Wind requires:

  • windScale > 0
  • Shape vertex color data for wind weighting
  • Material features that support wind deformation
  • Active ForestWindEmitter or global wind source

Wind affects:

  • Trunk bending
  • Branch movement
  • Leaf/frond detail movement
  • Local impulse response

ForestWindEmitter

ForestWindEmitter defines wind in a level.

It can act as:

  • Global directional wind
  • Local radial wind source

Important fields:

Field Description
windEnabled Enables this emitter.
radialEmitter If true, wind is local/radial instead of global direction.
strength Wind strength.
radius Radius for radial emitters.
gustStrength Maximum gust strength.
gustFrequency Gust frequency in seconds.
gustYawAngle Direction drift angle.
gustYawFrequency Direction drift frequency.
gustWobbleStrength Random wobble added to gusts/turbulence.
turbulenceStrength Turbulence strength.
turbulenceFrequency Turbulence frequency.

Example:

{
  "class": "ForestWindEmitter",
  "name": "forest_wind",
  "position": [0, 0, 0],
  "windEnabled": true,
  "radialEmitter": false,
  "strength": 1,
  "gustStrength": 0.5,
  "gustFrequency": 3,
  "gustYawAngle": 10,
  "gustYawFrequency": 4,
  "turbulenceStrength": 0.25,
  "turbulenceFrequency": 2
}

Wind update radius

The wind manager only gathers nearby wind-reactive trees around the camera.

This is controlled by the engine settings, such as wind effect radius.

Items with:

windScale < 0.001

are skipped from wind update placement info.

This avoids spending CPU time on static rocks or non-wind vegetation.


Radial impulses

Forest can apply radial impulses to nearby wind-reactive items.

This is used for effects like:

  • Explosions
  • Strong local forces
  • Wind gust interactions

The impulse affects local wind accumulators and causes nearby vegetation to bend/react temporarily.


Forest Editor

The Forest Editor uses the Forest object named:

theForest

If no active forest exists, the editor can create one.

The editor modifies forest data through tools such as:

  • Paint
  • Erase
  • Erase selected
  • Snap to terrain
  • Biome placement tools

Changes are stored in the forest data and saved to .forest4.json files.


ForestBrush

A ForestBrush is an editor-only container for ForestBrushElement objects.

It is stored under:

ForestBrushGroup

The brush defines which forest item types can be painted and with what placement rules.


ForestBrushElement

A ForestBrushElement defines placement parameters for one forest item type.

Important fields:

Field Description
forestItemData Forest item type to place.
probability Relative probability for random selection.
rotationRange Random yaw rotation range.
scaleMin Minimum random scale.
scaleMax Maximum random scale.
scaleExponent Bias between min and max scale.
sinkMin Minimum sink amount.
sinkMax Maximum sink amount.
sinkRadius Radius used for slope sinking.
slopeMin Minimum allowed slope.
slopeMax Maximum allowed slope.
elevationMin Minimum allowed elevation.
elevationMax Maximum allowed elevation.

ForestBrushTool

ForestBrushTool is the editor tool used to paint, erase, and adjust forest items.

Important brush tool fields:

Field Description
mode Paint, erase, erase selected, or snap-to-terrain mode.
size Brush radius.
pressure Density/strength of brush stroke.
hardness Brush falloff/hardness.
depthOffset Offset above/below terrain relative to item pivot.
forceAlignToTerrain Forces alignment to terrain normal.
snapSinkEnabled Enables sinking when snapping to terrain.
snapSink Sink amount for snap operation.
snapAnyForestItemType Snap all item types instead of selected types only.

Paint mode

Paint mode places forest items randomly inside the brush circle.

The process roughly:

  1. Calculate brush area.
  2. Multiply by pressure.
  3. Pick item types based on ForestBrushElement.probability.
  4. Randomize scale and rotation.
  5. Raycast to terrain/static surface.
  6. Check slope/elevation limits.
  7. Check nearby items using placement radius.
  8. Apply sink/depth offset.
  9. Add item with undo support.

This produces natural randomized scatter.


Erase modes

Erase mode removes forest items inside the brush.

Modes:

Mode Description
Erase Erases any forest item under the brush.
EraseSelected Erases only selected/active forest item types.

Erase amount is influenced by brush pressure.


Snap to terrain

Snap-to-terrain mode moves existing forest items onto terrain/static surface.

It can also:

  • Apply sink
  • Align to terrain normal
  • Respect selected item types

This is useful after terrain edits or when items float/clip incorrectly.


Biome placement

The Forest tools include advanced biome placement workflows.

Biome tools can place or replace forest items based on:

  • Terrain material index
  • Grayscale mask image
  • Lasso/polygon areas
  • Slope range
  • Elevation range
  • Falloff regions
  • Exclusion zones
  • Edge placement rules

These tools are useful for large-scale vegetation generation.

Example uses:

  • Fill grass material with bushes
  • Place rocks along biome edges
  • Scatter trees only on certain slopes
  • Replace old biome items in a selected area
  • Use masks to control vegetation density

Context IDs

Forest items can store a tool context ID.

Examples include:

  • Normal editor placement
  • Biome-generated placement

This lets tools identify which items were created by biome tools and selectively remove/replace only those items.


Saving

When saving, forest items are grouped by item type and written to:

levels/<levelName>/forest/<type>.forest4.json

The filename is made safe from the forest item type/internal name.

If an item type no longer has any items:

  • If the forest is empty, the file may be deleted.
  • Otherwise, unused files may be renamed/backed up.

Dirty state

Forest data tracks whether it has been modified.

The editor uses this to know whether forest data needs saving.

Useful commands/methods include:

save()
reload()
clear()
regenCells()
isDirty()

Zoning

Forest cells update their zone visibility state when scene zoning changes.

This allows forest cells to be culled correctly for indoor/outdoor visibility systems.


Debug stats

The Forest system exposes some debug stats:

$Forest::totalCells
$Forest::cellsRendered
$Forest::cellItemsRendered
$Forest::cellsBatched
$Forest::cellItemsBatched

These can help diagnose forest rendering performance.

Additional debug drawing can show forest cells and bounds.


Minimal Forest object example

{
  "class": "Forest",
  "name": "theForest",
  "position": [0, 0, 0],
  "rotationMatrix": [1, 0, 0, 0, 1, 0, 0, 0, 1],
  "scale": [1, 1, 1],
  "lodReflectScalar": 2
}

Minimal ForestItemData example

{
  "pine_small": {
    "class": "ForestItemData",
    "internalName": "pine_small",
    "shapeFile": "/levels/example/art/shapes/trees/pine_small.dae",
    "collidable": true,
    "radius": 1.5,
    "snapRotationToTerrain": false,
    "windScale": 1,
    "trunkBendScale": 0.4,
    "branchAmp": 1,
    "detailAmp": 0.25,
    "detailFreq": 1,
    "mass": 5,
    "rigidity": 10,
    "tightnessCoefficient": 0.4,
    "dampingCoefficient": 0.7
  }
}

Best practices

  • Use Forest for repeated natural/scatter assets.
  • Use TSStatic for individual unique objects.
  • Keep forest item shapes optimized.
  • Use LODs and billboard/imposter details for trees.
  • Keep collision meshes simple.
  • Disable collision for decorative foliage when possible.
  • Use radius to prevent overcrowding.
  • Use wind only for assets that need it.
  • Set windScale to 0 for rocks/static props.
  • Use biome tools for large-scale placement.
  • Save forest data after major edits.
  • Remove old .forest / .forest.json files after upgrading.

Common issues

Forest items do not appear

Possible causes:

  • Missing Forest object
  • Missing .forest4.json files
  • Missing managedItemData.json
  • ForestItemData internal name mismatch
  • Invalid shapeFile
  • Shape failed to load

Some items are missing

Possible causes:

  • Missing item type definition
  • Renamed/deleted ForestItemData
  • Invalid lines in .forest4.json
  • Scale below minimum

Forest collision is too heavy

Possible causes:

  • Too many collidable items
  • Complex collision meshes
  • Dense placement
  • Collision enabled for small decorative foliage

Wind does not affect trees

Check:

  • windScale is greater than 0
  • Shape has vertex color data for wind weighting
  • Material supports wind deformation
  • ForestWindEmitter exists and is enabled
  • Item is within wind effect radius

Items float above terrain

Use Snap to Terrain, check item pivot, or adjust sink/depth offset.

Items are buried too deeply

Reduce sink values or check asset pivot.

Forest editor says no Forest exists

Create or add a Forest object named theForest.


Summary

Forest is the main system for rendering and managing large numbers of repeated static items in a level.

It loads placement data from .forest4.json files, uses ForestItemData definitions from managedItemData.json, organizes items into spatial cells, supports culling and batching, can provide collision, and supports wind deformation for vegetation.

Use Forest for large-scale repeated natural assets, and use TSStatic for individually placed static meshes.

Last modified: July 23, 2026

Any further questions?

Join our discord
Our documentation is currently incomplete and undergoing active development. If you have any questions or feedback, please visit this forum thread.