Secrets of Relic Entertainment. Part 2.
Sorry for the long break. Let's continue digging through engines and games. :) As promised, the second Relic game under examination is the RTS Company Of Heroes. Product page: http://www.companyofheroesgame.com/ Without a doubt, it's an excellent game, but what interested me most was how different its renderer was from DoW 40K. The answer: radically different.
From Part 1 we remember well that everything in DoW was built on the FFP. It was obvious that CoH looked more technologically advanced, but there was still a very high chance that the engines were fundamentally similar.
The second terrible secret of Relic is that CoH uses a renderer that is completely different from DoW. Imagine a car manufactured in 1990 and one manufactured in 2006. Some well-known brand. (No, not VAZ. They didn't evolve. :) ) Audi or BMW will do. The older cars were also well built, and many of them still drive perfectly fine today. But the sheer number of innovations, technologies, and features available now is simply mind-blowing. The leap in Relic's engine technology is roughly comparable.
The reverse-engineering was done on: A64 X2 4200+, 2 GB RAM, GF 8800 GTX. All settings set to maximum.
There is no FFP at all. Shader Model 3.0 is used almost everywhere. The first thing worth mentioning is the extremely sophisticated lighting system. Very well designed and beautifully implemented. But let's go through everything in order.
Right at the beginning, a so-called Point Light Map is generated (Relic's own terminology). This is simply a dark texture into which all brightly lit locations on the map are rendered. On night maps, for example, these are spotlight beams and street lamps. The process is straightforward: Looking at the map from above, wherever there is a bright light source, a textured quad containing a highlight is rendered. The result is an image that vaguely resembles a satellite photograph of a city at night.
Example:

Next come two passes into two different shadow maps. The first one is used for objects close to the camera (higher detail). The second one is used for more distant geometry. Not all visible models are included. If you pay attention, you can actually see shadows appearing on distant geometry. No fancy techniques such as PSM or TSM are implemented. Naturally, the NV shadow map hack is used. I assume ATI hardware uses its own depth texture implementation. The shaders are simple, but there is one interesting detail: texkill is always used to emulate alpha testing. Why not use regular alpha testing? The answer turned out to be simple. Pixel depth is written into the color buffer. Apparently the programmers wanted to reduce shader variations and use a single shader for R32F, NV depth textures, and ATI depth textures. Personally, I think this is a questionable decision. Adding one more split (one version with texkill, another without alpha testing) would allow a double-speed Z-only pass. Both shadow textures are 2048×2048.

Water reflection pass. (If there is water visible in the frame, of course.) All objects rendered by the shaders used in the main pass (described later) are included. The only optimization applied is distance culling. If you move along the shoreline, you can clearly see objects appearing in the reflections.

Sky. A simple hemisphere rendered using fairly straightforward shaders. Interesting detail #1: The game uses Atmospheric Light Scattering. I'm not an expert in this area, but after some investigation I started suspecting that Relic uses a simplified version of the model presented by Naty Hoffman and Arcot J. Preetham at GDC 2002. (Additional documentation can be found in the ATI SDK.) I suspect it is simplified because the game has no dynamic day/night cycle, meaning most coefficients can be precomputed on the CPU. Example sky texture:

Map objects. Buildings, units — everything is rendered here. The shaders are complex. The vertex shader for static models contains 126 instructions. For skinned models: 150 instructions (hardware skinning is used). The common pixel shader contains 65 instructions. So what exactly is happening inside?
-
Interesting detail #2: The game uses Spherical Harmonics Lighting. The approach strongly resembles the method described by Tom Forsyth in the notes accompanying his GDC 2003 presentation. http://home.comcast.net/~tom_forsyth/papers/SH_GDCE_TomF.zip Blog: http://home.comcast.net/~tom_forsyth/blog.wiki.html See the January 17th post. In a nutshell, the idea is as follows: The 3–4 brightest light sources are evaluated normally (normal mapping, specular lighting, etc.). All remaining lights are converted into SH coefficients on the CPU and evaluated in the vertex shader. Roughly speaking, SH lighting can be thought of as diffuse lighting using a cubemap. Except that evaluating a cubemap in real time is considerably more expensive than evaluating seven coefficients (which is exactly how many CoH uses). Using only the first seven polynomial terms introduces a fairly significant error (nine are usually used), but apparently the developers were satisfied with the results.
-
The Atmospheric Light Scattering described above is also used. Visually, it appears as a haze that covers distant objects.
-
Two shadow maps are used. No artificial softening is applied. The developers were satisfied with the free 2×2 PCF available on NVIDIA hardware. I don't know how ATI handles it. It wouldn't be difficult to implement, but the shader workload is already quite heavy.
-
Medium-priority light sources are evaluated in the vertex shader. The most important ones are evaluated in the pixel shader with normal mapping.
-
The pixel shader uses:
Specular map

Gloss map

Ambient occlusion map

AO Detail Map (In Relic terminology: Dirt Map.)
Local Ambient Occlusion map. LAO. An absolutely wonderful texture. :) My lengthy meditation sessions over the shader code failed to produce any clear conclusions. It's obvious that different channels contain different information about the lighting of the level viewed from above. Some kind of attenuation of the base color is performed using this texture.
Channels shown separately:
R:
G:

B:

Fog of War
(computed on the CPU):

Destructible objects also have a damage map. It is applied through a mask. So yes, things are not exactly simple here. :)
Water. Fairly straightforward, actually. Reflections only. There is a texture containing a shoreline mask used to simulate foam near the water's edge. The same atmospheric light scattering is applied. Wind direction is controlled directly from the application.
Terrain. At this point, ten texture slots are already occupied, leaving no room for terrain tiles and blend masks. The solution is simple: Model and texture the terrain just like ordinary objects. The shaders used are exactly the same as those used for other scene objects. The only addition is the Point Light Map described at the beginning of the article.
Particles. A complex vertex shader calculates lighting based on a large number of input parameters. It also calculates texture coordinates because Relic implemented a rather clever texture atlas system. When a single large texture atlas (2048×2048) was no longer sufficient, but they still wanted to render everything in large batches, the programmers remembered cubemaps. Thus was born a gigantic cubemap (6 × 2048 × 2048) containing every image required for rendering effects.
Examples of two faces:


This is actually a very unusual solution. I've never seen anything quite like it before. The pixel shader uses the ever-present atmospheric light scattering plus a strange blending of cubemap samples fetched using nearest and point filtering (two samplers). Why do they do this? I couldn't figure it out. :)
At the end come the playable area boundaries and unit selection highlights. There is something unusual here as well. These are highly tessellated meshes generated on the CPU. It's difficult to describe.
Better to see it once:

Bloom. Downsample + color remap + Gaussian blur horizontally and vertically.
UI. Actually quite decent. However, after everything else it loses a lot of its impressiveness. Batching could have been done better. Text is rendered word-by-word, while minimap icons are rendered one at a time.
My overall impression of the renderer is very positive. Technologically advanced and well executed. At the standard camera angle (press Backspace), at maximum zoom-out, there are only 600–800 DIPs. About 100 of those belong to the UI. If you rotate the camera to a horizontal view, the count reaches 2000, but that's not particularly important since nobody actually plays that way. Just like in DoW, a scissor rectangle optimization is used: The screen area covered by the UI is excluded from rendering. This wasn't especially important in DoW. In CoH, with its monster shaders, it definitely matters. Naturally, none of this would work nearly as well without the outstanding art.
Mini-conclusions:
-
This time it was a good balance between art and technology that carried the day. :)
-
I still have a few minor criticisms of the engine. For example, instead of Atmospheric Light Scattering—which is only really noticeable when the camera is positioned horizontally—they could have used ordinary fog. The visual quality would not have suffered much, while performance would likely have improved due to simpler shaders. Then again, the game contains many cut-scenes... Just some random thoughts. Nothing more. I'll also mention the lack of a double-speed Z pass, as well as the UI.
-
The DoW and CoH engines are completely different from one another. I won't claim they were built by different teams, but I certainly have my suspicions. Another piece of evidence supporting this theory: CoH still contains special markers that are visible in PixWin. That made reverse-engineering a little easier. More generally, little details like that reveal a strong engineering culture.