Custom Render Passes

Good morning!

We were wondering if we could run through an idea we’ve had to improve performance on a very specific part of our product to see if you guys thought was viable and if it were, what would be the best way to approach it. While our target platform is relatively low-end, we’re still interested in the impact of having something like this in other platforms as well.

Currently our product has an interesting performance problem with masked and opaque particle (Niagara) emitters which we believe are caused by our depth prepass setup (set to r.EarlyZPass=3 (auto)) and the fact that we’ve also setup velocity rendering to happen as part of the prepass (r.VelocityOutputPass=0). While we generally found that outputting velocity as part of the prepass to be beneficial, the main issue we’re seeing now that we’re paying too much in terms of GPU performance to render certain particle effects twice (once for their velocity output during the RenderVelocities(opaque) pass and another one during the base pass), so we were wondering if something like what we’re about to propose would work and if it seems doable, what would be the best way of doing it code-wise.

While there are a few obvious ways where we could improve the performance of those emitters such as reducing the amount of particles and disabling motion vectors in the emitters, we don’t want to sacrifice visual quality too much so we think having a custom pass which allows rendering a (separate) base pass with both depth and velocity information while keeping our current setup might be an interesting thing to investigate. We are aware the engine already supports custom render passes and we’ve also found an example on how to create one in Engine\Plugins\Compositing\CompositeCore\Source\CompositeCore\Private\CompositeCoreSceneViewExtension.cpp as seen in the screenshot below although we’re not sure if this is the best way of doing it or not. We’ve also found the FSceneCapturePass class contains a very similar way of implementing the custom render pass.

[Image Removed]

In our case we’d probably want to execute it just before the main base pass to get the benefits from depth discards from those masked / opaque particles and we’d need a way of tagging which assets would go through this path - while it will probably need some custom work I’m sure we’d figure a way to do it.

Looking at the code in Engine\Source\Runtime\Engine\Public\Rendering\CustomRenderPass.h we’ve noticed it suggests creating a custom class that inherits from FCustomRenderPassBase to create custom behavior which we suspect will be the way to go but we thought it would be a good idea on what you think would be the best approach and if you think we’ll potentially see some improvements from the changes we’ve suggested. We are aware this might cause some issues with occlusion tests which we currently have enabled at the moment but we might require implementing this custom pass to see the full impact.

So the main idea is to have:

  • A way of tagging assets, in our way specific types of particle emitters, to make sure they’re rendered as part of our custom base pass (which I believe can be done already through primitive IDs as they are received by the custom pass info.

And then rendering wise:

  • Prepass (r.EarlyZPass=3)
  • RenderVelocities(Opaque) (excluding opaque / masked Niagara Particles)
  • [ HZB, Custom Depth, etc.. ]
  • CustomBasePass (opaque / masked Niagara particles, outputs depth and velocity) -> this is what we’d need to add
  • Base Pass (everything else)
  • […]

Please let us know if you need more info and thanks in advance!

Adrian

[Attachment Removed]

Hello,

Thank you for reaching out.

I’ve been assigned this issue, and we will be looking into the options for adding a pass as described for you.

[Attachment Removed]

Hello,

Are you not able to use a derivation of MeshPassProcessor along with SceneViewExtension to order the pass to achieve your needs here?

Example - “FSceneRenderer::VoxelizeFogVolumePrimitives(…)” from VolumetricFogVoxelization.cpp

You can also control what gets rendered by the pass by using custom lists or using the existing mesh batches stored in the view.

[Attachment Removed]

Hey Stephen, thanks for your response!

I see what you mean with that example and yes I think that has a good part of what we’ll need for this - that’s really helpful so thanks a lot!

Having had a look at that file you’ve mentioned we’re thinking we’ll probably go the route of having a custom list similar to the VolumetricMeshBatches array where we’ll selectively add elements to it as they come in through the VelocityRendering part and then skip them during the normal base pass rendering. We suspect this will only contain engine changes and the asset tagging thing shouldn’t be too difficult to make so we’re thinking about posting the results once we get it to a decent state in case anyone else needs to reference it in the future :).

Thanks!

Adrian

[Attachment Removed]

Hello,

Thank you for the reply.

If you have any further questions, please let us know.

[Attachment Removed]