Barry Legg did a breakdown of his UE4 environment inspired by Simon Stålenhag: working on master materials, using blueprint, Megascans, SD, and more.
Hello, my name is Barry Legg. I live in Whitstable, a coastal town in South East England, and home of both Grand Moff Tarkin and Dracula.
My background was in graphic design, and I was drawn more and more towards 3D over time. I intended just to use it as an extra element for motion graphics projects – I was using Bryce to generate landscapes for aerial shots – and it was from there that my interest in creating fully-formed, immersive CG environments really grew. Game environments were the next logical step.
I’m fairly late in discovering Simon Stålenhag. The appeal of his work to environment artists is obvious, but I only came across ‘Tales from the Loop’ – the book this image is taken from – quite recently.
I like the casual way that he blends the unfamiliar into the mundane; so the idea of how the abnormal came to be routine is more unsettling than anything contained in the images. I’m always drawn to science fiction that’s built on those undertones of paranoia, or anxiety.
Most of the images in the book are quite clean in terms of composition – lots of sparsely populated, open spaces. This stood out for how busy it was by comparison. It already had a lot there for me to begin working with, I could get a sense of how the environment outside the frame would be laid out and what it might contain. I also had some ideas for how to compose the props in the scene to do a little story-telling:
Because of how the car and the giant structure almost looked as though they were involved in a stand-off, I wanted to give the impression that this was a place where confrontations happened regularly:
Modeling Large Meshes & Working on Master Materials
The key to getting these very large hero props to look good enough for the player to walk right up to (or into, in this case) was to start with a Custom Normal (or Face-Weighted Normal) workflow – so I was mostly free from the limitations and time-consuming tasks of the baked normal workflow. The modeling process was pretty straightforward; I just had to be careful to make sure the UVs for the interiors of the meshes could be laid out perfectly flat and straight so I could handle the interior structural detailing with POM material functions.
After modeling, I spent time setting up a couple of master materials that could handle most of the large metal meshes around the scene with as little additional input as possible. For the largest props, I settled on a graph that would take a single channel-packed mask map made in Substance Designer and use it to define areas for the functions in the master material to appear. The functions that were laid down in the final material included:
- two basic 1k Substances (painted metal and rust),
- sand textures (already present in the layered landscape material),
- two solid colors, used as either dirt or patches of paint.
As an experiment, the mask channel for adding the rust layer was used to generate a normal map using UE4’s built-in NormalFromHeightmap function to create subtle indentations in rusted areas. (This function is pretty expensive, so it may actually be more efficient to use a separate normal map generated in Designer along with the mask map).
The tiling maps are contained in material functions identical to this – no instructions for adjusting brightness, roughness etc. are necessary because parameter tweaks are handled in the Substance Graph Instance.
The Distance Fade function is used to prevent visible texture repetition on huge meshes that are visible over long distances.
Above is the master material used to create material instances for the large metal assets. Aside from generating the normal map for the pitted rust, everything is pretty straightforward. The F_TwoHeightlerp_ma function is just a version of the built-in HeightLerpWithTwoHeightMaps function that I tweaked to work on all Material Attributes in one function.
The structural detailing of the large mesh interiors was handled by the built-in ParallaxOcculsionMapping function, the maps needed for this were generated in Substance Designer again. To keep the master material from getting too confusing, this part of the graph was saved into a separate material function:
Because of how the UVs are laid out on the interiors of the main props, I couldn’t use the same bitmap mask function to add other layers. So, in addition to the height and normal maps necessary for the POM function – I made an AO map and a mask map that could be used to blend the tiling materials in these areas.
Here’s the master material used for generating material instances that use POM – apart from the added POM layer it uses the same material functions as the main material.
This time the sand is added using inputs from the POM maps before the built-in WorldAlignedBlend function is used to cut it off when it gets to a certain height.
I initially started looking into using the Blueprint editor just to help out with laying down the roads, and I eventually came across the Modular Road Tool by Coqui Games which is just an incredible resource to give away for free – it has a tonne of features that went way beyond my needs.
After setting it to use my own meshes and materials for the roads and curbs, along with a few other tweaks, I’d finished the road incredibly quickly – so I started looking for other tasks around the scene that could be solved with simple construction scripts made in the Blueprint editor; making the pipework wrapped around the building was the obvious next step. I used it again with the perimeter fence and overhead power-lines; manually placing and setting up cable actors in UE4 is really tedious so anything that would save me having to do that over and over again was definitely worth spending time on. Toward the end of the project it came in really handy again for laying down the strips of crack-sealant you can see stretched out all over the road:
This was the first time I’d tried to exploit Mixer’s capabilities for adding decals into landscape materials to add another layer of detail. After I’d made two main landscape materials that cover the majority of the world, I made alternate versions of them that were loaded with decals of metal trash and other debris. Most of the decals are from Megascans but in a couple of cases, I managed to trick Mixer into loading in some decals I’d made myself, like the coiled wire. The alternate versions were then manually painted into areas where it seemed logical that there would be layers of junk and debris embedded into the sand.
Utilizing Substance Designer
SD was most useful in generating the textures for the POM functions used on the main mesh interiors. Height, normal, AO and a rust mask were all that was needed. I based the shape on a small technical detail I found elsewhere in Stålenhag’s book:
In the past I would have made these textures by baking a high-poly mesh – now though, Substance Designer gets it done so much faster, as well as allowing me to create things like the rust mask at the same time, so really there’s no reason to use anything else. Again – the process was very simple – the basic shapes were made with shape generators and bevel filters and then tiled a couple of times with the Tile Sampler.
The rust mask was then made by running the curvature of the base shapes through a Slope Blur Grayscale and blending it with a noise generator.
I also used SD to generate the mask textures used in the main master material for the large meshes. The central, giant mesh required a mask to itself, just because it was so large – but most others were able to share a single map.
Making the mask was totally straightforward – I just used grunge maps and dirt generators like Dripping Rust and Ground Dirt. Whenever possible I tried to use tri-planar projection so it didn’t matter so much if my UV islands weren’t perfectly aligned. For meshes covered in random patches of white paint, I imported a couple of roller-paint textures I made in Photoshop and manually placed them with Transform 2D filters. To export the mask I just ran the separate parts of the graph into each channel of the RGBA Merge node, then into the output.
The base of the lighting is again – pretty simple! It just uses the default sky-sphere blueprint, a direct light for the sun, and a skylight. I spent a while getting the sky and light colors as close to the concept as I could before introducing anything else to the lighting setup – I settled on really warm sunlight contrasted with a very deep, cool color for the sky. The direct light has a little Bloom and Light Shaft Bloom enabled. I used very little indirect illumination this time as it has the effect of making static meshes feel like they’re glowing which wasn’t appropriate for this scene, so I let the skylight intensity handle most of the fill-lighting.
After the lighting base was working – the really key thing to getting the atmosphere right was down to a combination of the Exponential Height Fog and a handful of cylindrical particle emitters that were set to a very flat, wide shape. Getting the color and density of the Height Fog right was important to the overall atmosphere – it’s set to a pale pink hue which is most noticeable when facing toward the sun, and gives a kind of soft, early-morning quality to the overall lighting scheme. After that, it was a case of tweaking the Volumetric Scattering Intensity of the direct light and the skylight – by then it had mostly come together
There was just a little final finessing done in the post-process volume; subtle flares and a little more bloom on the lens, and some very minor tweaks to the color balance of the shadows and highlights to add a little more overall contrast.
I definitely confirmed the importance of seeking out and responding to feedback: a few people have now commented on the quality of the lighting, and I don’t think that would be the case if I hadn’t listened to some early feedback telling me the light, atmosphere and color balance were all wrong. In truth – I knew it was wrong before it was mentioned, but actually hearing it said out loud by someone impartial probably made me take the problem more seriously than if I just kept it on a mental to-do list and fixed it in my own time.
That… and to keep my material graphs tidy from the start.