graphics · sub-star
colossus
virtualized geometry from scratch in c++20 and vulkan, the idea behind nanite: 15.9 billion triangles in 1.51 ms.
readme
Virtualized geometry from scratch, the idea behind Unreal Engine 5’s Nanite, built with nothing but Vulkan and GLFW. A builder turns a scanned model into a crack-free hierarchy of clusters; a renderer streams it from disk and draws thousands of copies, picking per cluster the coarsest detail within a pixel of the original. 900 statues of Lucy and the XYZ RGB dragon are 15.9 billion triangles at full detail, drawn at 1920x1080 in 1.51 ms on an RX 9070 XT with soft shadows, bounce light, ambient occlusion and antialiasing. It takes real content too: a textured museum scan, skinned and animated characters, and a photoscanned pine forest of 753 million triangles. There is a one minute video on the repository. Clustering, simplification, streaming, culling, both rasterizers, shadows and shading all live in the repository, and the whole renderer is ported to WebGPU.
artifact
not simulated: the repo’s lod rule in 2d. each ring picks the coarsest level whose error is within a pixel on screen, and nearer means finer.
signal log
- clusters of at most 128 triangles by recursive bisection of the triangle graph, grouped about eight at a time, merged and simplified to half with locked outlines, level after level until one small root. every level indexes the original vertices, so a crack is exact, and every cut checked has none.
- errors are proven, not sampled: each level’s error is an upper bound on its distance from what it replaced, and the projection to the screen is bounded too. proving both costs triangles, 2.99m to 4.77m beside lucy: the usual error over distance was up to two pixels off axis where it promised one.
- errors only grow toward the root, so one comparison per cluster, own error on screen within a pixel and parent error beyond it, picks exactly one level on every path. one gpu thread per cluster, no tree to walk.
- checked in images, not just asserted: against full detail, every pixel whose coverage changes at a one pixel threshold touches the full-detail silhouette, and nvidia’s flip scores the shading.
- two rasterizers into one 64 bit visibility buffer: mesh shaders for clusters over 32 pixels, a compute rasterizer for the pixel-sized triangles hardware handles worst. the compute path saves 0.33 to 0.37 ms, and grows its triangles 1/256 of a pixel so the seams between the two stay watertight.
- two pass occlusion culling of cells, instances and clusters against a depth pyramid. at a million instances, 17.6 trillion triangles, it is what makes 1.78 ms possible.
- geometry streams from disk in bit-packed pages through a fixed pool on eight loader threads. a page is resident only while its coarser stand-ins are, so whatever has loaded, exactly one cluster draws on every path. from a cold cache the crowd settles in 34 ms.
- virtual shadow maps: a 14 level clipmap of 128 texel pages, drawn from the same hierarchy seen from the sun, with soft penumbras sized by a blocker search. with the camera still the shadow pages cost 0.08 ms.
- real content: the smithsonian’s george washington scan streams its own texture in tiles beside the geometry, khronos foxes run their skinned animations with errors measured in their poses, and poly haven’s pine forest, 14,780 instances of needles, ferns and rocks with their normal and roughness maps, draws in 7.5 ms.
- foliage breaks the usual simplifier: needles are islands edge collapse won’t delete, and a distance bound lets a crown thin, since every removed needle lies near a kept one. foliage errors also count the area they lose, so a pine 200 m away keeps 95% of its coverage at one pixel (88% before), and all 55 forest models stay crack-free at every cut.
- measured against meshoptimizer’s reference builder through the same renderer, only the builder swapped: colossus keeps silhouettes tighter at the same triangle count, meshoptimizer shades better and builds faster. the guarantee costs 0.12 ms in the crowd.
- the webgpu port has no mesh shaders, 64 bit atomics or ray queries, so the compute rasterizer runs twice and pages stream over http range requests. 900 instances take 1.73 ms of gpu time in chrome.