Terrain Configuration
A terrain is described by a JSON config. Give this config to the terrain field of an environment spec, inline or as a path to a file. The full schema is below.
terrain_name and grid are required, and so is at least one of tiles or randomization: a grid with no way to fill its cells is rejected.
{
// Required. The output XML is written as terrain/<terrain_name>.xml.
"terrain_name": "string",
// Required. Grid dimensions and per-tile size in meters.
"grid": {
"rows": 3,
"cols": 3,
"tile_size": [8.0, 8.0]
},
// Optional. Connector strip between tiles. width = 0 disables connectors.
"border": {
"width": 0.5,
"match_mode": "min" // "min" | "max" | "mean"
},
// Optional. "diverse" (per-tile colors), "uniform" (one shared color), or
// "custom" (per-type overrides in `palette`). Under "uniform" the color comes
// from palette["uniform"] or palette["terrain"], else a default gray
// (0.78, 0.78, 0.78, 1.0).
"palette_preset": "diverse",
// Optional. Keys are tile type names (or "connector"). "custom" requires an
// entry for every placed type; "diverse" takes them as overrides. Under
// "uniform", use the single key "uniform" instead, since one shared color
// cannot take per-type entries.
"palette": {
"stairs": [0.3, 0.5, 0.85, 1.0]
},
// Optional, and "uniform" mode only. Bind a 2D texture to the shared material.
// A bare string is shorthand for just the file: "texture": "CONCRETE.png".
"texture": {
"file": "CONCRETE.png", // resolved against the build output dir's
// parent, then the output dir
"name": "terrain_concrete",
"repeat": [0.5, 0.5],
"texuniform": true
},
// Explicit per-cell placements. One tile per cell: two entries for the same
// (row, col) is an error. Combine with `randomization` to fill the rest.
"tiles": [
{ "row": 0, "col": 0, "type": "flat", "params": { "height": 0.0 } }
],
// Optional. Sampling spec for any cell not covered by `tiles`.
"randomization": {
"seed": 42,
"weights": { "flat": 0.5, "stairs": 0.3, "rough": 0.2 },
"param_ranges": {
"stairs": { "n_steps": [4, 10], "axis": ["x", "y"] },
"rough": { "vertical_relief": [0.3, 1.0] }
}
}
}
See Tile Types for every tile type and its params.
Your config is validated
A terrain config describes an experiment, so the framework rejects mistakes rather than working around them. The case that motivated this: {"terrain": "slope", "dge": 8} used to build flat ground and report success, so a run finished and produced numbers for a course that was never built.
Rejected, with a message naming the problem:
- Unknown keys, in either config form. Prefix a key with
_to keep it as a comment. - Unknown tile
params, reported with the tile type and the cell. - Two tiles in one cell.
- A
textureoutsidepalette_preset: "uniform", which used to be discarded along with any typo in its path. - Per-type
paletteentries under"uniform", which cannot apply to one shared color. palette_preset: "custom"missing a color for a placed tile type.- Randomizing a list-valued parameter such as
size_range. A[lo, hi]spec would be read as a range and replace the list with a single number. - Reversed numeric ranges in
param_ranges. - A
terrain_namethat is not a bare file name, since it becomesterrain/<terrain_name>.xml.
Asking where the ground is
If you need the surface height at a point, for example to place something on the terrain, ask the terrain package rather than probing a compiled model:
from myoassist_terrains import max_surface_height_in, surface_height_at
z = surface_height_at(config, x=1.5, y=-2.0) # a point
foot_z = max_surface_height_in(config, x=1.5, y=-2.0, radius=0.12) # a footprint
Both take a config, not a model, and both work for uniform and tiled terrain. Use the footprint query for anything with extent: a point query between two stepping stones reports the base slab, which is not where a foot would rest.
This is how MyoAssist seats a model at reset. It matters because the alternative, measuring the ground from a compiled model’s collision geometry, is unreliable at the contact margins needed to find the surface at all, and produced models that started episodes buried in their terrain.