Why This Material?
I have recently been working on various tools, such as edge sculpting nodes. I also created some grunge maps that could be used for rock surfaces and wrapped these into a utility node so that I could reuse them in the future as a starting point. Once I got these nodes set up, I wanted to put them to the test, which is why I chose to make this material and try to achieve all of the edge damage and surfacing with these nodes.
I took some inspiration from the final material from some of these pieces; they had some nice realistic surfacing and wear to them which I wanted to push my utility tools to be able to achieve, to get a complex heightmap with just a handful of nodes. I also really like the lighting and presentation of these materials.
Stan Brown: https://www.artstation.com/artwork/vJgrVA
Masking The Edges
Creating the JT_EdgeSculpt Utility Node
First, I wanted to create an edge sculpting node that could be used on any future projects. The goal is to be able to input a mask and then add edgewear to it, with controls for edgewear distance, rotation options, noise controls, and polish those shapes with some chiseling and layering effects.
Masking the edges
This node inputs an edge detect and runs a few flood fills on it, not too many to keep it performant. Then it uses flood fill to gradient and blends multiple of these to get some interesting shape intersections when combined with max lighten and min darken.
Then using the histogram scan, I’m able to control how close the mask is to the edges of the surface. I also run a flood fill to random grayscale and histogram scan it to be able to mask this edgewear effect to only be on some of the bricks.
I exposed the minimum parameters needed to keep it a simple tool to use and to be more generic, to work on both realistic and stylized materials.
I exposed the angle rotation and rotation random of the flood fills to have complete control. This way, if in the future, I used it for something like roof tiles and only wanted it to affect the bottom of the tiles, then I have the control needed for that.
Shape breakup, Layering, and Chiselling
Creating the JT_EdgeSculpt Utility Node
I’m using a slope blur with a low-res grunge map and blending that in to add some shape breakup to the edgewear mask. I’m also adding a Crystal 1 noise on top to add more variation. Both of these are blended using a min darken, and I have the value exposed to the same ‘Shape Breakup’ parameter to easily control both of these at once.
For the layering effect, I’m using the quantized grayscale node. I exposed the steps and slope values to have control of this later. I then slope blur this by a clouds 2 to provide very frequent noise which I layer in a subtle amount. Finally, I use a combination of noises and slope blurs to get more variation and directionality. I want this edgewear node to work with both stylized and realistic work, so anything which adds noise should be exposed to be controlled later in the utility node and should be controlled from a couple of sliders.
Creating the JT_Edgewear Node
The previous JT_EdgeSculpt node I made works great when inputting edge-detected shapes since it relies on flood fills. So I also want a node to be able to create chips and edgewear on grayscale surfaces. This should be able to be combined with the JT_EdgeSculpt node. For this edgewear node, I used the Triangle Grid Grayscale node and warped it with a Crystal 1 to get some sharp varied triangular shapes. I’m then blending some noise in to add some variation.
The heightmap input is then sloped and blurred by this noise. I did this a few times and used different values for the tiling amount in the Triangle Grid Grayscale and Crystals 1 to get different levels of frequency. I combined each of these and masked some of it out by a Perlin noise so that some areas have more or less rest with different levels of frequency. I exposed very few values to have simple controls and make it an easy node to integrate into any graph and have lots of reusabilities.
I wanted to create some grunge maps and noises which I could reuse later for several things.
These could be used as a starting point to create other noises for materials such as dirt grounds, concrete, and plaster. I blended some noises to create a rocky surface, a cracked rocky surface and a crumbly rock surface.
All 3 of these plug into the output of this subgraph so I can reference them later in the main graph. For these, I focused on the large and medium shapes.
I’m not giving it too much specific micro detail as I can add this in later in the main graph and keep these more as a starting point, similar to how you’d use the existing noises and grunge in Designer.
Creating The Stone Wall Heightmap
Creating The Pattern
I started by creating the pattern for my brick; in this case, I used the tile generator as it’s lightweight and has some controls for random offsets and interstice which you don’t get access to in nodes like the tile sampler.
I warped this shape so it’s not too uniform and beveled it to create a softer shape which is one of the things which sell the material. I found myself tweaking this value and making it much softer here at the end of creating this material to emphasize a crumbly look.
Using The Utility Nodes
For the edge sculpting, I purely used the JT_EdgeSculpt and JT_Edgewear nodes I showed previously.
This worked great and proves how powerful this node is when you layer a few of them together. I used the Surfacing nodes I showed previously to blend the surface detail.
I used the directional warp and plugged in my flood fill to a random grayscale mask to break up the surface detail per brick. Whenever I’m working on materials with clear separate shapes like a brick wall, I always directional warp any grunge and noises I blend in.
You can also use the random grayscale mask as the mask when blending if you want the surface’s normal intensity to vary per brick.
Creating Areas of Rest
When you push a grayscale mask too far, it will ‘blow out’ or ‘clip’ the values when they hit 100% black or white. In this case, I did this purposely here to create some areas of rest on some of the bricks. I added noise on top which made some of the image hit pure white and caused clipping, which gave me some more planar bricks.
I then blended some of my surfacing details back on with a low intensity so that it was not completely flat.
This helped to create some areas of rest that are very different from the rest, which added a lot of variation.
I also blended brick height and angle variation using the flood fill to random grayscale and flood fill to gradient nodes, which helps the surface read as having more depth and will later make the grout blend more interesting.
I blended the crumbled rock noise I showed previously, which helps sell the ‘feel’ of the surface. I always think the most successful materials I see are ones where you can imagine what the surface would feel like if you were to touch it.
I then added some subtle noise on top for the micro details; this will help later when working with gradient maps to add more detail to the base color.
Once the brick was ready, I wanted to add some grout. I created this using various noises and a shape splatter to create interesting height variation. I added the brick edge detect mask on top and blurred it to make it stick out further between the gaps of the bricks.
You can also use a non-uniform blur to make the grout droop down, creating the look of it being affected by gravity and adding directionality if desired.
In this case, I felt it was not needed, but I’ve used it on some of my other materials, such as the Wood Lathe material in my portfolio.
Finally, I used a height blend to blend the grout with the bricks. This node is great as it provides you with a mask you can use to separate the grout and bricks’ color and roughness later.
Creating The Base Colour
Color Variation Per Brick
For the base color, I usually set some main average value for the surface to start from. In this case, the whole wall can be set to one color. Then I blend on some grayscale values for variance.
In some cases, you may want to blend more variance in hue and saturation as well by color-picking from some references using a gradient map.
Then I blend some warmer tones and some darker tones onto different bricks to add more variation.
The dirt node I’m using here is the same as the built-in one. I just removed some parameters that I don’t use to simplify the node to a couple of sliders.
I’m planning to try and add extra options for overlaying grunge into this node in the future.
Next, I added some subtle curvature highlights. I typically do this for most of my materials. It’s important to keep this value super low for realistic work, or it will create a CG look. It’s not technically accurate to use it; however, a tiny amount can help your materials, especially when in shadow, as it can emphasize the shapes.
I usually add this with a value as low as 0.1 or even lower, and I add the existing color to itself, which makes the effect more subtle than blending on white, for example.
The curvature node I’m using here is a utility node I made. It blends between the Curvature and Curvature Sobel nodes, runs a histogram scan to clamp it to a mask, and then blurs it slightly.
I found myself doing this frequently in my materials, so I made this node to be able to keep it compact and have a few sliders, rather than adding those nodes to all of my materials each time.
I blended in the color for the grout, along with a few layers of grunge which I directional warped so it would vary per brick and not be overlaid on.
For the roughness, I simply used a grayscale conversion node on the base color, inverted it, and then blended on top of a few of the masks, such as setting the grout to be rougher.
I didn’t want to add too much information into the roughness as it’s a very rough and noisy surface, so just making sure there’s some variation in there based on the color and that there’s contrast between the grout and bricks is all I needed.
Default Graph Scale
The default graph scale is something I would recommend adding to all of your graphs. You can add an ‘Input Value’ or ‘Value Processor’ plug that into an output and set it to ‘heightScale.’ This will mean that whenever you reopen the graph, it will use this as the scale for the height map.
If you don’t do this, then every time you open the graph, you will need to change the height scale manually, which can become tedious, especially if you’re jumping back and forth between subgraphs in more complex material.
Normal Map Strength
I typically use a value between 5 and 25 for the strength of most of my materials that have a large height variance like this one, but there may be times you need to go outside of that.
Increasing this will make your normals read better. There are big changes in height with this type of material, as well as subtle details, so you’ll need a bigger range for this type of material.
Tweaking and Exporting
Custom Node – JT_Exporter
For all my materials, I use this JT_Exporter node I created, which just allows me to plug in all of my outputs and have the option to disable or enable them. When working on the roughness or height, for example, I can turn off the base color and vice versa to help me focus on specific maps.
I have the option to blur the height or normal as well; typically, I blur my heightmap by around 0.4, which helps to reduce stretching on materials that are using large height values like this one. This node then packs my textures which I use for bringing into Marmoset or Unreal so that I have fewer textures to work with.
This is great for personal work, but it isn’t set up to be the most efficient texture packing for a game. This node also exports the individual textures so that I can take them into Photoshop for showing a breakdown of the maps.
I was happy with the final result. As always, a while after creating my work, I tend to see all of the issues with it, but you have to keep moving forward onto the next piece in order to improve, and next time I can avoid the same issues.
With this piece, I wanted to get some dramatic lighting and a very chunky sculpted feel to the bricks, which turned out to be some of my favorite things about the end result.
I also wanted to prove out the custom utility nodes I’d been working on, which I was able to use to create the majority of the height map, so I’d say it was a pretty successful project.
I hope you found this article helpful!