Paint, replace, and erase GridMap terrain cells by catalog terrain name: single cells, LINE/RECTANGLE_FILL/RECTANGLE_OUTLINE drags, and erase. Game-authored placement rules evaluate every paint exactly like 2D terrain. FLOOD_FILL has no 3D shape math and fails closed.
The plugin owns no game rules about how terrains behave — ore stays ore because your game says so, not because the plugin knows what ore is. It only consumes your placement rules, validates, and paints into the correct GridMap layers.
Paint one cell
var report:= terrain_service.try_place_terrain_by_name(
&"grass", cell, grid_map,null, entry, palette)entry/palette are optional: when omitted, the entry resolves from the service catalog by terrain name. Painting the item a cell already holds returns a successful no-op by default. Set TerrainPlacementService3D.fail_on_identical_repaint to true to refuse identical repaints.
Stack terrain blocks
Stacking is optional per terrain entry, off by default. Configure it in the Inspector; no game script is needed:
- Open the block's
TilePlacementEntryresource from your terrain palette or catalog. - Under Terrain, enable Stacks On Occupied Cells (
stacks_on_occupied_cells). - Leave Require Existing Ground off when the block should be the base on an empty cell.
- Run the scene, select that terrain, and click.
An empty cell takes the block. That block is the ground. The next click stacks on it.
A click on a thin pad leaves the pad and occupies the cell above it.
The pad is shorter than the cell, so an air gap shows between the pad top and the block. That gap is the rest of the pad's cell.
A second block on the first block sits flush, because both tiles are one cell tall.
A crate sits on the pad mesh, with no air gap. A block cannot stand on that crate. Blocks stand on grid tiles.
Add a
TerrainStackRule3Dwhen a thin slab should be replaced and only full-height blocks should stack. Turn Require Existing Ground on only when an empty column must be refused. Holding still paints once; release and click again to add another level.
Leave Stacks On Occupied Cells off for flat ground or pad entries: the cursor and marker stay on
the GridMap's local ground editing plane, so a foreground block cannot steal
an empty cell behind it. Turning it on follows the visible terrain surface
and stacks above it. The setting controls 3D GridMap terrain targeting; it does not add vertical rows
to a 2D TileMapLayer. Stacking scene objects such as crates uses a separate
snap-profile setup.
For support, height, and overlap limits, add a TerrainStackRule3D resource to
the block entry's Placement Rules list. Its base_row defaults to 0 and
max_row to 7. Keep max_row within the object placement settings'
surface_scan_max_y so the cursor can still find the top. The rule validates
placement; stacks_on_occupied_cells chooses the target cell.
Drag shapes
Start a drag, then commit it — the host routes these intents for 3D sessions:
START_TERRAIN_DRAGanchors the drag at the cursor cell.COMPLETE_TERRAIN_DRAGstamps the shape between anchor and cursor.COMPLETE_DEMOLISH_DRAGerases the dragged shape instead.
For LINE and rectangle tools, preview_terrain_drag_3d returns the pending
shape without changing the world. SINGLE paints continuously: fast pointer
jumps fill the cells between samples. While held, its indicators show the last
attempted segment using the paint service's recorded outcomes: green for an
accepted cell, red for a rejected cell. Releasing or canceling clears that
segment and restores the current hover indicator. No separate preview path is
calculated.
Author rules for 3D paint
Subclass TilePaintRule and opt in:
func supports_3d_terrain()-> bool:
return true
func validate_cell(p_context:PlacementValidationContext)-> Array[String]:
var cell:Vector3i = p_context.cell_3d
var map:GridMap = p_context.target_map_3d
# ... your game policy here (tools, ownership, costs) ...
return []Rules that do not opt in never run on 3D paints — 2D-authored rules cannot observe 3D coordinates they cannot interpret. Entry/palette rule resolution works the same as 2D (PlacementRuleResolver.resolve_terrain).
Layers and persistence
Paint lands on the explicitly targeted GridMap only — pass it directly or bind it as the session's target_map_3d. Other layers are untouched.
The restore coordinator applies the GridMap cell data supplied by your save layer. The 3D demo saves every used cell with its item and orientation, then clears the map before applying them so cells removed since the save do not remain. React to edits live through TerrainPlacementService3D.terrain_cell_changed.
Related guides
Using this in a game?
Grid Placement v6.3.0 — full source, playable demos, commercial license
The guide above is the same setup the shipped demos use. Try the build in your browser before you buy it.