Matthew Taylor has talked about the Victorian Tiles project and shared how the procedural material was created in Substance 3D Designer, detailing the process of setting up cameras, lighting, and final renders.
Hi! I'm Matthew Taylor, and I'm a 3D Generalist based in Manchester, UK. I mainly specialise in procedural PBR material creation using Substance 3D Designer but generally love all things procedural and non-destructive. I originally learnt to model in Maya through an interest in animation and video games, which led to my first proper job in 3D art working as a modeller making assets for video slot games in the gambling industry. My natural curiosity then pushed me to keep learning more about all the aspects of 3D art, and I became a generalist.
I first discovered an interest in non-destructive workflows through 3ds Max's layer stacks, then eventually discovered Substance 3D Designer and fell in love. After that, I knew I wanted to pursue a role as a material artist and got my opportunity when I was offered the role of Lead Material Artist at Poliigon. The job allowed me to work closely with some talented material artists, and mentoring them felt very rewarding, but I missed producing art myself. So, I stepped down and settled into a role as a Technical Substance Artist focusing mainly on making custom nodes to assist the team and improve workflows. I also got to produce and release lots of assets to the site and was responsible for developing a few advanced generators, capable of exporting many materials all from one file due to their array of parameters.
Being always hungry to learn new skills, though, I have since left Poliigon, and I am currently self-employed, selling a few materials and nodes on Gumroad, and doing occasional freelance work while learning procedural modelling in Houdini.
The Story of Starting with Material Art
When I first started using Substance 3D Designer, it just made sense to me. I felt completely at home. I felt so inspired by the power of it that I found myself spotting interesting materials everywhere I went and revelled in the challenge of recreating them procedurally. Around that time, there was also an explosion of fantastic material artists to learn and draw inspiration from. Artists such as Daniel Thiger, Josh Lynch, Eric Wiley, and Vincent Dérozier, to name just a few. I'd look forward to seeing their next material studies on ArtStation, and it would inspire me to keep looking for ideas for my own. Every study I did was an opportunity to push myself further and learn more about what the software could do, and I would challenge myself to find problems to solve and make custom nodes to solve them. I spent a lot of time getting familiar with the most powerful aspects of Substance 3D Designer: function graphs, the FX-map, and the Pixel Processor. All of which now feature heavily in my workflow.
The Victorian Tiles Procedural Material
The material is based on the tile floor in the hallway of my wife's parents' house. This type of tile pattern is common in the UK in buildings from the Victorian and Edwardian eras and features a border that follows the edges of the room. I've always admired it and was inspired to have a go at making it in Substance 3D Designer. The problem I wanted to solve in this case was how to approach the border so that it could be applied to any floorplan without having to create one huge material for the whole floor. I also love working with patterns and like to practice ways of parameterising them. In this case, I wanted to make it easy to control the colours.
The first step was to collect references. In this case, I was fortunate enough to have access to the real material itself, which is a big benefit because I was able to get the exact shots I needed to answer all the questions I knew I'd have later on. It's best to get a mixture of close-up and mid-to-far-range shots and to include shots of all unique parts to leave as little to the imagination as possible when it comes to making the material. It's also important to get a few low, glancing angle shots to capture some specular reflections and give yourself a good understanding of how the material interacts with light. This helps a lot when it comes to achieving a realistic Roughness/Glossiness Map, which is critical in making your material look more believable.
I also took a few measurements as it's part of my workflow to work with real-world measurements and ensure everything is accurate in scale. To do this, I make all sizes relative to a "global texture scale" value. This also allows me to change the scale of my whole material, and all detail frequencies are scaled with it, giving me a lot of control over the final texel density.
I then studied the pattern to try to decide how best to tackle recreating it and to figure out what nodes I'd need to make for it. I figured out that all the tile shapes could be put into 3 major shape categories: rectangles, right triangles, and trapezoids. So, I made 3 tile shape nodes that took as inputs a bounding box size value and the global texture scale mentioned above, to ensure all measurements are accurate and consistent. These then generated Data Maps for each uniquely sized tile, including height, edge falloff masks, opacity (each packed into the channels of a Colour Map), local centroid position, and a Data Map containing corner positions and minimum edge length. This map will be used later to create cracks and chips on the tiles' corners.
I also needed to create two emblem designs. For one of them, I used the spline nodes to create a lot of the shapes, combined with some simple circles, for the other, it made more sense to draw the shape out manually with the SVG node. In both cases, I just made the minimum required parts of the emblem and then used a Pixel Processor to mirror and copy that segment to complete the design.
I then moved on to the tile pattern itself. I decided that the best way to solve the border problem was to split the pattern into two materials: a standard repeating material for the main section and a trim sheet containing the parts needed to build the border by UV mapping the geometry to the correct part of the texture.
Aside from the differences in the two materials' layouts, I knew I wanted the surface material itself and the grout to be consistent across both and didn't want to have two graphs to manage that were identical in all except the initial tile layout. So, I split the structure up into two separate graphs, containing all the data outputs needed for mapping colours and details to the main and trim sheet tile layouts, and a graph that can take those outputs and generate a realistic-looking tile material from whichever tile data node is connected.
To create the tile patterns and their data, I used a lot of functions and Pixel Processors. I made functions that would create the three different tile shapes' local UVs and bounding box sizes, then a few extra functions that helped me to manage copying, moving, and rotating the tiles into place. I also tracked each tile's individual index, shape index, and colour index, as well as the final total tile count.
Top tip: you can effectively create more than one output for a function by using the set node to create a variable name, the sequence node to control the evaluation order, and then another sequence node outside of the function with the function's output fed into the sequence node's "in" input, and a set node referencing the desired variable fed into the "last" input. Channel packing is also very useful, and I commonly use it when creating Data Maps like this. This means you can store up to four maps in each color texture.
I did all this for the main pattern, the border edges, and the border corners. Then I made the two tile data graphs needed for generating the final material. Each graph contained the same outputs: Tiles Base Color, Emblem Colors, Tile Data 0 (UVs, bounding box sizes), Tile Data 1 (indices and rotations), Tile Data 2 (height, Edge Falloff Maps, and opacity), Centroids, Corner Data (positions, minimum edge lengths, corner count, stored as an array), Color ID, the global texture scale, and height depth in centimetres.
The Tile Surface Base Material
I then made a material graph called Tile Surface, which described the surface of the tiles. The base colour was kept grey but with some subtle hue, saturation, and lightness variations. This can then just be added/sub-blended over the tile colours. I made most of the details for the Height Map using a custom node called MT Voronoi Plus that works a lot like 3D Voronoi Fractal but can work in 2D too and has a few extra options and outputs. This came in handy for creating the "salt and pepper" look of the fine stones in the clay but also worked well for creating the little pits and holes and general surface imperfections. This material will be used later for being mapped to the tile surfaces in the main material graph.
The Tile Maker
Finally, I was ready for the fun part: making the final material from all these maps and data! I made a graph that I called Tile Maker, set up the necessary inputs and outputs, and set about recreating the material from my reference. One thing to mention is that when working on a material that is generated from inputs, the inputs don't include any information within the graph itself, so the material won't look correct and will be hard to work on. You can enable graph editing in context in the preferences and right-click an instance of the graph with its inputs setup and select "Open Reference In Context" (or Ctrl+E), but I have found that to sometimes be unreliable. Personally, I just instanced one of the tile data nodes into the Tile Maker graph, shift-dragged the wires from the inputs to the outputs of the data node, worked on my material, then swapped the wires back to the inputs (don't forget this step!).
For me, most of the material work is usually spent building the Height Map, and I make heavy use of a custom node that I created for height blending, which contains lots of options for different types of height blends and has become a big part of my workflow (I use a lot of custom nodes in my work). I chained up a bunch of them to add edge wear, surface details (from the Tile Surface subgraph), scuff marks, an edge curling effect, a subtle stone effect, and cracks.
Then it was time to use the corner data from earlier to generate the corner cracks and chips. To do this, I created a separate node that loops through the local corner positions for all tiles and gets the distance to the local UVs, which creates a cone-like shape on all the corners. These are then given random scales and depths and some fractal noise and tile surface noise are added to make it look natural. The number of them that are included is controlled with a slider, and another slider controls how many of the included chips are converted to cracks. Finally, some random gradients are added in to give the tiles random tilts, and the tile heights are done.
The grout height is generated from the tile heights. Basically, I run the pre-tilted tile heights through a histogram scan to generate a mask, use an edge detect to inflate the grout parts by a pixel, and use this mask with a distance node to spread the pre-cracks-and-chips height into the grout areas and smooth it off with some blurs. Then I add some bumpy imperfections, cracks, chips, and a rounded, recessed profile. Finally, I add in some surface details from the Tile Surface with increased intensity for a bumpier look. The tiles and grout are then max blended, and a grout mask is taken from the areas where the grout is higher than the tiles.
The rest is straightforward. The normals and ambient occlusion are generated from the final Height Map. The colours and roughness already have a good starting point. The tile colours have already been generated by the tile data nodes, and the tile surface material gives us some details to mix in and a good base for the roughness. The rest is just blending in variations from a lot of the details that were created throughout the height-building phase to both the base colour and the roughness.
One important part that had a big impact on making the Colour and Roughness Maps look more realistic was a kind of clay grunge effect that I made. This is a method I use regularly to create these kinds of grungy details that seem to respond to the surface variations. Basically, start off with a fractal noise, then run it through a Non-Uniform Directional Warp node that uses maps such as the Height Map (or maps generated from the Height Maps, like curvature) for its intensity and warp angle inputs. Then, just tweak it until it looks good. There was some extra processing I did after that, but that's the part that creates the interesting details.
Finally, I reconnect the inputs and create the final graph, which contains the two tile data nodes, a series of switches hooked up to an Output Mode parameter for switching between the main section and the trim sheet, connect all these switches to the Tile Maker node, and feed its outputs into the final graph's outputs. I then finish off by promoting any parameters I want from the tile data nodes and the Tile Maker node.
For the final renders, I quickly created a simple floorplan mesh, skirting, and walls in Houdini. I included a few doorways and a window to let some outdoor lighting into the scene. The floorplan needed to be modelled in a specific way to ensure the material could be correctly mapped to the geometry. To do this, I created a grid plane divided into exact squares that were the same size as one of the corner sections of the border, based on my earlier measurements. Later on, I just selected the faces I didn't want in the floorplan and deleted them. I then mapped all the faces along the edges and all the corners to the appropriate sections of the trim sheet, being sure to properly orient them. Then I drew a Bezier curve skirting profile, used Convert Line to extract the skirting path from the floorplan meshes boundary edge selection, and plugged them both into a Sweep to generate the skirting. The result of the Convert Line was also used to create the walls using a few PolyExtrudes and PolyBevels.
Then I imported this scene into Marmoset Toolbag 4, set up and applied the materials, and began setting up the lighting. I intended to create a mixture of warm indoor and cool outdoor lighting and to use the comparative brightness of the outdoor light to create some nice specular highlights to show off the details in the Roughness Map. For the skylight, I chose an HDRI with plenty of bright sunshine, buildings, and a few trees. A street scene, as this made sense in the context of the scene wouldn't contain any colors or lighting that wouldn't fit the scene. I placed a child light where the sun is then adjusted its diameter under the Area/Shape tab until I was happy with the softness of the shadows.
Then, I placed a few indoor lights to brighten up the dark areas. One spotlight at the opposite end of the hallway to the front door, and one omni light that I imagined was a lamp sat on a small table in the corner. Again, I set their diameters to get the desired shadow softness, then enabled the Temperature tick box under the Light tab and adjusted the °Kelvin to values in the warm range, as this gives the impression of them being a manmade light source. I used 3000° (orangey) for the lamp light and 5125° (pale yellowish) for the spotlight.
I created a few cameras and placed them around the scene, looking for shots that nicely showed off the material properties, as well as illustrating the different parts of the border pattern. Low-angle shots with a bright light source worked best for highlighting the specular details. During this process, I was continually tweaking the light values and camera settings, trying to find the right balance. I opted for ACES tone mapping and tweaked the settings until I got the look I wanted. The specific settings were different for each camera, but I generally start by finding the right exposure, then adjusting dark and light tones to create a good amount of contrast and clarity of details, and then adjusting the mid-tones last. Any adjustments that increase contrast also tend to increase saturation, so I slightly reduced that too to compensate.
The final touches for the camera settings were to add some subtle sharpening. This can help bring out some of the finer details, but it's best not to go crazy with it. Less is more. Other things that can add to the realism are depth of field and film grain. For the grain, I chose film mode and left it at its default. I used Ray Traced for the depth of field method and used the focus tool (next to the Focus Distance slider) to pick the area of interest that I most wanted to be in focus. Then I adjusted the focal length and slider from side to side until I liked the result. The key here is to create enough of a sense of depth without over-blurring and losing too many of the details you worked so hard to create. It's a very nice effect, so it's easy to get carried away. However, remember that it should enhance your work, not obscure it.
For rendering, I used ray tracing, enabled Advanced Light Sampling, and cranked the number of bounces up to seven to spread that outdoor light as far into the scene as possible. There were no transmissive materials in the scene, so I set Transmission to 0. I was getting a few fireflies, so I reduced both the direct and indirect radiance clamp values a bit and increased Rays Per Pixel to 2. I output in 4K resolution with 1024 samples. The higher samples increased the render time a fair amount, but I thought it was worth it for the extra quality. And that's it!
Final Words And Pieces of Advice
To anyone starting out learning Substance 3D Designer, my advice is to have fun with it! It can be a very enjoyable process full of interesting and fun challenges, and if you enjoy it, that tends to come through in the final material. Keep practicing and experimenting, and don't be disheartened if something you try doesn't work out because it's all part of the learning process.
Look more closely at the world around you because we're surrounded by materials, and you'll be surprised how much inspiration you can draw from even the most mundane things. Be ready to whip out your camera or phone and take pictures because you never know if those tiles in the toilets at your local pub may be your next work of art! (Bad example. Please don't go around taking photos in public toilets on my advice!)
Follow the work of others. Learn from them, let them inspire you, but don't try to emulate them completely. Your process should be your own, and there's no substitute for experimentation and learning from your own mistakes. The fact that you're reading this article shows you have a hunger to learn from others, and that will serve you well. I know that my process won't be for everyone, but it's mine and I love it!
I'm grateful to have been given this opportunity to share my workflow with you all, and I hope that someone out there has learned something useful from it. Thanks, 80 Level!
Matthew Taylor, 3D Generalist
Interview conducted by Theodore McKenzie
You may find these articles interesting