They always say not to prematurely optimize. With everyone advising against it so much, it must be pretty fun, right?
One of the main features in this scene is the big glass habitat domes – half the course actually takes place inside one, before the action moves out onto the lunar crater. This means that the glass itself is usually going to take up a striking percentage of the screen, depending on your viewing angle and position. If the material for the glass is inefficient, that can have a big effect on performance.
One of UE4’s best tools to optimize this kind of thing is the Shader Complexity view.
From a very basic perspective – not because I’m trying to dumb it down, but because I’m a n00b who doesn’t know things – the colors in this view represent the complexity, in shader instructions, of each pixel. A pixel rendered by a 200-instruction shader takes as long to render as two pixels rendered by a 100-instruction shader (this isn’t exactly correct – processing shaders isn’t the only thing that happens in the rendering step, and rendering isn’t the only thing that happens during a frame – but still, sufficiently bad shaders will impact performance).
But fortunately, you don’t need to be familiar with the underlying math in order to make good use of the visualization. It’s very simple: red pixels bad, green pixels good.
The thing that this visualization makes immediately clear is that there’s one thing that will wreck your performance very quickly – transparency. The red parts are invariably the areas of the image where something is being rendered in front of something else.
The opaque parts of the grass here, the blades of grass that you actually see, are simple (green) to render. It’s the transparent bits that pose an issue, since the renderer must fall through to every other grass shader behind it until it can finally draw a pixel:
Similarly, the glass on the dome (seen in the first picture) is a massive issue for performance. One of the hard truths in computer graphics is that lighting and transparency do not go together well. In UE4 specifically, in order to be lit like the rest of the scene and still be transparent, the glass must be lit using “Surface ForwardShading” – which makes it very expensive compared to other materials that use the deferred renderer.
The alternative to expensive forward-shaded glass is to fake a custom glass material using a simple translucent/unlit material, and put all the detail in the emissive output.
One of the main things that makes a material look like glass is reflections – normally, a cubemap. Some UE4 games use a special actor, a SphereReflectionCapture, to make a cubemap from a specific place in the level. In my case, this ends up looking dull, so I just use a predefined cubemap containing an Earth-like sky.
Setting this up in an unlit material (which won’t receive cubemaps from SphereReflectionCaptures) is super simple: find the cubemap texture, drag it in so it’s a Texture Sample, and hook the Reflection Vector up to the UV input:
With just this one step, it’s actually looking pretty good. But there’s one issue: the smoothness of the original glass material isn’t exactly zero – it’s more like 0.1. The reflections in the cheap material are too sharp. You can blur the cubemap’s TextureSample in the material by setting its MipValueMode to MipLevel (allowing you to specify a particular mip level), and setting the Const Mip Value to 1 from -1 (In general, higher numbers are blurrier).
Looking better! There’s still one thing missing: the bright dot from the directional light in the scene. This is a bit more complicated, as the material doesn’t directly have access to the light direction (or any lighting data) – so I have to create a vector parameter and give the light’s direction to the material manually from a Blueprint.
The highlight is centered around dot(light vector, reflection vector) and is very small and bright – meaning, raise it to a high power and multiply it by a high amount. Don’t be afraid to use very large numbers here to get the effect you want!
And there we have it! A cheap material that looks almost identical to the original, but is far, far cheaper:
According to the material editor, the new shader is only 55 instructions – down from 528 instructions for the old forward-shaded glass! The Shader Complexity view seems to agree – even looking through several layers of glass only becomes a dark green.
There are still tinges of red and white in the grassy areas (and it’s worse when looking from the ground), so that will probably be the next thing I optimize!