Can not get FMeshBatch of Nanite StaticMesh for FMeshPassProcessor

This question was created in reference to: [Crash when switching to Wireframe (F1) with [Content removed]

We are using UE5.6.1, and we forward integrated CL46444386, in order to solve issues with Nanite meshes, bRenderInMainPass and custom depth.

In our project, we rely on a Scene View Extension to add a mesh drawing pass, in PostRenderBasePassDeferred_RenderThread.

We have an array of FPrimitiveSceneProxy pointers for the frame, that we want to render. Some of these are Nanite-enabled, and they all have bRenderInMainPass to false (= we only want them to be drawn through our custom FMeshPassProcessor in the SVE, not normal BasePass).

We use the “AddSimpleMeshPass” function to setup the rendering pass :

AddSimpleMeshPass(GraphBuilder, PassParameters, InView.Family->Scene->GetRenderScene(), InView, nullptr, RDG_EVENT_NAME("MyCustomPass %dx%d - %u prims", RTSize.X, RTSize.Y,  RegisteredPassPrimitiveProxies.Num()), static_cast<const FViewInfo&>(View).ViewRect,
             [&InView, this, &RegisteredPassPrimitiveProxies](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
    {
       FMyMeshPassProcessor Processor(InView.Family->Scene->GetRenderScene(), &InView, DynamicMeshPassContext);
       
       for (const FPrimitiveSceneProxy *const Primitive : RegisteredPassPrimitiveProxies)
       {
          if (!Primitive)
          {
             continue;
          }
          

          TArray<FMeshBatch> MeshElements;
          Primitive->GetMeshDescription(0, MeshElements); // <- For Nanite meshes, MeshElements remains empty
          if (MeshElements.IsEmpty())
          {
             continue;
          }
          
          for (const FMeshBatch& Batch : MeshElements)
          {
             Processor.AddMeshBatch(Batch, ~0ull, Primitive);
          }
       }
    });

Unfortunately, even with the forward integrated CL fix, GetMeshDescription returns no FMeshBatch for Nanite meshes.

This is very inconvenient, as we heavily rely on micropolygon meshes and we don’t want to use bForceDisableNanite as a hack.

Is there anyway we could access the Nanite mesh proxy’s FMeshBatch array ?

Thanks in advance,

Tim

Steps to Reproduce
Setup a scene with Nanite meshes, with bRenderInMainPass set to false.

Create a SceneViewExtension that holds a list of the mesh proxies of those meshes.

Notice how GetMeshDescription returns an empty array for these, meaning any rendering pass will not produce any output.

Hi Tim,

I’m sorry, I’m just getting around to this. Could you please send me the custom SVE that you wrote so that I can take a closer look at why you are not getting any data back from GetMeshDescription()?

Ah, I missed that part. I’m sorry about that. I am going to be out for the next two working days, so I will take a look when I get back next week. I hope that’s okay.

Hi Tim,

I tried using the code you sent from the previous question with the custom AddSimpleMeshPass code you pasted in this ticket. Still, I am getting two compilation errors for RegisteredPassPrimitiveProxies and FMyMeshProcessor. Do you have custom implementations for these classes that are not included in the original project? Can you please send me the necessary files?

Hi Tim,

I apologize for the delay in providing an update. I have been trying to find a suitable solution to get your project to work as you intend, which has led me down a bit of a rabbit hole in understanding the difference between the Nanite and non-Nanite methods of issuing draw calls. The reason you see a difference in being able to fetch data on your primitives via GetMeshDescription when “Disallow Nanite” is checked is that this option creates an FStaticMeshSceneProxy, which has GetMeshDescription implemented. Nanite scene proxies have a separate implementation that uses a different code path to generate draw calls. This means that you will not be able to add FMeshBatch objects to your custom mesh processor if you intend to utilize Nanite, as this would require exposing a set of private Nanite interfaces that we do not plan to make public (see Nanite::IRenderer). I assume you are still interested in adding custom rendering behavior to your Nanite geometry. In that case, I would say invest some time in creating a private scene extension (SceneExtensions.h) that has access to the necessary private interfaces to set up your own custom draw calls. The code you write for this extension would be mostly self-contained, with a one-line statement needing to be added to the actual render path to hook the extension in. If you need inspiration on how to implement this, please review the Nanite materials scene extension located in NaniteMaterialSceneExtension.h.

I hope you understand now why you are having trouble obtaining the necessary data for your mesh processor to work correctly. If you have any remaining questions, please do not hesitate to reach out.

You are welcome! I will go ahead and close this ticket. If you have any further questions, please don’t hesitate to contact me again.

Hello,

This is the same code as what I’ve sent in this question : [Content removed]

Thanks for having a look !

Hello, sorry for the delay !

I tried re-downloading and using the original project, everything compiles and works. The code snippet I provided above is just a part of that already existing code project, no need to add it !

We just forward integrated CL46444386 in our 5.6.1 engine so that Nanite meshes can use bRenderInMainPass. We typically use it to disallow meshes to be rendered in the main pass when they are rendered in our custom pass, although that is not mandatory for the repro.

You can just use the original project :

  • [Image Removed]Uncheck “Disallow Nanite” on the BP_TestMeshPass
  • Start a PIE
  • Put a breakpoint in your IDE TransparencySceneViewExtension.cpp line 157
Primitive->GetMeshDescription(0, MeshElements);
if (MeshElements.IsEmpty()) // <- BREAKPOINT HERE

Notice how the Nanite mesh doesn’t have any FMeshBatch element.

If you re-check “Disallow Nanite” on the Static Mesh Component (or use a non-Nanite mesh) : the code will have FMeshBatch instances in the array.

Hope that helps !

Hello,

Thanks for the detailed answer, I feel like I have a better grasp on the different code paths between Nanite and non-Nanite now !

I’ll sure have a look at NaniteMaterialSceneExtension.h to see if I can apply this to our own needs !

Thanks again for this detailed investigation !

Have a great day,

Tim