Creating Tarnished Metal with Ornament in Substance Designer

Stan Brown explained step-by-step how he created a Tarnished Metal material in Substance Designer: height data, grime and dirt layers, Albedo, Roughness, and more.

Introduction

Hi! My name is Stan Brown and I’m an Environment Material Artist at Grinding Gear Games in New Zealand working on Path of Exile and Path of Exile 2. Professionally, aside from PoE, while freelancing I have worked on VR and 3D Printing projects, Nornware’s Space Beast Terror Fright (my first game credits), and various projects for the outsourcing studio Dekogon.

I’m 26, and I started getting into Art and then Substance Designer at 24. I stumbled across Substance Designer when researching “how to make a game...” and quickly fell in love with texture creation. While I learned the environment art pipeline I always enjoyed texturing the most and decided to specialize in materials. This led to a year and a half of teaching myself in free time around an unrelated fulltime job, and then 5 months of full-time learning during which I travelled to Sweden - to a game dev co-living house called Spelkollektivet to bootcamp myself in art. During my time there, I took Mentorships with Josh Lynch and Chris Radsby – it was one of the best investments in my artistic development so far, they are both great guys and teachers. I returned to New Zealand and was freelancing until I had the fortunate opportunity to accept a job position at GGG. I now spend most of my days in Designer and love every minute of it.

1 of 2

Tarnished Metal Material: Idea

The tarnished metal material was a project I started to unwind after finishing my two recent concrete studies. Something loose and fun and a bit less serious. The whole thing was wrapped up over 3 evenings. I wanted to do some old brass/bronze type of material but I had nothing too solid in mind – I found the below refs that took my fancy on Pinterest and went from there.

Graph Overview

Height Creation

Base

I started by defining the 3 different sections with dividing strips. The middle strips were made using two shape nodes (square) and subtracting the smaller one from the larger so I could easily control the size and distance apart of the strips by changing the shape sizes. I then bevel them and run it through a curve node to create a dip in the middle.

This is then run through a histogram select to mask the dip inside each strip – to use as a mask for the tile sampler – set to paraboloids with the y set higher to make them oval and rotated about 40 degrees.

Some shaping with the blur and curve nodes, then blending into the strips with max lighten and using a levels to define the blend height. Lightly blurring again and running through a range node to crunch it down a bit this is then blended (max lighten) into a uniform color node to start our height chain.

The uniform blend node is set to absolute 16 bits so our height chain isn’t at 8 bit (causing stepping), and at a value of 0.5. This gives me a neutral start where I can easily subtract and add from here.

With the first strips in place, I now create the dividing strip at the top/bottom of the texture. Using a shape node to create a line, I blur and use the curve node to create some rounded forms to the strip, then safe transform to the top, mirror y axis and blend into the chain with add linear dodge at low opacity.

The ridges are created using a tile sampler (Square) with a shape line mask – and the squares are stretched by increasing the Y size in the sampler. A blur and levels to lower the white value, then moved to the centre of the strips with a safe transform and blended with a max lighten.

This next section is using the previous locations of the strips to create masks for the upper and lower sections where the patterns will be – the Split_Mask nodes at the end are a simple custom node that is half black/white to separate sections easily. We use these masks in the following sections when blending in patterns.

For the column section, I wanted something fairly basic with some flat space for rest and to show some nice reflection data. This was simply 2 tile samplers creating vertical lines, with the 2nd being masked by the first. The thin lines are subtracted with low opacity from the larger lines, lowered by the levels node, and blurred slightly. I add the result to the chain via max lighten using one of the masks set up beforehand with a slight blur to soften the blend.

At this stage, the height map looks like this: 

Let's dive into the fun patterns!

Tree creation

For the base tree (the pattern only uses one tree, recycled a lot) I made use of the awesome Igor Elovikov’s IE curve node.

All the branches were placed using separate IE_curve nodes and levels to control the max lighten blend into each other. Blurring slightly and using a standard curve node at the end to tighten it up gives nice shapes to the branches.

The leaves are based on a squashed ridged bell, using a histogram scan to get the shape, then multiplied with a gradient linear 3 and 1 to give some depth. From here, I directional warped it a little with a paraboloid to have some curve and transformed and mirrored it. After this, I blur and use a curve node to give it an outer edge inset, and blend smaller versions of itself above at lower levels to make a stack.

After 4 copies of the leaves are attached to the tree with transform 2d, I duplicate the tree and mirror it, then add in a few layers at various scales and depths using the transform 2d and a levels node to lower the white value and max lighten blend them together. I use a shape node square and the 2d transform node to subtract some parts at the edges the did not tile due to the 2d transform scaling.

The grass starts as a squashed ridged bell, grabbing the shape with a histogram scan, this is pulled down with a 2d transform and multiplied with a gradient linear 3. Using a gradient linear one and curve nodes I direction warp them to give them some flow. Transform 2d is used to scale them down and add to the trees with max lighten at different levels, this gets some of them behind the trunks/roots.

With the grass and trees placed I needed to mess them up a little before adding it to the chain. I used a mosaic grayscale with a Gaussian noise that twisted them up and gave shapes to the trunks and leaves so they appeared different from each other.

The “detail” added into the trees is simply the mosaic output slope blurred by itself at low samples ( 4 samples – 1.29 intensity on Blur mode) This gave this cool detail here:

This was then blurred and subtracted with opacity to add in some sculpty looking detail. At this point, I grab a mask of the trees with a histogram scan for later use.

The trees are blended into the main chain using a mask from the very first shape node at the start of the graph that defined the middle section. Firstly, I blur the trees and use a levels to push the white into the black / expand them. I subtract that in the main chain to leave an outline, as right after I add linear dodge the trees (from before blurring and expanding them) so they slot into the imprint. Doing this at low value keeps the trees at the back cut into the metal, while the front trees are now sticking out giving it a multi-layered look.

Swirl pattern

With the bottom two sections complete we move on to the swirl layer and detail to finish the height. The swirl was created from a tile sampler of squares, safe transform rotated 45 degrees, inverted, and warped with Gaussian noises.

Using cartesian to polar grayscale to get the swirl, I squish it with a 2d transform and move the centre of the pattern into the top section. This breaks the tiling, so it was manually placed in a way where the edges intersect, and it's not noticeable.

Using a scan to tighten the shape it’s bevelled, blurred, and adjusted with a levels, then in this instance blended via copy with a mask into the chain – by using the levels to raise the black value and lower the white before copying, it matches the expected height values for this detail – the mask is slightly blurred to ease the transition.

Detail

A small number of edge chips are added from a slope blur with a crystal 1 input (blurred). This is min darkened over the chain with a levels node to control the depth by decreasing the black value. The columns section was excluded from this blend via mask as the edge chips were meant to be small detail/break up and they showed super obviously on them.

For this kind of detail in other textures (Ie concrete) you would want to add more varied masks and more edge shaping layers but I was keeping this one pretty simple.

The bumpy beaten look came from a clouds 1 at scale 5 – blurred at different strengths and blended together (copy) with a Gaussian noise mask.

This was multiplied over the chain at low opacity with a mask that was full white in the gaps between the trees, mid-gray in the gaps in the swirl, and just above full black for the rest (using the levels node to increase the black value a bit) – this was to give the rest of the metal a very slight shift so it wasn’t perfect.

The spots are taken from the Gaussian spots 1 using a histogram scan, slope blurred with a clouds 2 to give some shape, and tightened up with a levels. These are then subtracted from the chain, which runs through an autolevels at the end.

Be wary of doing this (the autolevels at the end of your chain) as any height adjustments you make can throw off any generators that may run off it afterwards. Be sure you have finished your height adjustments before relying on the autolevel height data for various things in your albedo or roughness.

Final Height:

Grime/Dirt

Before we break into the color/roughness I’m going to go over the grime and dirt masks we will be using during their creation. These were not added to the height/normal. Depending on the material and the scale it’s not always needed and can sometimes detract from your roughness instead of adding value.

Grime/Dirt 1 is based on an AO grab from the height, inverted, and ran through a mosaic node with input from a Gaussian noise. The Gaussian noise is then multiplied over top at .5 opacity and then a grunge map (from Allegorithmics Grunge Collection 01 on Substance share) is multipled over that.

On a side note, I use grunge maps a lot and recommend that pack. Also the creation of your own grunges or other bitmap based grunges from other resources such as Megascans or Textures.com. Grunges are a great way to get a nice break-up and interesting results.

Grime/Dirt 2 creates most of the break up seen in the final texture, the base is made from a dirt node with a high dirt level. I then multiply grunge maps over to break up the dirt, however, the grunge map is vector warped first (this moves the grunges around based on a color input) – the input for this is a quantize grayscale from the final height (set low at 8) to get solid values that make up most of the shapes, and run through an edge detect. This gives me the outlines for most of the prominent features in the patterns.

The next node is one of my custom nodes which runs that through a flood fill – flood fill to random color – and then a distance node to close the gaps. I now have a color mask to vector warp the grunges by which stops the noise continue running seamlessly across hard edges and lines.

I continue to break up the dirt by subtracting grunges, a curvature, and noise created from a fractal sum base and a histogram scan. At the end, I tighten the mask slightly with a levels.

Grime/Dirt 3 is simply a dust node with a grunge multiplied over the top.

Albedo

The albedo kicks off with a uniform color node (set to 16 bit) picked from a scan albedo value. The first blend is a multiplied with an HSL input with lowered lightness and saturation at a low 0.16 value.

The mask input, (and the next mask) are based on a custom noise node I created based on multi-directional warped cloud noise and non-uniform blurs. These then have BNW spots blended with addSub at low values.

The following blend takes an awesome custom node from Linus Tegelbratt color dynamic, which is "a quick way to get some variation in your color with the ability to adjust the Hue, Saturation, and Value separately based on a single input or multiple”. Super handy – I run the previously created noise through this and blend copy at 0.5.

The next blend is a more saturated and slightly darker HSL, meant to be the area where the metal might have been more rubbed or touched. For this mask, I grab the top values by crunching my height through a highpass, and histogram scanning the top. This is because the outer points have differing white values and the highpass evens that out for me to grab a better selection. This is blended copy at 0.62.

The next blend is a desaturated HSL, copy blend 0.31, the mask is from scratches we will see in the roughness section.

From here I use two LT color nodes with crazy saturation values with grunge inputs, to get some nice red/purple/greens blended in at copy at 0.15 to get some subtle color shifts across the metal.

With the base of the metal down, we add in the grunges created from our earlier masks.

Starting with an HSL changing hue to green and using Grime/Dirt1 mask we get that greeny corrosion feel in the crevices. The next two are a dark uniform color blend utilizing a grunge covered in roughness and the spots mask from our height.

The main Grime/Dirt2 uses a fractal sum base run through a gradient map taken from dirt scan values, this is darkened with an HSL and blended with grunge, copied at 0.29 over top.

Grime/Dirt3 is used with a desaturated version of the dirt, this gives a nice dust feel in the little bumps from the height. Lastly is a small HSL desaturation tweak (0.49 on the HSL) and another copy with an LT color node using a fractal sum base, and finally a small sharpen to finish.

This albedo was a bit of an experiment to make the metal look right, when approaching an albedo I’m generally aiming for pixel level variation and recommend more variation than you see in this chain for other texture types – in more complex textures often my albedo chain can be around the same length as the height. You can see when zooming close into scan data the type of variation something has even when it appears a solid color at a distance. Tricks like fractal sum base with the LT color node or something with a similar effect, and a small sharpen can add that subtle touch to help get to that (of course you still need the variation in the main chain!).

Final Albedo:

Roughness

Roughness starts with a uniform color set to 16 bit. This gives the base level roughness control. The first blend is some subtracted directional scratches super low at 0.015 with a Perlin noise mask. Then one of our first grunges used with the albedo is subtracted at 0.04.

After this is the scratches we desaturated in our albedo – this uses a Scratches Generator node, safe transformed and tilted 45 degrees to make a slightly more tiled version, blended in with max lighten, then safe transformed again but 2x tiling this time.

I then multiply a grunge over it so it's not super constant but it's still rather strong. This could have been warped like our dirt grunges for more breakup, I decided against it in his instance but it’s probably a good idea.

Next is another grunge from our albedo section, AddSub at 0.02, followed by the 3rd albedo section gunge mask using add linear dodge also at 0.02.
After that is a broken up top values (of the height)  grabbed this time by a facing normal node, blended by height with copy 0.5, and tightened up with a histogram scan. This is broken up by some transformed grunge and subtracted at 0.05. I’m mostly experimenting here, getting some shine to the upper surfaces before the dirt layers.

Lastly, we are adding all our grime masks with Add Linear dodge blends including another grunge thrown in. The levels at the end has the black and white values pulling in slightly so nothing is full black or white which would look super unnatural.

Final Roughness:

Metallic AO Normal

The metallic took some tweaking, at first I had the grime taking away way too much of it giving a wide ranging map and far too much gray value. I ended up with a white uniform color, lightly subtracting all of the grime and dirt nodes and full subtracting the spots mask, where it has been chipped/corroded.

The AO node is quite high at 0.05, and the normal taken straight from the height at 5 strength.

And that’s the entire graph!

Production Thoughts, Tips and Render

When creating a material, after getting a base down for height and especially as you start to introduce color and roughness it’s very important to get the material into the engine. Be that the game engine it’s for, or if a portfolio piece into Marmoset or whatever you are using.

This is especially important in a production environment, as it may look great on a substance cube/sphere but terrible in-game. So iterations past a certain point should be made from the context of the engine.

My first iterations of this material were way too shiny. This kind of material while looking awesome shiny, doesn’t get that reflective in real life.

An example of a WIP vs the end result – цhile I really liked the super shiny version, I changed it to feel more grounded and matching to my refs. I also thickened some of the implausibly thin lines in the swirl pattern and removed the crosses on the lower section for some rest.

Older iteration vs end result:

Rendering metal is very dependant on the HDRI map, I used Marmoset's Grace Cathedral for the sphere render, and Museum for the vase shots.
They have about 4 – 5 supporting lights, mostly directional on the sides and a spotlight facing the front from an upper angle. I spent a bit of time changing the direction of these and brightness to make the render feel balanced and draw attention to the spots I wanted. One mistake I often see artists at the beginning of their journey make is to rush or not spend enough time in the presentation and rendering of their materials/scenes/art. A really great piece can be easily ruined by bad lighting or poor presentation, so make sure to allow time to iterate renders. Letting them sit for a day before posting can do wonders for noticing things you might not have the night before.

When asked about learning Substance Designer from scratch my advice is always to do about 8 – 10 tutorials from start to finish. This means without jumping off course and making your own stuff - also not just watching, but recreating them in your own graph.

It’s tough, to fight the urge to design your own materials straight away but it’s worth it – by the end, you will have an understanding of what the nodes are doing and how they interact, and then you can start trying out your own stuff, with a bunch of graphs to refer to! I see how new designers feel disheartened when trying their own materials too early as there just isn’t the mental node technique library to pull from and it can seem impossible.

Tutorials from Substance masters like Josh Lynch and Daniel Thiger are great, there are also some pretty sweet youtube tutorials out there now, as well as ArtStation Learning (I hear 80 Level has some breakdowns, too). You can also grab and open material graphs to study from Substance Source!

At a medium level, especially if you feel like you are plateauing, Mentoring is one of the best investments you can get in my opinion – places like the Mentor Coalition and the Dinusty Empire offer great mentorships which can help you find the path to the next level! Don’t forget to ask for feedback on places like polycount and discord too – it’s scary at first but worth it. Lastly if going for realistic materials, get some scans, and try and replicate them. Zoom in on 4k maps and see what details there really are! I learned a lot from doing that with my concrete studies.

Wrapping Up

I hope this breakdown has been helpful! Feel free to reach out if you have any questions. You can contact me and find more of my work here.

I hope everyone is staying safe out there. Thanks for reading - keep creating awesome art.

Stan Brown, Environment Material Artist

Interview conducted by Arti Sergeev

Keep reading

You may find this article interesting

Join discussion

Comments 0

    You might also like

    We need your consent

    We use cookies on this website to make your browsing experience better. By using the site you agree to our use of cookies.Learn more