Former Crytek engineer and recent id Software rendering programmer told Digital Foundry how DOOM runs at 60 FPS with such great visuals.
The answers are provided by Tiago Sousa – Lead Rendering Programmer at iD Software. Tiago is a well known rendering magician, having worked almost all his professional life at Crytek, working on Cryengine. He also worked at True Dimensions Entertainment – his own company – back in 1999, where he developed his own game engine.
From the start, one of our goals for the idTech 6 renderer was to have a performant and as much unified design as possible, to allow lighting, shadowing and details to work seamlessly across different surfaces types; while keeping in mind scalability and things like consoles, MSAA/good image quality and MGPU [multi-GPU] scalability.
The current renderer is a hybrid forward and deferred renderer. With such a design we try and get the best from both worlds: the simplicity of a forward renderer and the flexibility of deferred to be able to approximate certain techniques efficiently. Another goal from the start was to improve iteration times for the art team, and things like disk space consumption. We wanted to move away from the stamping approach from idTech5 – essentially how detail was applied to textures. In the past, it relied on pre-baking texture results into mega-texture and so on – on this iteration we’ve translated this process into a real-time GPU approach, with no draw calls added.
As for parameterising all the input data for feeding the GPU, “Clustered Deferred and Forward Shading” from Ola Olson et al and its derivative “Practical Clustered Shading” from Emil Person caught my eye early on during the research phase due to its relative simplicity and elegance, so we expanded from that research. All volume data required for shading the world is essentially fed via a camera frustum shaped voxel structure, where all such volumes are registered. It allows for a fairly generous amount of lights, image-based light volumes, decals, and so on.
One of our big goals was to transition idTech 6 into a physically plausible rendering model. This started with transitioning the entire team from an LDR/linear agnostic rendering into high dynamic range rendering and linear correct rendering, then after this step we introduced the team to physically-based shading.
This was a fairly big adjustment, particularly for the art team, as they had to get used to things like tone-mapping, image exposure, linear correctness, physically plausible texture parameterisation, asset creation in a consistent manner, and so on. Even for the engineering team this was a big transition; getting everyone up and running understanding all of the relevant nuances – eg transitioning all inputs to linear correct, HDR lightmap, no magic multipliers and such – all required for consistent and high quality rendering.
Our lighting approach is a mix of real-time approximations and pre-computed components. For the indirect lighting, idTech 6 uses pre-baked indirect lighting for static geometry, mixed with an irradiance volumes approximation for dynamics. For indirect specular bounce we used an image based lighting approach.
The real-time components use a state-of-the-art analytical lighting model for the direct lighting together with shading anti-aliasing, mixed with real-time directional occlusion and reflections approximation. Skin sub-surface scattering is actually approximated via texture lookups and baked translucency data. It’s fairly efficient – particularly compared to the usual costly screen-space approximations.
Our biggest achievement here is how well it performs and its consistency across different surface types, though we’re always looking for way to improve even further.
I like to keep things simple. Usually I tackle things from a minimalistic – both data and code – and algorithmically perspective, while taking into account target hardware and a grain of futurology. Eg does it make sense to process all this amount of data, or can we just process a sub-set? Is this the minimal data-set? If the solution is a bit on the rocket science/insane side, what can we do to make it as simple as possible? How would such run well on the slower platforms and how well would it scale? And so on. And of course the usual profile guided micro-optimisations.
Screenshots are taken from the PS4 version of DOOM (2016).
Source: eurogamer.net