Ishan Verma shared an enormous and in-depth breakdown of a new material inspired by Piccolomini Library and made in Substance Designer and Unreal Engine 5.
My name is Ishan Verma and I work as a 3D Material Artist at Ubisoft. In this article, I will explain how to authorize fully parametric high-quality floor tile textures using Substance Designer as well as the breakdown of blend material and showcasing it in Unreal Engine 5.
It will be a comprehensive walkthrough where I will cover points like Reference search, Reference breakdown, Creation strategies, Height building, Material creation, and Rendering in Unreal Engine 5.
The main idea following this study was to explore non-destructible parametric workflows and to create something new out of them. So, I started exploring reference images and came across a place called Piccolomini Library and the floor there caught my eye as it was way expressive, so I decided to recreate it in Substance Designer!
Art of Reference Collection
Any project starts with following up on a mood board or a collection of references. Without such a mood board sometimes an artist gets off from what is meant to be achieved. Below are some points mentioned which an individual can concern and follow up while starting any texture creation project.
Things to do:
- Do a small research and collect various images of a particular topic, this reference collection should contain all kinds of images from close-ups to distant shots.
- Collect and divide images into three categories which are Macro details, Medium Details, Micro Details, and touch-ups.
- Organize it step-wise and use the PureRef application to assemble all reference data.
- Try to collect high quality for better visuals.
Things to avoid:
- Avoid references that are too blurry or noisy.
- Avoid images with colorful lighting scenarios
- Avoid images that are not fully related to the type of texture going to be authorized.
- Organize references in a non-distracting manner to avoid confusion.
Reference breakdown contains a diverse image collection of features that are planned to be implemented in the material. Reference breakdown is usually important to mark out particular parameters an individual wants to put in specific places. Here I’m giving a brief example of how I broke down the reference for myself.
- Tile Base: This part contains the actual reference we are focusing on. Macro to Micro distance images are collected here. These pictures will help us to identify the particular surface and approach we are looking for.
- Cracks: This image collection contains crack references, all images show various crack properties which can be analyzed and implemented in the engine.
- Chipping: These reference images contain the kind of chipping damage we can have on tiles, various chipping references will be helpful in creating an aging look and feel.
- Tile Removal: Tile removal is another feature I planned to give more damage to the material it can give more usability in particular scenarios where material could be used. So here I collected references of tiles with diverse kinds of tile removal to get a basic idea of how things work naturally and to be implemented in the material later on.
- Crack Debri: It is one of the major parts of the material. I wanted to go from clean tiles to extreme damage so I decided to collect various crack damage and tile debris references, which later on found to be beneficial while working on the material.
Texture Creation Strategy and Tips
In this section, I will be talking about some ideal points to keep in mind before you start working on the textures.
- Pre-plan your reference and mood board, invest a good amount of time in searching high-quality reference images.
- Planning features and parameters accordingly to make it more usable, with more features and fewer boundaries in the non-destructive workflow will give you a master graph with a vast number of variation outputs.
- As I always say, try to think like you are sculpting in ZBrush while working on a Height Map and work accordingly. Stick with the macro to micro-detail process.
- Always break down your reference into a macro to micro sections, it will always help you to remain focused on particular steps at particular times.
- Develop an eye for picking surface details from surfaces around you and even from the internet. It will help to build a visual library.
- Try to experiment with each step you want to create that will help you to find innovative ideas for creating your own height-building workflows.
- Always focus on how the textures will perform outside the Substance Designer because material art is beyond just authoring textures. We need to analyze its use like how it will it look into specific 3D environments, with a particular asset, lighting or shader, etc
So once done with the reference collection and breakdown, at the beginning I will create a template then start experimenting and building the Height Map.
Here is an example of a template for material creation:
- You can take any template to start with either Spec/Gloss or Metal/Roughness, for this project I took the Metal/Roughness PBR template.
- Set graph relative to the parent
- For the base, I’m using three outputs to build Height and those are Normal, AO, and Height.
- Base Color, Roughness, and Metallic can use 16x16 Uniform Color nodes, which can be tweaked later on.
Height Building: Diamond Shape
The first step for the Height building is to create diamond-shaped tiles, which will be the base of the material. For that, I started the flow with a Uniform Color node with white color, then used a transform 2D to rotate at 45 degrees and a levels node to tighten up the shape which will avoid mipmap issues. Then I used two 2D transforms to squeeze the shape diagonally and horizontally to make it into an actual diamond shape.
For aligning the diamond shape, I used two Splatter Circular nodes with a shape count of 6 for both diagonal and horizontal shapes to create circular patterns. Then I blended both the circular splatters using a blend node with add blend and plugged one level node to tighten up the shape.
Then I plugged the shape into a tile generator and tiled it as X=4, Y=4 and increased the shape size till the gap gets occupied by the corresponding tile and changed blend mode to max lighten.
Then I used a Flood fill & Flood fill to a random grayscale node to vanish out the gap between the tiles and used one edge detect node which will give a thin crevice from the random grayscale data. Then I used one bevel node to give a very trifling bevel depth to the pattern.
Height Building: Border Shape
For the border shape, I followed the same steps as above but here I divided the flows into three shapes. The first one is an inner diamond and the other two are outline borders which will consist of a chain pattern in between.
Height Building: Chain Pattern
Now for chain pattern creation, first I wanted to create a chain base. For that, I took a shape node with Circle as the main shape plugged it into a 2D transform to make it small, and then using a blend mode subtract it from the main circle.
Then again, I took one Uniform Color node as white, transformed and mirrored it, and blended it with the ring shape we created earlier. After that, I used another 2D transform node to make a small version of the arc. Now using 2D transform, rotated it 180 degrees and blended over. For concluding the shape I just used a slight blur and levels to make it actually a unique shape!
Once chain base shape creation is done, plug it into a tile generator with X=1, Y=14, this is how we will achieve chain shape. Then use a 2D transform node to make it slant according to the diamond shape we created earlier and two mirror nodes to make it fully into a diamond silhouette.
Height Building: Crescent Pattern
For creating the crescent pattern, I simply used one shape node with a circle shape and subtracted a smaller circle out of it using a 2D transform and blend node. Then I used a non-uniform blur grayscale node to give a slight depth to the crescent and plugged the shape into two splatter circular nodes and added both of them.
Once done with the final shape then plugged it in the main tile generator with the same parameters as the diamond tile generator so the shape equally fits on top of the main tiles.
Surface Treatment: Chipping and Masking
For surface treatment, I kept it simple. Started with a slope blur node with the main height and a blend of Clouds 1 & 2 as noise input. Then inverted it using an invert grayscale node and used a histogram scan with exposed float parameter. This parameter will help us to move from 0 to 1 value mask so we can create edge chipping procedurally. Once done with creating the chipping for the blend mask, I just took one histogram selected from Flood Fill to a random grayscale node and blended it with the chipping histogram scan. Then blended it on top of the main shape with subtraction mode!
Surface Treatment: Gradation and Warps
For adding more surface formations, I used one Flood Fill to Gradient node, with this node I created random gradients on each tile shape and blended it over top of the main Height with SoftLight Blend mode. Once done with this, I created another mask from Flood Fill to random grayscale and created the same blend as what we did for Chipping pass. Here we will create the same parameters which will help us to create random surface unevenness.
For adding surface warps, I took various noises like Clouds 1,2, Gaussian Noise, and BnW spots 2 and drove all of them with a Directional Warp with Flood Fill to random grayscale as intensity input. This method will help us to create warped noises which can later be blended over the main shape with multiple blends.
Crack Pass: Creation
For generating large cracks, I started with a Shape node and splattered it using one Splatter node with random size, rotation, and grayscale values. Then used a Distance node to maximize the distance between those splattered shapes. After that using one edge detect, it will give us a base crack shape. Then used a warp node with Gaussian noise as input to give those cracks some organic feel.
To get a small crack pass, I followed up with the same steps shown above but put the octave or I say shape tiling more to get smaller cracks consistent. After that, for masking, I used histogram select and blended it with cracks then subtracted it from the main shape.
Crack Pass: In-Crack Damage and Debris Pass
Once cracks are subtracted from the main shape, now to give more depth formations I did a Bevel node to the particular crack masks we created earlier and levelled them up to tighten the shapes. This will give a debris pass to use along with cracks.
Now to give more surface and edge details to debris pass, I did a slope blur using a blend of clouds 1 and 2, this will deform the edges and give it uneven height. After this step, blend the debris slope blur pass on main cracks using histogram select mask.
Grime Pass: Creation and Blend
For creating grime pass, I started with Clouds 2 node, increased its tiling with Safe Transform Grayscale node. Then took Clouds 1, BnW spots 3 & Gaussian Noise and blended them one by one using SoftBlend mode with 0.5 intensity each. Once done with grime creation, I blended it with the main height output using the Height Blend node.
For the tile removal pass, I just used one Histogram Select node, took input from Flood Fill to grayscale node, and exposed all three parameters to expand features of the graph. The first parameter here is for Position, which will help to tweak the position of missing tiles. The second one will be Range, this will increase the area or amount of area for removing tiles and at least we have Contrast, which will help to tweak the unnecessary masking.
Height and Normal:
For Roughness I started with a curvature smooth from the Normal node and blended it with the BnW spots-2 node. Then I took one tile generator masking the inner diamond shape and blended it twice with grunge 14. As well for each parametric iteration I created several slider masks and blended as Subtraction mode for each mask. So it will give an independent slider for all-over Roughness with the occurring damage.
As the parameters for material are changed, the same will be effected to the roughness.
For Ambient Occlusion, I started with an AO node and used a histogram select to mask out damage then blend it over the main AO. Then I wanted depth where the tile will be removed, so I created one mask for tile removal and blended it over the main blend, and plugged it in AO output.
It has the same blend setup as Roughness with particular masks from each tile sampler.
Due to fewer color values used in the material, I kept the color inputs way less. Started the process by creating mask blends from all tile samplers and blended them with an Add Blend mode. Then used the Levels node to level out any noise from the mask. Then for adding more realisticity to the mask, I warped it a bit with Grunge Map 014 and blended the main Height again on top with SoftLight mode. This mask will be used for the Blue Color pattern.
BaseColor: Primary Color Pass
For the Base Color pass, I started creating a pale white color using an edge detect from main height to a Gradient Map and tweaked the color using the HSL node. Then I took another gradient and plugged the blue mask we created earlier as input, as well as driving it to form a blue color output. Then blended it on top of the white base color we created before. By this process, we create the primary color blend pass for the material.
For the parametric blends, I started with creating masks from each feature I exposed earlier in the material for example cracks, damage, edge chipping or edge damage, etc using histogram scan/select node. Then used all masks within specified blends one by one so it can work with the main height parameter tweak.
Approaching Unreal Engine 5
As we already know Unreal Engine 5 is publicly available and came with game-changing features such as Nanite and Lumen it gave a huge leap in terms of technology. So I decided to test it out for my material project.
In this portion, I will talk about how to set up a scene for a render template, 4-way blend shader, lighting, and few more additional features. The whole step-by-step process is mentioned below.
Our first approach for this part will be creating a render template that includes importing an asset, setting environment settings, and lighting setup. Later on, we will move to the rendering and post-process.
Firstly, I created one sphere and base mesh for the scene in 3ds Max. Then imported it in engine with import settings below:
- Untick generate auto collision
- Normal Import Method: Import Normals and Tangents
- Untick Combine Meshes
- Untick Import textures and Do not create material
Environment Light Settings
- Directional Light: I placed one Directional Light in the level, with the Atmosphere Sunlight option ticked and Intensity at 5 LUX
- Sky Atmosphere Component: After Directional Light, I added a one-atmosphere component. The settings I tweaked are Atmosphere Rayleigh Exponential Distribution - 0.5 and Sky Luminance Factor - 0.5.
- SkyLight: Third step here will be adding a SkyLight and ticking the Real-Time Option on.
- Exponential Height Fog: after SkyLight, adding one Exponential Height Fog and some settings which are Fog Height Falloff - 1, Fog Scattering Color - H(220), S(0.5), V(1.0), and Directional Inscattering Color - - H(0), S(0), V(0)
Now for setting up the post process, I started with exposure values by setting up metering mode to manual and exposure compensation to 10. After that setting blooms to standard mode with intensity at 1.4.
Then I turned on Lumen in the Global Illumination menu and did the same for reflections. If you have performance issues, then below the method there’s an option called Final Gather quality, this can be turned on and tweaked using values for decreasing the precise intensity of Lumen.
And finally, in the post-process volume setting, an option called Infinite Extent can be ticked to unbound the volume box limits to the whole level.
Setting a Camera
For setting a camera, I started with placing one camera actor in front of the template scene. Then I switched the projection mode from orthographic to perspective. Field of view at 30 degrees and aspect ratio as 1.045 to make it square frame as well tick the constraint of the aspect ratio option.
4-Way Parallax Occlusion Blend Shader
For creating a 4-way blend shader, I started with importing textures in a stacked manner with proper nomenclature.
- 4 Normal Maps
- 4 ARM Maps
- 1 Height Map as Splat map (containing 4 Height Maps)
- 4 BaseColor Maps
A Splat Map is a texture that controls the blending of multiple textures (or other values) across a model.
First I created a basic material, then imported all textures into the material editor. After importing I organized all of them by type into particular frame boxes with proper namings. For the first blend, I started with dragging one Vertex Color node and created a blend of 4 textures with the help of the Lerp node like in the image shown below.
I followed the same method for blending ARM, Normal, and Base Color Maps. For ARM, I divided the blends into pairs. The first blend here is for AO, took the R channels of each ARM map then multiplied it Base Color to give fake AO depth.
After that, I created a blend from G channels to create a Roughness Lerp blend with vertex data and plugged it into the Roughness channel.
Vertex data here will help to weight paint the mesh with 4 textures modes.
Now for the parallax bump offset, I started creating a tiling setup with a UVcoord node multiplied with an exposed float 1. This tiling will be plugged into the coordinate input of the bump offset node.
After that, I created another Float 1 and exposed it as a parameter, named it as Height Ratio, and set the value as 0.012. Then I plugged this float into the Height Ratio input.
Then for the height offset, I took the height splat map and plugged the height from each RGBA channel into the height input. Once done with the BumpOffset setup, I plugged it into the UV input of all textures.
For mesh vertex painting, selecting the Vertex Paint option will open the paint box. From there I selected few parameters which can be found in the image below:
- Color View Mode: Off
- Strength: 0.5
- Falloff: 1
- Texture Weight: ARGB (4 Textures)
Once done with vertex painting, I plugged the material into the render sphere. Below you can see the final render output from the camera viewport.
For taking high-quality renders in Unreal Engine, from the viewport options dropdown menu there’s an option called High-Resolution Screenshot. It will open up a pop-up. From there we can set up a size multiplier by 1 to 4, we can go with maximum numbers depending on the high-end systems.
Throughout the process from material creation to practical use, I brainstormed a lot and yes the results were worth it. I wanted to expand my skills in terms of creating a fully parametric material in a productive manner, so I decided to give in a taste of unreal 5 to the process. I highly recommend each individual to stay on track and find ways to learn things in-depth as well as welcome all your mistakes as serendipitous because you never know if silly mistakes can give you a good workflow by chance in Substance Designer. Try to catch up with different workflows and keep experimenting unless it’s worth proceeding. Be observant and develop a good visual library, It will really help to improvise your detailed workflow.
Believe it and keep greatness coming!
Ishan Verma, 3D Material Artist
You may find these articles interesting