Intro
Out of curiosity I used RenderDoc to dig a bit into Serious Sam 4. The first frame we are going to dissect is the following:
Shadow Maps
The game starts by rendering the shadow maps. Only the sun has shadows, 4 cascades are rendered to separate textures, the size goes from 2048 to 5120 depending on the settings.
Whether the terrain is rendered or not also depends on the settings.
Pre pass
The first pass on the scene has two render targets. After every opaque element of the scene has been drawn, they look like this:
On lower settings one of the buffers looks like this:
So one of them is clearly the depth buffer. I’m not sure about the other one. We will see how the various elements are drawn later.
Light pass
For each light in the scene a drawcall is made. The drawcall draws a sphere (made of 960 vertices) around the light, in the pixel the actual light calculation is performed and stored in a RGB16 HDR buffer. The only input to those two buffers are the two buffers generated in the pre pass. Normals are probably reconstructed from depth, materials attributes and normal maps have therefore no way of influencing this pass.
Final image:
Sphere for green light
Main scene pass
During this pass all of the elements from the first pass are redrawn plus transparent objects and particles. Not all of them are that interesting, so let’s just talk about the most interesting ones.
Background bridge
Instanced rendering is used to draw the various sections
Terrain
These slides go into some detail on how the terrain system works. In any case, the terrain is drawn in chunks:
A vertex buffer contains the following mesh
which the vertex shader transforms in the fhe final terrain mesh for the current chunk.
Chunk size can vary based on distance and required resolution.
Legion system
Finally, let’s dig right in to the legion system. Closer enemies and NPCs are rendered normaly in several drawcalls:
Interestingly, the gun for this NPC has 58,341 triangles, despite only covering a couple tens of pixels. Next, for far away enemies an impostor mesh is generated, containing a quad for each enemy.
Their textures are stored in an atlas that seems to contain animations frames as well as various orientations.
In just one drawcall tens of thousand of distant enemies are drawn. The process is repeated for different types of enemies.
The vertex buffer is probably uploaded from the CPU at every frame.
Sky
For the sky a cube is rendered in 6 separate drawcalls (one for each side):
The sky itself is stored in a 2D texture.
Portal
First a textured quad with alpha blending is rendered:
Then a bumpy circle mesh is rendered multiple times with different textures:
In 3 passes the portal effect is rendered:
This one does distorsion:
Particles
Particles are rendered in a single drawcall. I suppose the vertex buffers and particle simulations are done in the CPU.
Bloom
At this point, in order to create a bloom effect, the frame buffer is downcaled and upscaled multiple times. During the first upscale the dark parts of the buffer are rendered as black.
Various upscaling passes are omitted. At the end a 408×230 image is obtained.
Mixing and tone mapping
So far the image has been renderd into an HDR render target. This pass does tone mapping and mixes the result with the bloom buffer:
FXAA
Before FXAA:
After FXAA:
UI
At this point the UI is rendered on top of the LDR buffer, and we get the final frame:
Lighting
During the second pass the pixel shader calculates all of the lighting. Let’s see how it works by dissecting a different frame:
Terrain patch
To be precise we are going to look at the shader inputs for one of the terrain patches:
Some of the shader inputs are buffers or black images, but some have a much clearer purpose. This one looks like albedo:
Some kind of normal map:
One of the faces of a cubemap (used for specular reflections):
A texture that seems to contain a light map:
This is the lightmap for a different model:
Sun shadow map:
Gun
Let’s also see the shader inputs for the gun:
Cubemap face:
Normal map:
Albedo:
Not sure about this one, probably contains several material attributes in various channels:
Sun shadow map:
Smoke
The smoke is rendered as particles. They work like the ones we’ve seen before but those are lit. The shader has (among other things) those two images as input.
Conclusion
The game doesn’t make use of many compute shaders, instead many passes just render a quad to fill the entire screen. Some compute shaders are used at the very beginning for a purpose that I haven’t managed to figure out.
Overall the rendering is mainly done like in previous games of the series and has nothing special, but despite that
the overall look is pleasing to the eye.
Despite the simplicity of the rendering pipeline the game requires a pretty good PC to run properly.