How does Nanite work?
Nanite integrates as seamlessly as possible into existing engine workflows, while using a novel approach to storing and rendering mesh data.
- During import: meshes are analyzed and broken down into hierarchical clusters of triangle groups.
- During rendering: clusters are swapped on the fly at varying levels of detail based on the camera view, and connect perfectly without cracks to neighboring clusters within the same object. Data is streamed in on demand so that only visible detail needs to reside in memory. Nanite runs in its own rendering pass that completely bypasses traditional draw calls. Visualization modes can be used to inspect the Nanite pipeline.
Since Nanite relies on the ability to rapidly stream mesh data from disk on demand. Solid State Drives (or SSDs) are recommended for runtime storage.
What Types of Meshes Should Nanite Be Used For?
Nanite should generally be enabled wherever possible. Any Static Mesh that has it enabled will typically render faster, and take up less memory and disk space.
More specifically, a mesh is a good candidate for Nanite if it:
- Contains many triangles, or has triangles that will be very small on screen
- Has many instances in the scene
- Acts as a major occluder of other Nanite geometry
An example of an exception to these rules is something like a sky sphere: its triangles will be large on screen, it doesn't occlude anything, and there is only one in the scene.
Performance of Typical Content
For comparison purposes, the following GPU timings were taken from the PlayStation 5 Unreal Engine 5 technical demo
Lumen in the Land of Nanite:
- Average render resolution of 1400p temporally upsampled to 4K.
- ~2.5 millisecond (ms) to cull and rasterize all Nanite meshes (which was nearly everything in this demo)
- Nearly all geometry used was a Nanite mesh
- Nearly no CPU cost since it is 100% GPU-driven
- ~2ms to evaluate materials for all Nanite meshes
- Small CPU cost with 1 draw call per material present in the scene.
When considering these GPU times together, it's approximately 4.5ms combined for what would be equivalent to Unreal Engine 4's depth prepass plus the base pass. This makes Nanite well-suited for game projects targeting 60 FPS.
Numbers like these should be expected from content that doesn't suffer from the aforementioned performance pitfalls in previous sections. Very high instance counts and large numbers of unique materials can also cause increased costs and is an area of Nanite development that is being actively worked on.
Data Size
Because of the micro detail that Nanite is able to achieve, it might be assumed that it means a large increase in geometry data resulting in larger game package sizes and downloads for players. However, the reality isn't that dire. In fact, Nanite's mesh format is significantly smaller than the standard Static Mesh format because of Nanite's specialized mesh encoding.
For example, using the Unreal Engine 5 sample
Valley of the Ancients, Nanite meshes average 14.4 bytes per input triangle. This means an average one million triangle Nanite mesh will be ~13.8 megabytes (MB) on disk.
Comparing a traditional low poly mesh plus its Normal map to a high poly Nanite mesh, you would see something like:
Low Polygon Mesh
- Triangles: 19,066
- Vertices: 10,930
- Num LODs: 4
- Nanite: Disabled
Static Mesh Compressed Packaged Size: 1.34MB
Nanite Mesh
Static Mesh compressed package size: 19.64MB
Low Polygon Static Mesh
with 4k Normal Map
High Poly Static Mesh
with 4k Normal Map
The compressed package size isn't the entire size of the asset though. There are also unique textures only used by this mesh that have to be accounted for. Many of the materials used by meshes have their own unique textures made up of different Normal, BaseColor, Metallic, Specular, Roughness, and Mask textures.
This particular asset only uses two textures (BaseColor and Normal) and thus is not as costly on disk space as one with many other unique textures. For example, note the size of the of the Nanite mesh with ~1.5 million triangles is smaller in size (at 19.64MB) than a 4k normal map texture is.
Texture Type
Texture Size
Size on Disk
BaseColor
4k x 4k
8.2MB
Normal
4k x 4k
21.85MB
The total compressed package size for this mesh and its textures is:
- Low Poly Mesh: 31.04MB
- High Poly Mesh: 49.69MB
Because the Nanite mesh is very detailed already we can try replacing the unique normal map with a tiling detail normal that is shared with other assets. Although this results in some loss in quality in this case, it is fairly small and certainly much smaller than the difference in quality between the low and high poly version. So a 1.5M triangle Nanite mesh can both look better and be smaller than a low poly mesh with 4k normal map.
Total compressed package size for the Nanite-enabled mesh and textures:
27.83MB
High Poly Static Mesh
with 4k Normal Map
Nanite Mesh
with 4k Detail Normal Map
There are plenty of experiments that can be done with texture resolution and detail normal maps, but this particular comparison is to demonstrate that the data sizes of Nanite meshes are not too dissimilar from data that artists are already familiar with.
Lastly, we can compare the Nanite compression to the standard Static Mesh format using the high poly, where both are identical at LOD0.
High Poly Static Mesh
- Triangles: 1,545,338
- Vertices: 793,330
- Num LODs: 4
- Nanite: Disabled
Static Mesh Compressed Packaged Size:
148.95MB
Nanite Mesh
- Triangles: 1,545,338
- Vertices: 793,330
- Num LODs: n/a
- Nanite: Enabled
Static Mesh compressed package size:
19.64MB
Comparing the Nanite compression from earlier with a size of
19.64MB is
7.6x smaller than the standard Static Mesh compression with 4 LODs.
Nanite compression and data sizes are a key area that will be improved in future releases of Unreal Engine.