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.
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.
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:
- For the Early Z Pass, we only need to output depth.
- For the GBuffer Pass, we need to output GBuffer data. Therefore, the bound Render Target must be switched.
- 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.
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.
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.