This page describes functionality that appears in both Unreal Engine and Unreal Editor for Fortnite (UEFN).
The page was originally prepared for Unreal Engine, so some descriptions and screenshots may appear different than what you see in UEFN.
Click here to go back to the main UEFN documentation.
Nanite is Unreal Engine 5's virtualized geometry system which uses a new internal mesh format and rendering technology to render pixel scale detail and high object counts. It intelligently does work on only the detail that can be perceived and no more. Nanite's data format is also highly compressed, and supports fine-grained streaming with automatic level of detail.
Benefits of Nanite
Multiple orders of magnitude increase in geometry complexity, higher triangle and objects counts than has been possible before in real-time
Frame budgets are no longer constrained by polycounts, draw calls, and mesh memory usage
Now possible to directly import film-quality source arts, such as ZBrush sculpts and photogrammetry scans
Use high-poly detailing rather than baking detail into normal map textures
Level of Detail (LOD) is automatically handled and no longer requires manual setup for individual mesh's LODs
Loss of quality is rare or non-existent, especially with LOD transitions
Although the advantages can be game-changing, there are practical limits that still remain. For example, instance counts, triangles per mesh, material complexity, output resolution, and performance should be carefully measured for any combination of content and hardware. Nanite will continue to expand its capabilities and improve performance in future releases of Unreal Engine.
Differences Between a Nanite Mesh and Static Mesh
A Nanite mesh is a Static Mesh with Nanite enabled on it. A Nanite mesh is still essentially a triangle mesh at its core with a lot of level of detail and compression applied to its data. On top of that, Nanite uses an entirely new system for rendering that data format in an extremely efficient way.
All that is required for a Static Mesh to take advantage of Nanite is a flag to enable it. Authoring content for Nanite is no different than traditional meshes except that Nanite can handle orders of magnitude more triangles and instances than is possible for traditionally rendered geometry. Move the camera close enough and Nanite will draw the original source triangles that were imported.
Nanite meshes support multiple UVs and vertex colors. Materials are assigned to sections of the mesh such that those materials can use different shading models and dynamic effects which can be done in the shaders. Material assignment can be swapped dynamically, just like any other Static Mesh, and Nanite doesn't require any process to bake down materials.
Virtual Textures are not required to be used with Nanite, but they are highly recommended. Virtual Textures are an orthogonal Unreal Engine feature with similar goals for texture data that Nanite achieves with mesh data.
Working with Nanite should be familiar to workflows for Static Meshes, but there are many things not yet supported. See the Supported Features section of this page for more details.
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 an especially 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
Casts shadows using Virtual Shadow Maps
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. Typically these exceptions are rare and performance loss for using Nanite with them is fairly minimal so the recommendation is to not be overly concerned about where Nanite shouldn't be enabled if Nanite supports the use case.
Some use cases are not supported by Nanite currently. See the Supported Features section of this page for more details.
Enabling Nanite Support on Meshes
Nanite can be enabled on supported geometry in the following ways:
Converting geometry to Nanite requires some processing time for each mesh. On large projects, use of a shared Derived Data Cache (DDC) is especially helpful if there are many Nanite Assets. Please refer to the Shared DDC documentation for more information.
Importing a Static Mesh
When importing a mesh intended for us with Nanite, check the box for Build Nanite.
It is recommended to disable Generate Lightmap UVs property when not using precomputed lighting with Lightmass.
When this property is enabled, highly detailed geometry adds significant time to importing and building of Static Mesh data. The property also adds an additional UV channel, which includes a significant amount of data for very dense meshes. If your project doesn't require baked lighting, there's no need to incur either cost.
Enabling Nanite on Assets
In cases where you already have your project populated with content that you want to enable Nanite on, you have two options: enabling assets in batches using the Content Browser, or enabling individual assets through their own editors.
Enable Nanite on Meshes in Batches
For batches of Static Mesh Assets that you want to enable Nanite for, use the Content Browser to select them all. Right-click and choose Nanite > Enable from the context menu.
Enable Nanite on Individual Meshes
Open the editor of any mesh that supports Nanite, such as Static Meshes and Geometry Collections (Chaos physics-driven fracture meshes) and enable Nanite through the Details panel.
In the Static Mesh Editor, locate the Nanite Settings and check the box for Enable Nanite Support.
In the Geometry Collections Editor, locate the Nanite section and check the box for Enable Nanite.
Supported Features of Nanite
This section describes how best to work with Nanite in an Unreal Engine project with details on what is and is not supported and possible limitations.
Geometry
Nanite can be enabled on Static Meshes and Geometry Collections.
A Nanite-enabled mesh can be used with the following Component types:
Static Mesh
Instanced Static Mesh
Hierarchical Instanced Static Mesh
Geometry Collection
Foliage Painter
Landscape Grass
Nanite has limited support for deformation of rigid meshes. Nanite supports dynamic translation, rotation, and non-uniform scaling of these meshes, whether it is dynamic or staic. This means moving any position of a Nanite mesh in a way taht is more complex than can be expressed in a single 4x3 matrix multiply, uniformly applied to the entire mesh.
Deformation is limited with:
(Beta) World Position Offset in Materials
The bounding boxes used for occlusion cull clusters does not update or expand their bounding boxes based on deformation. This means that any time a surface is displaced outwards, such that it would cover where it previously was, there is a good chance it could occlude itself and look broken.
Foliage using WPO is less problematic because foliage is filled with holes and cannot really occlude itself.
Deformation is not supported with:
Skeletal animation
Morph Targets
Spline meshes
Nanite-enabled meshes do not currently support:
Custom depth or stencil
Vertex painting on instances
This specifically means per-instance painted colors using the editor's Mesh Paint mode, but Nanite does support vertex colors on the original mesh.
The maximum number of instances that can be present in the scene is hard-locked to 16 million instances, which includes all instances that are streamed in, not just ones enabled for use with Nanite. Only instances streamed in are counted towards the total.
Per vertex tangents are not stored from the Static Mesh when it is enabled for Nanite. Instead, tangent space is implicitly derived in the pixel shader. Tangent data is not stored in order to reduce data size. This difference in tangent space using this approach could cause discontinuities at edges. However, this particular issue has not shown to be significant, and there are plans to support vertex tangents in a future release.
Materials
Nanite supports materials which have their Blend Mode set to Opaque and Masked. When an unsupported material type is detected, a default material is assigned to the Nanite-enabled mesh and a warning is placed in the Output Log with additional information.
Additional material features notes:
Nanite-enabled meshes can receive decals projected onto their surfaces but does not support Mesh Decals, which require materials to use a Translucent Blend Mode.
Wireframe checkbox is not supported.
The Vertex Interpolator node and Custom UVs are supported but will be evaluated three times per pixel.
Rendering
The following rendering features are not currently supported:
View-specific filtering of objects using:
Minimum Screen Radius
Distance culling
Forward Rendering
Stereo rendering for Virtual Reality
Split Screen
Multisampling Anti-Aliasing (MSAA)
Lighting Channels
Ray-tracing against Nanite meshes
The Fallback Mesh is used for Nanite-enabled meshses by default. Lower the Fallback Relative Error parameter in the Static Mesh Editor to use more of the source meshe's triangles.
(Experimental) Initial support for native ray-tracing of Nanite meshes is enabled with the console variable
r.RayTracing.Nanite.Mode 1
. This preserves all detail while using significantly less GPU memory than zero-error Fallback Meshes.
Some visualization view modes do not yet support displaying Nanite meshes
Use caution with some visualization modes in the Static Mesh Editor when viewing highly detailed geometry. Viewing Normals and UV can cause problems with editor performance.
Supported Platforms
Nanite is currently supported on PlayStation 5, Xbox Series S|X, and PCs with graphics cards meeting these specifications, using the latest drivers with DirectX 12 with Shader Model 6 (SM6):
NVIDIA: Maxwell-generation cards or newer
AMD: GCN-generation cards or newer
All newer versions of Windows 10 (newer than version 1909.1350) and Windows 11 with support for DirectX 12 Agility SDK are supported.
Windows 10 version 1909 — The revision number should exceed or be equal to .1350.
Windows 10 version 2004 and 20H2 — The revision number should exceed or be equal to .789.
DirectX 12 with Shader Model 6.6 atomics, or Vulkan (VK_KHR_shader_atomic_int64)
Latest Graphics Drivers
PlayStation 4 and Xbox One also support Nanite, but support on these platforms is currently considered experimental. It is expected that the performance of Nanite on these platforms with very high fidelity content may not meet the requirements of a shippable game.
Nanite Fallback Mesh and Precision Settings
Static Meshes include additional properties that control the precision of the Nanite representation and the Fallback Mesh generated from the full-detail mesh.
These settings are located in the Static Mesh Editor Details panel under the Nanite Settings section.
Nanite settings include the following properties:
Property |
Description |
---|---|
Enable Nanite Support |
Enables this mesh to be used with Nanite and to generate a Fallback Mesh in situations where Nanite cannot be used. |
Preserve Area |
Enables Nanite meshes that would lose surface area due to simplification to redistribute that lost area to the remaining triangles by dilating out the open boundary edges. This is most useful for foliage where leaves tend to become disjoint triangles and quads through simplicication. The effect of this setting is to scale each leaf up. For geometry ribbons, like blades of grass, it has the effect of thickening them. This setting should be enabled on all foliage meshes and nothing else. |
Position Precision |
Choose the precision this mesh should use when generating the Nanite mesh. Auto determines the appropriate precision based on the size of the mesh. The precision can be overridden to improve precision or optimize disk footprint. |
Minimum Residency |
Sets the memory byte size this mesh should always keep in memory, and has the rest streamed in. Higher values require more memory, but for some meshes, this can mitigate streaming pop-in issues from occurring. |
Keep Triangle Percent |
The percentage of triangles to keep from the source mesh. Reduce this percentage to optimize disk size. |
Trim Relative Error |
Sets the maximum amount of relative error that is allowed to be removed for the Nanite mesh. All detail in the source mesh with less visual impact than this relative error amount is removed. The relative error does not have a unit size and is relative to the size of the mesh. By default, Nanite stores all of the original source mesh's triangles. |
Fallback Triangle Percent |
Sets the percentage of triangles that remain when reducing the source mesh for Nanite. This becomes the coarse representation (or Fallback Mesh) used when the full detail Nanite data cannot be, such as platforms which do not support Nanite rendering, or when it is impractical to use Nanite data like with complex collision. |
Fallback Relative Error |
Sets the maximum amount of relative error that is allowed to be removed for the Fallback Mesh. All detail in the generated Fallback Mesh with less visual impact than this relative error amount is removed. The relative error does not have a unit size and is relative to the size of the mesh. |
Source Import Filename |
The file path used to import a High Res mesh to be used with Nanite. The high resolution version of the mesh is used in place of LOD0 by systems that can benefit from more detailed geometry, such as Nanite and Geometry Modeling in Unreal Engine. |
Vertex Precision
Nanite quantizes mesh vertex positions to maximize memory density and minimize disk footprint. The quantization step size is a power of two that can be selected to match the requirements of individual meshes using the Position Precision property. By default, Auto picks the appropriate precision based on the size of the mesh and its triangle density. You can manually override by selecting a precision size to improve precision or optimize disk footprint.
Qantinization is a form of lossy compression. Lossy compression is particularly challenging when working with modular mesh pieces, or other meshes that have shared boundaries. Especially when those boundaries need to align perfectly to not introduce holes or cracks in the geometry.
To ensure consistency, quantization happens in unnormalized object coordinates centered around the mesh origin. This ensures that the quantization never causes cracks when the mesh uses the same precision setting, and the translation between the mesh center is a multiple of that precision.
Trimming data
There are times when you'll need to reduce the amount of data Nanite stores to optimize for disk size. Nanite includes settings which allow you to trim the detail data from a stored Nanite mesh at any time during production, meaning that you can safely overshoot quality up front and adjust accordingly later on.
To trim the detail data, you will want to use the Keep Triangle Percent and Trim Relative Error properties. You can think of them like a pre-decimate option before being stored as a Nanite mesh. In Nanite's case, detail doesn't need to be uniform across the mesh. It removes the least significant data first and is more akin to lossy compression.
Use Keep Triangle Percent to set the percentage of triangles to keep from the source mesh.
Use Trim Relative Error to set the maximum amount of relative error that is allowed when trimming the data from the source mesh. Any triangle that if removed would incur a relative error less than this amount is removed. Or another way to think about this is all detail with less visual impact than this value is trimmed. Relative error does not have a unit size and is relative to the size of the mesh.
The defaults for both of these properties are such that nothing is trimmed by default, and Nanite stores all of the original source mesh's triangles.
Trimming data is important to reducing disk size (in other words, download size), not for improving performance. See Data Size section below for more on this topic.
Fallback Mesh
Many parts of Unreal Engine need access to the traditional vertex buffer provided by traditionally rendered meshes. When Nanite is enabled for a Static Mesh, it generates a coarse representation (called a Fallback Mesh) of the highly detailed mesh that is accessible and used where Nanite data cannot be. The Fallback Mesh is the generated mesh used when Nanite rendering is not supported. It is also used in situations where it wouldn't be ideal to use the full-detail mesh, like when complex collision is needed, using lightmaps for baked lighting is required, and for hardware ray tracing reflections with Lumen.
The Fallback Triangle Percent property represents the percentage of triangles from the original source mesh that are used to generate the Fallback Mesh. You can specify the percentage of triangles to keep between 0 and 100 percent, where large percentages keep more of the original mesh's detail.
The Fallback Relative Error sets the maximum amount of relative error that is allowed when removing details from the source mesh. Any triangles that if removed would incur a relative error less than this amount are removed with detail of less visual impact being first to go. The relative error does not have a unit size and is relative to the size of the mesh.
For example, if you wanted your mesh to not have any decimation at all, you would use a Fallback Triangle Percentage of 100 and a Fallback Relative Error of 0.
In the comparison below, there is the highly detailed Nanite mesh created from the original source mesh which is compared with default settings of a generated Nanite Fallback Mesh.
Use the Fallback Relative Error to specify how much of the original detail is retained from the original source mesh, and the Fallback Percentage to set how much of that detail is used.
In the comparison below, the Fallback Mesh keeps 100 percent of the Fallback Triangle Percent but adjusts the Fallback Relative Error to use more of the triangles from the original source mesh. When adjusting these values, you can use the Nanite details for Nanite Triangles in the viewport as an indicator when changing their values.
Fallback Mesh Visualization
In the Static Mesh Editor, you can toggle between the fully detailed Nanite mesh and the Nanite Fallback Mesh using the viewports Nanite Fallback option in the Show dropdown menu. Alternatively, you can use the hotkey Ctrl + N to quickly toggle between the two visualization options.
Using Custom Fallback Mesh LODs for Nanite-enabled Meshes
The Fallback Mesh is used for engine features, such as complex per-poly collision, ray tracing, light baking, and so on. It is also used for platforms which do not support Nanite. When generating the Fallback Mesh, a Nanite-enabled mesh always uses the LOD0 slot of the source mesh for auto-generating the fallback mesh. However, there are times when it is desirable to use a manually specified fallback mesh, or a series of traditional LODs, rather than an auto-generated one.
This level of control would allow you to use Nanite in a project but also directly control the geometry seen in ray-traced reflections, or on platforms which do not support Nanite.
Follow the steps below to specify your own custom fallback mesh, or to use a series of LODs:
Set the Fallback Triangle Percent to 0 so that the fallback mesh is as small as possible since it will be ignored when using this approach.
Add one or more LODs to the mesh using this traditional LOD setup procedure.
Use the LOD Import dropdown to Import LOD Level 1 from the LOD Settings section.
Set the Minimum LOD to 1 under the LOD Settings section. This causes the Nanite-generated Fallback Mesh to be ignored.
Complex Collision presents a special case. Use the LOD for Collision property under General Settings to specify which LOD should be used for collision. Any LOD can be used for collision, including LOD0.
This particular approach may not be feasible to make Nanite projects automatically compatible with non-Nanite-supporting platforms, and should be tested and evaluated for your project.
Nanite efficiently handles very large numbers of instances, but if Nanite is disabled, there could be an overwhelming number of draw calls for the traditional render pipeline. You can test this in your project for feasibility using the r.Nanite 0
to toggle Nanite support off and on.
See the Console Variables and Commands section of this page for more information.
Working with Nanite-Enabled Content
In most cases, Nanite scales extremely well within screen resolution. It does so based on two techniques: fine-grained level of detail and occlusion culling. Typically this means, regardless of geometric complexity of the source data in the scene, the number of triangles Nanite attempts to actually draw to the screen is consistent and proportional to the number of pixels.
Nanite follows the design principle that there is no use in drawing far more triangles than there are pixels.
However, there are some cases of content that breaks the techniques Nanite uses to scale, but this doesn't mean it should not be used at all for this content, or that it will not render faster than the traditional rendering pipeline. It only means that for this type of content, scaling with pixels — and not scene complexity — no longer applies to them. Use the Profiling features provided by Unreal Engine to monitor these types of situations when they occur.
Aggregate Geometry
Aggregate geometry is geometry that has many disjointed parts that become a volume in the distance, such as hair, leaves on trees, and grass. This type of geometry breaks the level of detail and occlusion culling techniques of Nanite.
Nanite is inherently a hierarchical level of detail structure that relies on being able to simplify small triangles into larger triangles and choosing the coarser one when it determines the difference is smaller than can be perceived. For continuous surfaces, this works well, but not for aggregate geometry that from a distance appear more like a partial opaque cloud than a solid surface.
As such, Nanite is more likely to determine it cannot reduce aggregate geometry nearly as aggressively as it would typical solid surfaces, thus resulting in more triangles being drawn for the same number of pixels covered.
Another optimization that aggregate geometry breaks is Occlusion Culling. Although it is very fine-grained, its granularity is not per pixel. Geometry that is filled with holes — and worse yet, layers upon layers of geometry filled with holes — causes excessive overdraw because many depth layers need to build up before that area on screen will block anything behind it. One way to think about this is to consider an 8x8 pixel region on screen and how many depth layers need to be drawn before every pixel is filled. Excessive overdraw means that for the same number of pixels covered, Nanite attempts to draw more triangles causing it to render slower.
Foliage is the most obvious case for causing problems with occlusion culling, but even then, it does not mean that Nanite should not be used on foliage-type meshes at all. Refer to the Foliage Using Nanite section below for more.
It is good to experiment with different use cases and see what works well for your projects. Use profiling tools to confirm good performance from Nanite with these types of meshes.
Closely Stacked Surfaces
Occlusion culling with traditional meshes makes kitbashing workflows nearly impossible on a large scale due to practical limitations. The fine-grained nature of occlusion culling with Nanite makes it possible to use these types of workflows during development with less concern.
As is explained in the Aggregate Geometry section above, overdraw can come from hidden surfaces being very close to visible surfaces below them. If any geometry is buried well below the visible surface, Nanite detects and culls it fairly cheaply, such that it can mostly be considered free of cost. However, when there is stacked geometry that is close together near the top-most surface, Nanite is not able to determine which is on top or bottom, causing both to be drawn simultaneously.
This particular issue with culling is a worst case scenario where Nanite does not know which surface is on top, and just draws all the layers instead. Imprecision like this scales with screen size and distance, so while 10 centimeters may separate layers and look fine while close to the surface, farther distances away can cause the difference in distance to be smaller than a pixel, resulting in overdraw.
In the example below, if the camera is moved to look downward on the area where the character is standing, the Nanite Overdraw visualization shows how these stacked surfaces are being rendered. Brighter areas indicate more overdraw is happening in those areas than others.
The Overdraw visualization is the most effective way to find issues of overdraw. While some amount of overdraw should be expected, excessive amounts of it result in Nanite culling and rasterization costs becoming higher, and Nanite's scaling independently of scene complexity will become less effective in the process.
Faceted and Hard-edge Normals
One issue to be mindful of is when importing highly detailed meshes that have faceted normals, meaning that the normal between two different polygons was not smoothed. This issue is common and easy to miss and caution should be taken to avoid this particular issue because low amounts of vertex sharing in a mesh can become significantly more expensive both in rendering performance and data size.
Ideally, the number of vertices for a mesh should be less than the number of triangles it has. If the ratio is 2:1 or higher, then there is likely a problem, especially if this results in a high triangle count. Having a ratio of 3:1 means the mesh is completely faceted where every triangle has its own three vertices, none of which are shared with another triangle. Most often, this is caused by the normals not being the same because they are not smoothed.
With that in mind, more vertices means more data to store. It also means more vertex transform work, and ratios higher than 2:1 fall down some slow rendering paths. Intentional use in hard surface modeling shouldn't cause any issues, and there is no reason not to use them. However, accidental 100% facet very dense meshes are far more expensive than intended. Another thing to watch out for is imported normals on dense organic-type surfaces generated in other DCC packages that have hard normal thresholds that might be sensible on lower polygon meshes, but can add unnecessary expense with Nanite.
For example, In the two meshes below, the mesh on the left has faceted normals while the one on the right has smoothed normals. When comparing these using the Nanite Triangles visualization, there are noticeable differences in the number of triangles used by Nanite to draw them. The faceted one on the left draws significantly more triangles than the smoothed one on the right.
Nanite-enabled meshes with faceted (left) and smoothed (right) normals |
Nanite Triangle Visualization of Nanite-enabled meshes with faceted (left) and smoothed (right) normals |
Click image for full size. |
Click image for full size. |
Foliage Using Nanite
Foliage using Nanite is considered Beta and is beting actively researched and developed. This section provides some guidance on using foliage with Nanite in Unreal Engine 5.1.
For assets like trees with default Nanite settings you might find that the canopies tend to thin out with distance. These cases are a particular form of Aggregate Geometry where each disjoint part (a leaf or grass blade) has open edges at its boundary. Enabling Preserve Area is useful to prevent this thinning out when Nanite is enabled. When Nanite simplifies the geometry in the distance by reducing the number of triangles, it eventually needs to start removing some of these disjoint elements completely. Without Nanite having more information the result will look thinned out because there was major surface area loss. Preserve Area will redistribute that lost area to the remaining triangles by dilating out the open boundary edges. Dilation for symmetric shapes like leaves has the same effect as scaling them up. In non-symmetric cases like ribbons, for example blades of grass, it has the effect of thickening them.
Preserve Area is recommended for all foliage meshes, but not for meshes that are not foliage.
The Nanite Cluster visualization provides a clearer look at how Preserve Area redistributes lost area.
Below are some recommendations when using and authoring foliage assets with Nanite in mind. We are still experimenting and learning ourselves what are the best approaches. So far, we have seen that foliage using Nanite should be authored differently than before but if you play to its strengths you can get faster, higher quality results using Nanite.
Use Preserve Area (enabled in the Static Mesh Editor).
Use geometry instead of masked cards.
Masked materials are fairly expensive compared to Opaque ones. Fastest results are likely obtained by not using them at all.
The traditional card approach (many elements are represented with a single card) with Nanite can be slower than non-Nanite. Do not expect that enabling Nanite on card-based foliage will always be a performance improvement.
Masked out pixels cost nearly as much as drawn pixels. Overdraw is already an issue with aggregates in Nanite. If a masked material is used, the Nanite overdraw visualization will not tell you the entire story in terms of cost. Overdraw is a complex concept in this case and the visualization only shows a particular aspect of it.
Geometry foliage has shown to be faster with Nanite than card approaches, both Nanite cards and non-Nanite cards. It also looks better.
The Megascans: Grass pack on the Unreal Engine Marketplace offers good examples for testing. The pack offers both masked and high-poly geometry where each element is independent and masked low-poly cards where many elements are represented by a single card.
When using World Position Offset (WPO), more vertices equal higher cost. WPO logic must be limited and monitored.
The issues explained in the Aggregate Geometry section of this page still apply. Dense forests (like the examples above) will render much slower than the same scene with all meshes replaced with solid shapes of the same triangle count.
Hybrid Non-Nanite and Nanite Content Workflows
The following sections highlight workflows you can use in your Nanite-enabled projects that need to also support non-Nanite features and platforms without duplicating assets.
Importing a High Resolution Mesh for Nanite
You can import a high resolution mesh to be your Nanite representation for any existing non-Nanite Static Meshes through the Content Browser or the Static Mesh Editor.
From the Content Browser, you can use the right-click context menu on a Static Mesh Asset to select Level of Detail > High Res > Import High Res and navigate to the file you want to import.
Alternatively, you can use the Static Mesh Editor to import a high resolution mesh using the Nanite Settings in the Details panel. Click Import and navigate to the file you want to import.
Using this workflow, the pre-existing Static Mesh and its level of detail (LOD) chain become the Fallback Mesh rather than having the import process automatically generate a Fallback Mesh from the Nanite geometry.
This workflow respects the Disallow Nanite setting on Static Mesh Actors in your scenes and is explained more in the Static Mesh Component Options section below.
Material Workflows
There are two ways you can improve your non-Nanite and Nanite workflows with materials: by using a node in the material graph to break up logic paths, or by using an override material only used for rendering with Nanite.
Nanite Pass Switch Node
The Nanite Pass Switch node allows you to define specialized behavior in a material graph when rendered with Nanite.
Use the Default input when rendering into non-Nanite passes, to handle the material as it would be normally. Use the Nanite input for any material logic you want to simplify or be specifically rendered to Nanite passes. For example, in cases where a material uses a feature not supported by Nanite, you could keep the same logic for the Default input and use a friendlier logic for the Nanite input.
Nanite Override Material
The Nanite Override Material slot is available on Materials and Material Instances. When you set an override material, any Nanite-enabled meshes that have the Material or Material Instance assigned will use the referenced Nanite Override Material instead. This means that you can create materials specific to Nanite workflows rather than managing logic directly inside the material graph using the Nanite Pass Switch node.
In Material Instances, the Nanite Override Material slot is forcibly defaulted to None so that setting the override in a parent Material will not cause it to automatically be inherited in any of the child instances of that material.
In the example below, the Static Mesh Asset for the statue has Nanite enabled and it has a Material Instance applied. The Material Instance has its Nanite Override Material set with some simple color changes for demonstration purposes. The Static Mesh Actor on the left displays the Nanite Override Material since the mesh is being rendered with Nanite. The Static Mesh Actor on the right displays the same material until Disallow Nanite is set on the actor, disabling the Nanite Override Material to show the non-Nanite base material of the Material Instance.
Static Mesh Component Option: Disallow Nanite
You can set when Nanite-enabled Static Meshes should use their Nanite representation using the Disallow Nanite setting on individual scene actors. This means you can have a mix of Nanite and non-Nanite actors which use the same Static Mesh Asset.
The example below shows a single Nanite-enabled Static Mesh Asset where the left is the Nanite mesh representation and the right has Disallow Nanite enabled.
Landscape Terrain
This is an experimental feature.
To use Nanite with your Landscape terrain, select it and use the Details panel to check the box next to Enable Nanite.
There are two ways to build the Nanite mesh representation from Landscape data:
Click the Rebuilt Data button in the Landscape's Details panel under the Nanite section.
Use the Build menu to select Build Nanite Only.
Depending on the size of the Landscape, or number of tiles, it can take a moment for it to generate its Nanite representation. When complete, you can check it out in the Nanite visualization modes.
The following console variables are useful when working with Nanite-enabled Landscapes:
Landscape.LiveRebuildNaniteOnModification
triggers a rebuild of the Nanite representation immediately when a modification is performed. (Default 0)Landscape.RenderNanite
sets whether the Landscape should render using Nanite or not. (Default 1)
Nanite-enabled Landscapes have the following limitations:
When using live modification of Nanite-enabled Landscapes (
Landscape.LiveRebuiltNaniteOnModification 1
), it makes landscape sculpting almost unusable because it rebuilds the Nanite representation of all Landscape Actors at every frame.The maximum resolution of the Nanite mesh is the same as LOD0 for Landscape. No resolution increase should be expected by using Nanite over a normal Landscape. In its current state, this is purely a runtime optimization.
Saving Landscape Actors with Nanite enabled when Nanite mesh has not been updated is slower since Nanite meshes have to be built before saving.
Technical considerations:
Nanite Landscapes are currently streamed in on top of the usual Landscape data streaming because both Nanite and non-Nanite data are necessary at runtime, with the latter required for Runtime Virtual Textures, water rendering, and more. This means twice the data has to be streamed in — one set of data with Nanite streaming, and the other with the texture streaming — and resident in memory when Nanite is enabled.
Runtime performance is improved with Nanite rendering, especially with regards to shadow passes, but no visual improvement (or downgrade) should be expected since the source data is identical.
Hierarchical Level of Detail (HLOD)/streaming is expected to behave identically to non-Nanite Landscape.
When editing Nanite-enabled Landscapes, we advise to keep the live rebuilding of Nanite meshes off (Landscape.LiveRebuiltNaniteOnModification 0
). Landscape rendering relies on non-Nanite Landscapes until the Nanite mesh is rebuilt (either on save or when using the Build Nanite Only / Build All Landscapes in the Build menu) and up-to-date, in which case it will use that version for rendering. Since no major visual difference should exist between Nanite and non-Nanite Landscapes, it does mean that in-editor performance while the non-Nanite Landscape is in use is not representative of the runtime performance in your project.
Performance of Typical Content
For comparison purposes, the following GPU timings were taken from the Unreal Engine 5 technical demo Lumen in the Land of Nanite on a PlayStation 5:
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
Static Mesh Compressed Packaged Size: 1.34MB |
Nanite Mesh
Static Mesh compressed package size: 19.64MB |
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 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
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
Static Mesh Compressed Packaged Size: 148.95MB |
Nanite Mesh
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.
General Advice on Data Size
Nanite and Virtual Texturing systems, coupled with fast SSDs, have lessened concern over runtime budgets of geometry and textures. The biggest bottleneck now is how to deliver this data to the user.
Data size on disk is an important factor when considering how content is delivered — on physical media or downloaded over the internet — and compression technology can only do so much. Average end user's internet bandwidth, optical media sizes, and hard drive sizes have not scaled at the same rate as hard drive bandwidth and access latency, GPU compute power, and software technology like Nanite. Pushing that data to users is proving challenging.
Rendering highly detailed meshes efficiently is less of a concern with Nanite, but storage of its data on disk is now the key area that must be kept in check.
Visualization Modes
Nanite includes a number of visualization modes to inspect its data in the current scene.
In the Level viewport under the View Modes dropdown, hover over Nanite Visualization and choose from the selection.
The Overview visualization displays the rendered scene in the center of the image with select Nanite visualizations around the screen for reference.
The following Nanite visualization modes are available to choose from:
Nanite Visualization |
Description |
---|---|
Mask |
Visualization that marks Nanite (green) and Non-Nanite (red) geometry. |
Triangles |
Displays all triangles of the Nanite meshes in the current scene. |
Clusters |
Displays colored representations of all grouping of triangles being rendered in the current scene view. |
Primitives |
Visualization that colors components all the same color for all instances in an Instance Static Mesh (ISM). |
Instances |
Visualization that applies a different color for each instance in the scene. |
Overdraw |
Displays the amount of overdraw happening for scene geometry. Smaller objects that are closely stacked together create more overdraw than larger ones. |
Material ID |
Displays separate colors for each Material ID of individual Nanite meshes. |
Lightmap UV |
Visualization that displays the UV coordinates of Nanite mesh surfaces. |
Evaluate WPO |
Colors Nanite-enabled geometry that are using world position offest (green) versus ones that are not (red). |
Nanite includes an Advanced visualizations mode that enables additional visualization options in the Nanite Visualization menu. These visualizations are useful for programmers who are debugging or profiling various low level aspects of Nanite.
Enable this advanced visualization mode with the console variable r.Nanite.Visualize.Advanced 1
.
Console Variables and Commands
The following stats and console variables are available for use in debugging and configuring Nanite.
Nanite rendering can be enabled and disabled globally at runtime using the console variable r.Nanite 0
. Disabling Nanite is a good way to emulate platforms where it is not supported.
Nanite Fallback Rendering Modes
Nanite provides fallback mesh rendering modes for when Nanite is either disabled or unsupported by a platform. You can control which mode is used with the console variable r.Nanite.ProxyRenderMode
.
0 is the default mode and falls back to rendering fallback meshes, or screen space-driven LODs, if set. This includes the recognition of Min LOD in the Static Mesh Editor properties (described in the Fallback Mesh section above).
1 disables all rendering of Nanite-enabled meshes.
2 works similarly to mode 1 but allows the Show > Nanite Fallback visualization in the Static Mesh Editor to render a Nanite fallback.
The Fallback render modes 1 and 2 are useful for scenes that have far more instances than could possibly be supported without Nanite. They allow the scene to be opened in the editor on non-Nanite-supporting platforms.
For example, in the Unreal Engine 5 Valley of the Ancients sample project, disabling Nanite would cause there to be tens of thousands of regular draw calls happening, making it difficult to open the map on a non-supporting platform.
Nanite Stats Command
The command Nanitestats adds an overlay of Nanite culling statistics to the top-right of the viewport.
Command arguments are used to specify what stats Nanite displays on screen. When no argument is provided, the primary view is used.
Use Nanitestats List
to show all available views in the debug output:
Primary
VirtualShadowMaps
You may also see other stats available for ShadowAtlas
and CubemapShadows
when available. Select a view by entering the command followed by that stat list name you want to view. For example, you would enter NaniteStats VirtualShadowMaps
.
For views that use two-pass occlusion culling, the statistics are split into separate buckets for Main and Post pass.
Controlling Nanite Streaming Pool Size
Control the amount of memory dedicated to holding Nanite streaming data with the console variable r.Nanite.Streaming.StreamingPoolSize
. Using larger pools reduces IO and decompression work when moving around the scene but at the cost of a larger memory footprint.
If the pool is not large enough to fit all the data needed for a view, cache thrashing can occur where streaming never settles even for a static view.
This console variable cannot be changed at runtime and must be specified in a configuration (.ini) file.
Setting Maximum Clusters in a Single Pass
You can specify the maximum number of candidate and visible clusters used in a single pass with the console variable r.Nanite.MaxCandidateClusters
and r.Nanite.MaxVisibleClusters
. Their values are used for sizing intermediate buffers and their default values have been chosen to work for common rendering scenarios.
There is no mechanism for dynamically resizing either of these buffers, or automatically scaling down quality on overflow, which can result in rendering artifacts from them being too small for scene complexity, and typically manifesting as missing or blinking geometry. When these types of artifacts occur, use Nanitestats
to determine conservative bounds for candidates and visible clusters. More specifically, look at the stats for ClustersSW and ClustersHW. The memory cost of a candidate cluster is currently 12 bytes and a visible cluster is 16 bytes.
This console variable cannot be changed at runtime and must be specified in a configuration (.ini) file.