Description

When using the Niagara Mesh Renderer with multiple mesh variants selected via MeshIndex, the number of TLAS instances allocated is NumParticles × NumMeshVariants and enabling the Path Tracer can cause a 24-bit InstanceId overflow:

Ensure condition failed: InstanceDesc.InstanceId <= 0xFFFFFF
[File: RayTracingInstanceBufferUtil.cpp] [Line: 316]
InstanceId must fit in 24 bits.

Root Cause

GetDynamicRayTracingInstances() in NiagaraRendererMeshes.cpp (line ~1660) force-disables sort/cull for the RT path:

ParticleMeshRenderData.bNeedsSort = false;
ParticleMeshRenderData.bNeedsCull = false;
ParticleMeshRenderData.bSortCullOnGpu = false;

This causes PerformSortAndCull() to return the total particle count for every mesh variant,. Each mesh variant creates an FRayTracingInstance with NumTransforms set to all particles. The total TLAS instances is NumParticles × NumMeshVariants. The raster path handles this correctly via SortAndCullIndices / FNiagaraSortCullHelper::IsVisibile() which filters by MeshIndex.

The InstanceId is set to InstanceSceneDataOffset + TransformIndex with bIncrementUserDataPerInstance = true (in PrimitiveSceneInfo.cpp:SetupCachedRayTracingInstance), which can exhausts the 24-bit DXR InstanceId space.

Additional Notes

  • Path Tracer disables RT instance culling (RayTracingInstanceCulling.cpp:71), so all ghost instances are included in the TLAS.
  • Temporal samples do NOT multiply the instance buffer — the TLAS is built once per frame.
  • CalculateMeshUsed() already scans particles to determine which meshes are active, but only produces a boolean per variant, not a count. It also only works for CPU sims.

Potential Fix

Re-enable MeshIndex culling for the RT path. For CPU sims, the existing FNiagaraSortCullHelper already filters by MeshIndex — remove the force-disable in the RT path and call InitializeSortInfo before PerformSortAndCull. For GPU sims, a lightweight count pass or one-frame-latent readback of per-variant counts would be needed since particle data is not CPU-accessible.

Affected Code

  • Engine/Plugins/FX/Niagara/Source/Niagara/Private/NiagaraRendererMeshes.cppGetDynamicRayTracingInstances()
Steps to Reproduce
  1. Open the attached project
  2. Open the NewNiagaraSystem asset and disable the Niagara preview so it doesn’t effect stat SceneRendering
  3. Enable stat SceneRendering
  4. Note that there are around 9000 RT instances
  5. In the NewNiagaraSystme asset, change the MeshRenderer to the one that only has one mesh and disable Set Particles MeshIndex (see attached screenshots)
  6. Save and compile the particle system
  7. Note that there are only 900 RT instances now.

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-381970 in the post.

0
Login to Vote

Unresolved
CreatedMay 28, 2026
UpdatedJun 3, 2026
View Jira Issue