Mesh Draw Commands

Concept of Multi-passes

How we render the cube, in different render passes.

As a complex deferred rendering system, unreal engine not render mesh in one draw call. Instead, it contains many passes.

image

If you are not familiar with this concept, please check this image from https://unrealcommunity.wiki/unreal-schematics-2d6859

For example, our cube need to be rendered in both early Z pass for scene depth, and in base pass for GBuffer.

image

In other words, please imagine a table like this:

Early Z Pass
GBuffer Pass
Shadow Pass
Mesh 0
Mesh Batch 0
Draw Call 0
Draw Call 1
Draw Call 2
Mesh 0
Mesh Batch 1
Draw Call 3
Draw Call 4
Draw Call 5
  • Why do we need to divide the Mesh into two Batches: Mesh Batch 0 and Mesh Batch 1?

Because they have different materials, the shaders used for rendering such as GBufferPass may also be different.

  • Why do we need to generate separate Draw Calls for each Pass for Mesh Batch 0?

Because for the same Mesh, we have completely different drawing methods in different Passes:

  1. For the Early Z Pass, we only need to output depth.
  2. For the GBuffer Pass, we need to output GBuffer data. Therefore, the bound Render Target must be switched.
  3. For the Shadow Pass, our projection matrix will be completely different from 1 and 2.

Mesh Draw Command and Mesh Pass Processor

This means that even if we only have a single FMeshBatch, we need to generate more than one draw call. We must save the information related to each draw call somewhere. This is what we call a FMeshDrawCommand. And we need someone to take the responsibility to generate FMeshDrawCommand for each different pass, we call that one FMeshPassProcessor .

If you want to know more, here is the official document.

image

So our story becomes:

  • The render thread takes the rendering data, including both the runtime data (render proxies from components) and the common data (render data from assets), and uses it to render the image.
    • For each FStaticMeshSceneProxy:
      • Retrieve many FMeshBatch objects.
      • For each FMeshBatch:
        • Build mesh draw commands for each pass.
    • For each pass, merge all the draw commands that belong to this pass.
    • For each pass:
      • Execute the related FMeshDrawCommand list.
image

For our cube, we have 2 FMeshDrawCommand, one for Depth Prepass, anther one for Base Pass.

Question for the Next Step

Now we have already split the rendering of a Cube into fine enough granularity so that it can be completed in one Draw Call.

The next question is, how do we map the information of the MeshDrawCommand to the rendering API requests?

  • How to correctly set up the Shader for drawing?
  • How to set the Material-related parameters to the rendering pipeline?

This leads us to the next section: RHI layer.