Quick answer: Two MultiMesh instances at the exact same position produce a depth tie that the rasterizer breaks differently every frame — you see shimmer. The fixes are to jitter positions by a per-instance noise offset, enable depth_prepass_alpha for transparent foliage, sort transparent multimeshes back-to-front, and use a normal-aligned vertex offset (Godot’s polygon-offset equivalent) on intentionally overlapping decal layers.

Here is how to fix Godot MultiMesh instances that z-fight or shimmer where they overlap. You scatter 5,000 grass instances across a hillside with a procedural placer, hit play, and a chunk of the hill flickers in the wind — not the foliage moving, but a strobing pattern across the surfaces of the cards. Or your stacked decal layers (a road overlay on top of terrain) shimmer in moving sun. Both come down to two surfaces drawing into the same depth-buffer pixel and the rasterizer flipping a coin on every frame.

The Symptom

You instantiate or generate a MultiMesh with hundreds or thousands of instances. The visible failure modes:

High-frequency shimmer where instances stack. Sections of the multimesh visibly buzz when the camera moves. Stationary camera, stationary instances, the buzz still appears at sub-pixel scale. Standard z-fight signature.

Whole instances disappear behind themselves. Two instances at the same transform produce overlapping geometry — one set of triangles wins the depth test and the other set draws nothing. Looks like missing pieces of the mesh from certain angles.

Transparency artifacts on foliage. Grass cards, leaf billboards, and other alpha-tested or alpha-blended multimeshes show wrong sort order — back leaves drawing in front of close ones — because MultiMesh has no per-instance depth sort.

Shadows shimmer too. The shadow map sees the same z-fight from the light’s perspective. Even if the visible mesh resolves, the shadow flickers because the shadow caster picks a different fragment per pixel each frame.

What Causes This

Instances at exact same position. Procedural placers commonly produce duplicates: the random seed is constant across iterations, the loop forgets to advance the seed, or the world-space hash collides. Two transforms with identical translation produce identical depth, and the depth test cannot distinguish them.

Identity transform default. Every MultiMesh instance starts at the identity transform. If your generation loop forgets to set a transform on a particular instance, that instance lives at the origin — on top of every other instance you also forgot to set. With 1000 instances missed, you get 1000 copies stacked at world origin.

No depth bias configured. Godot does not apply polygon offset by default. Stacked decals or layered terrain meshes that share the same depth need an explicit offset to win or lose the depth test consistently. Without it, every frame is a coin flip.

Shader writes depth twice. A shader with a vertex pass that displaces position based on UV (e.g., wind sway, vertex animation) can produce non-deterministic depth across frames if the displacement input changes per-frame. Two instances driven by the same wind seed end up at the same animated depth and z-fight cyclically with the wind.

Transparent sorting is global, not per-instance. MultiMesh is one draw call. Godot sorts draw calls back-to-front for transparency, but cannot reorder individual instances within a multimesh. Foliage cards rendered transparently will sort wrong almost everywhere they overlap.

The Fix

Step 1: Jitter positions with a per-instance seed. Even a millimeter of offset breaks the depth tie. Derive the offset from the instance index so your placement is still deterministic across runs:

# Generating MultiMesh transforms with per-instance jitter
func populate_grass(mm: MultiMesh, count: int, world_seed: int) -> void:
    mm.instance_count = count
    var rng := RandomNumberGenerator.new()

    for i in range(count):
        rng.seed = hash(world_seed + i)

        var base := grid_position(i)
        # Jitter by up to 5cm in XZ, 1cm in Y
        var jitter := Vector3(
            rng.randf_range(-0.05, 0.05),
            rng.randf_range(-0.01, 0.01),
            rng.randf_range(-0.05, 0.05))

        var t := Transform3D()
        t.origin = base + jitter
        t.basis = Basis().rotated(Vector3.UP,
            rng.randf_range(0.0, TAU))

        mm.set_instance_transform(i, t)

The hash(world_seed + i) seeding gives every instance a unique RNG state without losing determinism. Run the same world_seed twice and you get the same offsets. The 1cm Y jitter is the critical one for resolving depth fights at oblique camera angles.

Step 2: Enable depth_prepass_alpha for transparent foliage. Foliage cards almost always need this render mode. It writes depth in a prepass before the color pass, so within-instance overlaps resolve correctly without a per-instance sort:

shader_type spatial;
render_mode depth_prepass_alpha, cull_disabled,
             unshaded;

uniform sampler2D leaf_tex : source_color;
uniform float alpha_cutoff : hint_range(0.0, 1.0) = 0.5;

void fragment() {
    vec4 c = texture(leaf_tex, UV);
    if (c.a < alpha_cutoff) discard;
    ALBEDO = c.rgb;
    ALPHA = c.a;
}

depth_prepass_alpha is the Godot 4 equivalent of an alpha-to-coverage prepass. It is significantly cheaper than full transparent sorting and removes 90% of the visual problems with stacked foliage.

Sort Transparent Multimeshes Back-to-Front

If you genuinely need order-dependent transparency (smoke puffs, magic effects), the practical approach in Godot is to split the multimesh by camera distance into 2-4 buckets and draw each as a separate MultiMeshInstance3D. Each bucket has a depth range; sort the buckets front-to-back globally and rely on the within-bucket order being good enough.

func _process(_d: float) -> void:
    var cam_pos := get_viewport().get_camera_3d().global_position

    # Split instances into 4 distance buckets
    var buckets: Array = [[], [], [], []]
    for t in _all_transforms:
        var d := cam_pos.distance_to(t.origin)
        var b := clampi(int(d / 25.0), 0, 3)
        buckets[b].append(t)

    for i in range(4):
        var mm: MultiMesh = _bucket_meshes[i].multimesh
        mm.instance_count = buckets[i].size()
        for j in range(buckets[i].size()):
            mm.set_instance_transform(j, buckets[i][j])

This costs you per-frame CPU work, so reserve it for cases where transparency is actually important. For grass and leaves, alpha-tested with depth_prepass_alpha looks better than any sort you can afford.

Polygon-Offset Equivalent for Decal Layers

For intentional overlaps — a road decal on terrain, a stain layer on a wall — bias one layer toward the camera in the vertex shader:

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back;

uniform float z_offset : hint_range(0.0, 0.01) = 0.001;

void vertex() {
    // Push the decal slightly toward the camera
    VERTEX += NORMAL * z_offset;
}

1mm of normal offset is invisible at any normal viewing distance and reliably wins the depth test against the underlying surface. Apply it to whichever layer should appear on top. For overlapping decals, give each layer a different z_offset in increasing order.

“Z-fighting is the depth buffer telling you that two pieces of geometry are claiming the same pixel. Move one of them by a millimeter and the buffer stops arguing with itself.”

Related Issues

If MultiMesh performance is bad even after fixing visuals, see MultiMesh Slow With Many Instances. For shadow z-fights specifically, check Shadow Acne and Bias Tuning.

Jitter every instance, even by a hair — identical depth is the only thing the depth buffer cannot resolve.