Skip to content

Grid Placement v6.3.0

3D Terrain Painting

Paint, replace, and erase GridMap terrain cells by catalog terrain name.

Status
Current
Version
v6.3.0
Source updated
2026-10-29
Generated on
2026-10-29

6.3. These pages document the 6.3 release, where placeable is now entry (what changed) and PlacementOwner is deprecated (migration). Still on 6.2? Your version's guides ship inside the plugin itself, under addons/grid_placement/guides/; the 6.2 URLs on this site now redirect to this series.

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:

  1. Open the block's TilePlacementEntry resource from your terrain palette or catalog.
  2. Under Terrain, enable Stacks On Occupied Cells (stacks_on_occupied_cells).
  3. Leave Require Existing Ground off when the block should be the base on an empty cell.
  4. 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 TerrainStackRule3D when 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:

  1. START_TERRAIN_DRAG anchors the drag at the cursor cell.
  2. COMPLETE_TERRAIN_DRAG stamps the shape between anchor and cursor.
  3. COMPLETE_DEMOLISH_DRAG erases 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.

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.