Terrain and scatter¶
Terrain¶
A heightmap on a regular grid, one height per grid vertex, painted with up to four texture layers. The bulk data is base64 text in JSON and raw bytes in the binary container.
| Key | Type | Default | Meaning |
|---|---|---|---|
origin |
[x, y, z] |
required | World position of the first vertex |
resolution |
[nx, nz] |
required | Vertex count along X and Z, at least 2 each |
cell_size |
number | required | Map units between neighboring vertices |
heights |
base64 | required | Little endian 32 bit floats, one height per vertex |
layers |
array | required | Up to four texture layers, see below |
splat |
base64 | omitted | Four weight bytes per vertex, one per layer, saying how much each layer shows there |
holes |
base64 | omitted | One byte per cell, non-zero cuts the cell out of the terrain |
chunk_cells |
integer | 32 |
Always written. Cells per chunk side. The terrain is split into chunks of this size for rendering and collision |
Vertex (i, j) sits at origin + (i * cell_size, heights[j * nx + i], j * cell_size). splat uses the same order,
its weights are normalized on read, and an all zero entry means layer 0. holes covers the (nx - 1) * (nz - 1)
cells in the same order.
Each layer:
| Key | Type | Default | Meaning |
|---|---|---|---|
material |
string | required | Material painted by this layer |
tile |
number | 256 |
Map units per texture repeat |
detile |
number | 0 |
0 to 1, how strongly the repeat is broken up so the grid pattern stops showing |
detile_sharpen |
number | 0.5 |
0 to 1, how crisp the de-tiled result stays |
See Terrain layers for how these settings look in practice.
Terrains stay axis aligned. An instance moves a terrain's center by its whole transform, rotation included, but never rotates the grid itself.
Scatter¶
A scatter set keeps many copies of a few models, like trees, rocks or grass painted onto surfaces, in one node. See
Scatter for the editor side. Every key except targets and material is always written.
| Key | Type | Default | Meaning |
|---|---|---|---|
name |
string | required | Name shown in the editor |
kind |
string | props |
What Godot builds. props keeps scripts and collision, foliage is a MultiMesh without collision |
targets |
array of node ids | omitted | The surfaces the set is painted on |
items |
array | required | The models it scatters, see below |
collision |
string | none for foliage, else convex |
Collision shape per instance: none, box, convex, decomposition or trimesh |
cast_shadows |
bool | true |
Whether the instances cast shadows |
visibility_range |
number | 0 |
Hide instances beyond this distance, 0 is never |
chunk_size |
number | 0 |
Split the set into cells of this size so Godot can cull what is off screen, 0 is one cell. New sets use 2048 |
static_props_multimesh |
bool | false |
Draw prop scenes that carry scripts as MultiMesh too. Cheaper for many props, but their scripts are dropped |
material |
string | omitted | Material override for the whole set |
instances |
array | empty | The placed instances, see below |
Copy a set together with a surface it targets, and the copy targets the copied surface.
Each item is one model the set can place:
| Key | Type | Default | Meaning |
|---|---|---|---|
source |
string | required | res:// model or scene |
weight |
number | 1 |
Relative chance of this item being picked |
scale |
[min, max] |
[0.8, 1.2] |
Range for a random uniform scale |
spacing |
number | 48 |
Minimum distance to every other instance |
align |
number | 0 |
0 stands upright, 1 follows the surface normal, values between lean part way |
random_yaw |
bool | true |
Turn each instance to a random heading |
tilt |
number | 0 |
Largest random lean in degrees |
sink |
number | 0 |
Map units pushed into the surface, so roots and rock bases do not float |
material |
string | omitted | Material override for this item. It wins over the set's |
enabled |
bool | true, omitted |
Whether the brush paints this item. Instances already placed stay |
Each instance is a flat array [item, x, y, z, pitch, yaw, roll, scale], where item indexes items and the angles
are degrees in YXZ order. On save the position is rounded to 0.01, the angles to 0.1 and the scale to 0.001, which lets
the container store them as integer columns.