Skip to content

three-virtual-geometryBillions of triangles in three.js

Virtual geometry for three.js WebGPU. Load your models, and every frame the GPU draws just the detail the screen can show. One line to set up.

A 2-million-triangle bronze sculpture in front of a ruined temple, rendered live in the browser
5.7 billion
triangles in the ruins scene
160–230 FPS at 1080p · 103–158 at 4K
37.5 billion
triangles, 3 million instances (6 km world)
147–150 FPS at 1080p · 101–120 at 4K
1 million
instances in the stress test
177–1,404 FPS at 1080p
101+ FPS
in every scene and view, even at 4K
at most 0.6 ms of CPU time per frame

Measured uncapped (no vsync), shadows on: Apple M4 Pro, Chrome 154. Every scene and camera view · run them yourself

Abstract ​

Rendering highly detailed scenes in real time usually means hand-made levels of detail, aggressive culling and a tight polygon budget. Virtual geometry removes the trade-off: every mesh is preprocessed into a hierarchy of small triangle clusters, and every frame a compute pass selects, per cluster, the coarsest version whose error is below a pixel on screen. Detail is then proportional to screen pixels, not to scene size.

three-virtual-geometry brings this technique to three.js on WebGPU. It builds the cluster hierarchy (with meshoptimizer), selects and culls clusters entirely on the GPU, and draws each mesh with a single indirect draw that works with three.js materials, lights and shadows. Foliage, which plain triangle simplification handles poorly, gets voxel-based coarse levels automatically. A whole scene goes through shared buffers and a fixed set of 12 compute passes, so a level with hundreds of different meshes costs the same per frame as one with a single mesh.

An ancient city of 5.7 billion triangles: temples, streets, walls, hills and trees
The showcase scene: 5.7 billion full-detail triangles in 113,000 instances, where every paving stone, column flute and carving is real geometry. About 7 to 9 million triangles are drawn per frame, at 100 to 230 FPS. Run it below.

Results ​

SceneFull-detail trianglesInstancesDrawn per frameFPS at 1080pFPS at 4K
Ruins5.7B113k6.5M – 9.0M160 – 230103 – 158
World (6 km)37.5B3.0M8.3M – 9.1M147 – 150101 – 120
Valley (2 km)1.1B152k3.1M – 8.6M159 – 329109 – 203
glTF import5.1M12k522k – 557k941 – 964468 – 516
Stress, 1M instances39.5B1.0M642k – 8.4M177 – 1,404154 – 696

Uncapped (no vsync): frames are submitted back to back and the GPU is waited on after every 8, so this is the sustained frame rate, not the display's. Each camera view is measured in 3 rounds of 96 frames (median round), after the automatic occlusion setting has settled; ranges span the views of each scene. Error threshold 1 px, shadows on (the stress test has none). Apple M4 Pro, 24 GB, darwin 25.5.0, Chrome 154.0.8037.98, 2026-10-08.

Drawn triangles stay roughly constant as scenes grow, because detail follows screen pixels. Every camera view, and how to run the benchmark on your machine: Performance.

Live demos ​

The scenes run right here, in your browser, with WebGPU (Chrome, Edge or Safari 26+), ordered from the heaviest to the lightest. Pick one and press run (the real scans are a recording: 2 GB is too much for a web page). Only the selected scene runs, and it pauses when you scroll away. The first load builds the scene's cluster hierarchies; later loads come from the browser cache. The left panel shows what the GPU is doing, and the settings panel on the right holds the levers.

Real 3D scans, the kind of data virtual geometry was made for, shown as a museum: 723 statues from 14 scans of classical sculpture, 1 to 4 million triangles each (SMK, National Gallery of Denmark, public domain), and 40 photoscanned rocks and cliffs (Poly Haven, CC0). 2.1 billion triangles, drawn with about a million per frame.

Recorded, because the scans are about 2 GB: too much to download just by opening a page. To run it live, clone the repository and run npm run demo:scans. It downloads the scans once and opens the scene.

How it works ​

  1. Build (once per mesh, cached). The mesh is split into clusters of up to 128 triangles. Neighbouring clusters are grouped, merged, simplified to half the triangles with their shared borders locked, and split again, level after level, into a hierarchy (a DAG). Every cluster stores its error and its parent's error, and errors only grow toward the root. When simplification stalls on aggregate geometry like tree crowns, a voxel proxy of the original takes over the coarse levels.
  2. Select (every frame, on the GPU). A cluster is drawn when its own projected error is at most the threshold (about one pixel) and its parent's is above it. Because errors grow monotonically, exactly one version of every part of the surface passes, so there are no holes and no overlaps. Cells of instances, single instances and clusters are culled against the view frustum, by size, by distance and (when it pays off) by occlusion.
  3. Draw. The selected clusters are expanded into one index buffer per pool, and each mesh draws its region with one indirect draw. The vertex shader pulls vertices from storage buffers, so the material is a normal three.js NodeMaterial.

More detail: How it works.

Use it ​

ts
import { VirtualGeometry } from 'three-virtual-geometry';

const vg = new VirtualGeometry();
await vg.add(gltf.scene);   // every static mesh becomes virtual geometry
scene.add(gltf.scene);
renderer.setAnimationLoop(() => renderer.render(scene, camera));

Getting started · Let your AI agent set it up

Acknowledgements ​

This is an independent, open-source recreation of the virtual geometry technique popularized by Nanite, written from public descriptions of the technique. It contains no code, shaders, binaries or assets from Epic Games, and is not affiliated with or endorsed by Epic Games. "Nanite" is a trademark of Epic Games, Inc. Parts of the preprocessing and GPU pipeline started from the MIT-licensed nanite-webgpu by Marcin Matuszczyk. Mesh simplification and clustering use meshoptimizer by Arseny Kapoulkine. Cars in the import demo are from the Kenney Car Kit (CC0).

Citation ​

bibtex
@software{benhaim2026threevirtualgeometry,
  author = {Ben-Haim, Elad},
  title  = {three-virtual-geometry: Virtual Geometry for three.js WebGPU},
  year   = {2026},
  url    = {https://github.com/elad12390/three-virtual-geometry},
  license = {MIT}
}

MIT License. An independent open-source implementation of virtual geometry, not affiliated with or endorsed by Epic Games.