Scatter a thousand rocks across a terrain with Geometry Nodes, hit File → Export → glTF 2.0, and the GLB either comes back missing the scatter entirely or balloons to hundreds of megabytes. Neither is a bug. Blender's exporters read mesh data, not geometry node instances — a scatter is a set of transform pointers to one source mesh, and until something turns those pointers into real geometry, or the exporter understands instancing natively, export behavior is unpredictable. Two fixes exist: realize the instances into unique geometry before export, or ship them as `EXT_mesh_gpu_instancing` data. Only one of the three major game engines picks the second option up automatically.
Why Geometry Nodes exports come out empty or huge
![]()
A Geometry Nodes modifier that scatters copies via Instance on Points doesn't create new mesh data per copy — it stores one source mesh plus a list of transforms (position, rotation, scale). That's fast in the viewport and cheap in RAM. It's also invisible to exporters that only walk real mesh data, which is why an un-realized scatter can export as a single point, an empty object, or nothing at all, depending on exporter version.
The standard fix is the Realize Instances node (or the equivalent toggle at the top of the modifier stack in the Modifier Properties tab), which converts every transform pointer into actual mesh data. That guarantees compatibility with any importer, at a cost you can calculate directly: instance a mid-poly prop like the Young Treant — roughly 500 triangles — 2,000 times across a forest floor, and Realize Instances bakes the whole scatter into one 1,000,000-triangle mesh, every copy carrying its own vertex and UV data. Export the same scatter with `EXT_mesh_gpu_instancing` instead and the mesh payload stays at 500 triangles — the GPU redraws it 2,000 times from a transform buffer, which is the entire point of GPU instancing. A free account's two monthly downloads cover evaluation; commercial use is included with paid memberships (pricing).
Exporting instances the right way in Blender
Blender's glTF exporter has written `EXT_mesh_gpu_instancing` for regular object duplicates since version 4.0, and picked up an experimental Export Geometry Nodes instances checkbox (Data panel, Mesh section, in the glTF export operator) since 4.1, specifically for GN-generated scatters. Turning it on skips realization for instanced geometry and writes the GPU instancing extension directly instead — but it depends on Apply Modifiers being checked in the same panel, since that's what determines whether any modifier stack, Geometry Nodes included, affects the export at all.
Whichever path you take, verify the actual file rather than trusting the export dialog:
```bash
# Confirm the extension actually made it into the file
npx @gltf-transform/cli inspect scatter.glb | grep -A2 extensionsUsed
```
If `EXT_mesh_gpu_instancing` isn't listed, Blender fell back to realized geometry — check your triangle count against the math above to confirm which path you actually got.
Which engines actually pick up GPU instancing
![]()
Writing the extension is only half the pipeline. The importer on the other end has to read it too, and support is uneven enough that it should decide which export path you pick.
| Engine | Reads `EXT_mesh_gpu_instancing` on import | What you actually get |
|---|---|---|
| Unity (glTFast / UnityGLTF) | Yes | Each instance becomes a GameObject with GPU Instancing enabled on its material automatically |
| Godot 4.x | No — open feature request, unresolved as of this post | Instances typically collapse to a flat scene; build your own `MultiMesh` |
| Unreal Engine 5 (Interchange glTF) | Undocumented, not confirmed working | Treat as unsupported until you've verified it on your exact version |
| Blender re-import | Yes | Round-trips correctly for Blender-to-Blender pipelines |
For Godot specifically, the practical move is realizing instances in Blender and letting Godot import flat geometry — or, if the instance count is high enough that draw calls matter, rebuilding a `MultiMesh` by hand after import:
```gdscript
# Rebuild GPU instancing manually after a flat glTF import
var mm := MultiMesh.new()
mm.transform_format = MultiMesh.TRANSFORM_3D
mm.mesh = source_mesh_instance.mesh
mm.instance_count = transforms.size()
for i in transforms.size():
mm.set_instance_transform(i, transforms[i])
$MultiMeshInstance3D.multimesh = mm
```
That's the same technique engines have used for grass and rubble fields since long before glTF had an instancing extension — you're doing by hand what the extension was supposed to automate.
Gotchas
The experimental flag can rename or relocate between Blender point releases — if a tutorial screenshot doesn't match your export dialog, check the changelog for your exact build before filing a bug. Nested Geometry Nodes modifiers, where an instance's source object has its own GN modifier, can realize inconsistently; flatten to one level before export if the triangle count looks wrong. Apply Modifiers has to be on for either path — off, and the exporter reads your pre-Geometry-Nodes base mesh, not the scatter. Neither export path gives you collision automatically, either: glTF import drops collision by default in Unity, Godot, and UE5 alike, instanced or not.
If your target is UE5 and you're not confident `EXT_mesh_gpu_instancing` will land correctly, realize instances and compress instead — which engines actually decode Draco without a plugin is worth checking before you ship a 1,000,000-triangle GLB. And confirm which importer you're actually testing against on that engine first: UE5.8 quietly removed Datasmith's glTF importer, which changes what "supported" means release to release.
---
*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*