POLYMASON

A forest in Godot 4 with MultiMeshInstance3D

Part of Free low poly assets for Godot

A forest of a thousand MeshInstance3D nodes works, but it's slow. The same forest as one MultiMeshInstance3D is a single node with one draw call per level of detail, and it renders at the speed of a single tree. This article shows how to make one from a low poly tree, vary the trees, and keep the far ones cheap. It follows on from free low poly assets for Godot, which is where the tree comes from, and the packs compared, which is where the alternatives are. The levels the forest uses are in the Godot LOD article.

What a MultiMesh is

A MultiMesh resource holds one mesh and an array of instance transforms, and optionally a color and some custom data per instance. A MultiMeshInstance3D node draws it, every instance in one call, with the GPU doing the placement. The instances share the mesh and the material. That's why a tree with one material and a palette texture is the right export for this.

Setting one up in the editor

  1. Add a MultiMeshInstance3D to the scene.
  2. In the Inspector, give it a new MultiMesh resource. Set Transform Format to 3D, Mesh to the tree mesh, and Instance Count to the number of trees you want.
  3. Each instance now needs a transform. The editor's Populate Surface tool, in the MultiMeshInstance3D's menu in the viewport toolbar, scatters instances over a target mesh such as your terrain, with random rotation and scale within ranges you set. For a hand-placed forest, set the transforms from code instead.

Populating from code

This script goes on the MultiMeshInstance3D and scatters trees over a rectangle, with a random turn and a little variation in size:

extends MultiMeshInstance3D

@export var count := 800
@export var area := Vector2(200, 200)

func _ready() -> void:
    multimesh.instance_count = count
    var rng := RandomNumberGenerator.new()
    rng.seed = 7
    for i in count:
        var t := Transform3D.IDENTITY
        t = t.rotated(Vector3.UP, rng.randf() * TAU)
        t = t.scaled(Vector3.ONE * rng.randf_range(0.85, 1.15))
        t.origin = Vector3(rng.randf_range(-area.x, area.x) / 2, 0, rng.randf_range(-area.y, area.y) / 2)
        multimesh.set_instance_transform(i, t)

Set the height of each origin from your terrain, by raycast or by sampling the heightmap, so the trees stand on it. The scale variation and the turn about Y are what keep the forest from looking like a grid.

Color per instance

Per-instance color is the cheapest way to vary a forest. Turn on Use Colors on the MultiMesh and call set_instance_color(i, color) per tree. With a material that has Vertex Color Use as Albedo on, the color multiplies the palette, so you get a range of slightly different greens for free.

Levels of detail

Godot picks one automatic LOD level for the whole MultiMesh, from the nearest point of its bounding box, so every tree in it switches together. A Visibility Range works the same way and hides or shows the whole node. One MultiMesh for an entire forest therefore never drops detail while the camera is inside it. Split the forest into chunks, for example one MultiMeshInstance3D per 50 meter square, and the far chunks drop to a lower level on their own. For hand-made levels, give each chunk one MultiMeshInstance3D per level with the same transforms, and give each a Visibility Range so only one draws at a given distance. The Godot LOD article covers the ranges. A billboard level is a MultiMesh of quads with a billboard material.

Collision

A MultiMesh has no collision. For a forest the player walks through, add a CollisionShape3D per tree under one StaticBody3D, with a capsule at each instance's origin, from the same loop that placed the trees. Capsules are cheap enough that you can have thousands of them. You can also skip collision for the far forest and give it only to the trees near the path.

Where the add-ons take over

The scatter add-ons in the Asset Library paint trees onto terrain, thin them along roads and follow slopes, all on top of MultiMesh, and a terrain add-on usually comes with its own. Switch to one when you want to place trees with a brush. Until then, the loop above is enough.

What PolyMason exports

The tree builder writes one mesh with one material per tree, in meters, standing at the origin, which is what a MultiMesh needs. It also writes the tree's levels of detail as separate files, ready for a set of per-level MultiMeshes.

More in this guide

  • Free low poly assets for GodotWhere to get free low poly models that work in Godot 4, what each source's license allows, and which formats to prefer. It also covers importing an OBJ or GLB with its colors and flat shading intact, adding a collider, and scattering a forest.
  • Free low poly asset packs comparedThe free sources of low poly 3D models compared on license, formats, style and size, with what each one is best for. The paid packs are included for context, along with where a builder fits beside them.

Or build a tree and see what comes out.