Documentation

How to Create PBR Marble Textures Using Substance Designer

This tutorial for beginners shows how to create a PBR marble material using Adobe Substance 3D Designer and Poly.

📌 Textures used: Poly Marble Texture Collection, Poly Substance Texture Collection

I’m Treb Tsai, an environment artist from Los Angeles. In this tutorial for beginners, we’re going to create a PBR marble material using Adobe Substance 3D Designer and Poly. The goal of this tutorial series is to explore new ways for artists to incorporate AI tools into existing game asset creation pipelines while retaining maximum creative control over their designs. Standard procedural techniques will predominantly be used in the creation of our marble material.

The Strategy

Procedural marble patterns created in Substance Designer are essentially warped noise patterns layered on top of one another. Unless specific node formulas are used, the process primarily involves finding happy accidents by tweaking various node parameters. The resulting swirl pattern is then used as an input to drive Color Gradient maps.

For this project, we’re going to use Poly’s albedo information to create our Base Color map. The rest of the marble material, including the shape of the tiles and the trims between the tiles, will be created 100 percent procedurally. If you feel that using Poly’s raw color information takes away too much creative control, you can instead convert Poly’s data into grayscale masks, blend these masks with other Substance Designer noise patterns and warp nodes, and then manually add color by using Color Gradient maps.

Fundamentals: Flood Fill to Grayscale as a Pattern Breaker

In order to understand how we’ll be utilizing Poly’s textures in our marble material, we first need to explore some fundamental Substance Designer node “recipes.” In Substance projects, Flood Fill to Random Grayscale is commonly used as a Warp Intensity input to break up a texture pattern into individual marble tiles.

Image 1: This image demonstrates the fundamental technique of using Direction Warp to break up patterns.

Image 1: This image demonstrates the fundamental technique of using Direction Warp to break up patterns.

The basic concept is to use Flood Fill to Random Grayscale as a pattern breaker by connecting it as an Intensity input for Directional Warp. Imagine if we overlaid the marble texture made by Poly on top of our tile shapes without any processing. The texture would look continuous and “spill over” to neighboring tiles; it would look as though all neighboring tiles were cut from one large, continuous slab of marble. In reality, though, it would be more likely that neighboring tiles were made from different stones, so each tile’s pattern would end at its edges.

Image 2: These images demonstrate Directional Warp’s function as a pattern breaker.

Image 2: These images demonstrate Directional Warp’s function as a pattern breaker.

We can see in the images above how using warp nodes like Directional Warp can help break up the noise pattern on a per-tile basis so that neighboring tiles look different from one another.

Preparation: Floor Tiles for Tile Shapes

The official Adobe Substance 3D YouTube channel has a five-minute video showing how to quickly create a PBR marble material using Adobe Substance 3D Sampler. However, because Substance Sampler operates on a simplified layer stack system that uses presets to control parameters, the amount of artistic control the program gives users is limited. Even so, we can take advantage of some of the starter assets packaged with Substance Sampler and use them as training wheels inside of Substance Designer. Both programs are included with an Adobe Creative Cloud subscription.

Navigate to where Adobe Substance 3D Sampler is installed, and search for a folder called StarterAssets. On a Windows PC, the directory path is something like: C:\Program Files\Adobe\Adobe Substance 3D Sampler\resources\assets\StarterAssets. Once you’ve located this folder, search for floor_tiles.sbsar. Either copy this file to a temporary folder or keep the StarterAssets directory open.

Creating Tile Shapes, Preparing Masks, and Preparing Pattern Breakers

To make this tutorial more accessible, we’re going to use the Floor Tiles starter asset as a base for our marble tile shapes. Normally, Tile Sampler or Tile Generator would be used to create complex tile patterns, but these techniques are beyond the scope of this tutorial. For now, Floor Tiles will get us started in learning fundamental concepts.

Start a new project in Substance Designer and drag and drop floor_tiles.sbsar onto the graph. Click on the node, and tweak parameters that look appealing to get a sense of what this .sbsar is capable of achieving in only a few clicks. An .sbsar file is basically a complete Substance Designer project with exposed parameters for users to tweak. We’re only going to use Floor Tiles to generate a cell shape, so there’s no need to adjust parameters that control properties like the gap width between tiles — we’re going to build these controls manually in the next step to increase the amount of artistic control we have over our marble material.

Image 3: This screenshot shows the Metallic channel of Adobe Substance 3D Sampler’s Floor Tiles node. The black and white nature of the Metallic channel makes it an ideal starting point to extract masks for tile shapes.

Image 3: This screenshot shows the Metallic channel of Adobe Substance 3D Sampler’s Floor Tiles node. The black and white nature of the Metallic channel makes it an ideal starting point to extract masks for tile shapes.

For my Floor Tiles, I used Hopscotch Tiles as the Floor Pattern and set the Tile Amount to 2. I left all of the other parameters alone.

Now that we have a basic tile pattern, we can begin to leverage the power of Substance Designer to break away from the training wheels we borrowed from Substance Sampler. By default, the Floor Tiles node comes with 5 exposed outputs, including Base Color, Normal, Roughness, Metallic, and Height. We won’t use any of these outputs; we just want to extract the shape of the tile cells. The Metallic output helps us do exactly this, since by default it is a black and white mask.

Image 4: This screenshot shows the beginning of the marble material graph, using the isolated Tile Edges as a starting point to form Flood Fill utility nodes for later use.

Image 4: This screenshot shows the beginning of the marble material graph, using the isolated Tile Edges as a starting point to form Flood Fill utility nodes for later use.

To create our main tile shapes, we first want to isolate the tile edges. To do this, invert the Metallic Output of the Floor Tiles node and run it through a Histogram Scan to make sure that it’s clamped to black and white only, with no values in between. Then we’ll plug the Histogram Scan into an Edge Detect node. Here, we have Edge Width and Edge Roundness parameters. We can use these two parameters to sculpt the shapes of our tiles. Use Edge Width to control the gap distance between the tiles, and use Edge Roundness to dial in the desired design. This Edge Detect node will become the basis for many other node chains later. I’ve framed it and colored it green so that I can easily find it. This node will be the main Tile Shape Mask. Invert the Tile Shape Mask to create another mask that we will later use a lot: Trim Mask. This mask will be used to isolate the gaps between the tiles. We will use this mask to create a metallic trim around the marble tiles.

Now it’s time to use the knowledge from the earlier section “Fundamentals: Flood Fill to Grayscale as a Pattern Breaker.” Connect the output of the Tile Shape Mask to a Flood Fill node, and then connect the Flood Fill node to a Flood Fill to Random Grayscale. Next, connect the Flood Fill to Random Grayscale to a Distance node’s Source input. Plug the Tile Shape Mask into the Distance node’s Mask input, and then set the Maximum Distance parameter to something high, like 6000, to remove the edges of our Grayscale tiles. This Flood Fill to Grayscale will be used later to drive our Directional Warps for breaking our marble patterns between neighboring tiles, as described earlier.

Adding Edge Damage to the Tiles

Our Tile Shape Mask is also the starting point for our Heightmap. In this section, we’re going to use the Tile Shape Mask and Flood Fill to Grayscale to add some damage to our tiles.

Image 5: This screenshot shows the nodes used to create erosion and edge damage on our marble tiles.

Image 5: This screenshot shows the nodes used to create erosion and edge damage on our marble tiles.

Connect the Tile Shape Mask — our Heightmap at this moment — into a Slope Blur Grayscale node. This is the main node used to add edge damage to shapes. Set the Slope Blur’s Mode to Min to change it into a Boolean subtraction operation.

Next, create any noise node (for example, Perlin Noise or Clouds 2) and break up its pattern using a Directional Warp, with the Flood Fill to Grayscale/Distance we prepared earlier as its Intensity input — just as described in the earlier section “Fundamentals: Flood Fill to Grayscale as a Pattern Breaker.” Crank up the Directional Warp’s Intensity to a high value like 200. Next, plug the Directional Warp into the Slope Blur node’s Slope input. Because we set our Slope Blur to Min Mode, the noise we use will subtract from our tile shape, resulting in something that looks like edge damage on our tiles.

Repeat this sequence of nodes a few times in a chain, using Blend nodes to connect into the next Slope Blur group. Use the Opacity slider in each Blend node to dial in the amount of damage you want for each group of Slope Blur. Also, make sure that each group of Slope Blur uses a different type of noise as its Slope input. For example, use Perlin noise to chip away at the tile edge in one group, and then use Clouds 2 to chip away at the tile edge in the following group. The different shapes of noise will give us a variety of damage shapes.

After finishing our repeated sequence of Slope Blur edge damage, we’ll create a Blend node and connect the new Heightmap with edge damage into the Foreground input of the Blend node. Then we’ll connect our original, undamaged Tile Shape Mask into the Background input of the Blend node. We can now use the Opacity slider in this Blend node to dial in the amount of total damage we want on our tiles. If we do not want any edge damage at all, we can set the Opacity slider to 0, giving us our original Tile Shape Mask without any damage.

Finishing the Heightmap: Adding Bevels to the Trim and Tiles

We’ll be using a Bevel node to refine the gaps between our tiles, creating a metallic trim in the area. Then we’ll add a second Bevel node to create an angular taper along the perimeter of our tiles.

Image 6: This screenshot demonstrates how the Trim Mask can be used to bevel the area between the marble tiles.

Image 6: This screenshot demonstrates how the Trim Mask can be used to bevel the area between the marble tiles.

First, connect the Trim Mask to a Bevel node. Adjust the Distance and Smoothing parameters as desired. I used a Distance of 0.03 and a Smoothing of 0.3. Second, connect the Tile Shape Mask to a different Bevel node and adjust its Distance and Smoothing. Blend these two Bevel nodes back into the main Heightmap chain by using Blend nodes. To control the amount of Bevel further, insert a Levels node or a Histogram Range for value adjustments. Our Heightmap is now complete.

Using Textures Made by Poly for Base Color

Our material will use three different types of marble, based on the following textures made by Poly:

Image 7: This image represents three Color Maps generated by Poly AI.

Image 7: This image represents three Color Maps generated by Poly AI.

The dark marble is a bit too warm, but we can use the HSL node to adjust its hue, saturation, and lightness — as the name of the node suggests.

Creating Masks to Select Specific Tiles

Before we can add color to our tiles, we first need to create two masks to help us isolate and select specific groups of tiles. Each mask will be paired with one of the three color textures made by Poly.

There are different ways to create selection masks in Substance Designer. For this tutorial, we will be using Flood Fill to Position and Color to Mask.

Image 8: This screenshot demonstrates how Flood Fill to Position and Color to Mask can be used to create specific mask selections.

Image 8: This screenshot demonstrates how Flood Fill to Position and Color to Mask can be used to create specific mask selections.

To begin, connect the Flood Fill we created at the start of the project as an input for Flood Fill to Position. Then create an array of Color to Mask nodes all connected by Blend nodes set to Blending Mode: Add. This Blend network will combine every color selection from the individual Color to Mask nodes.

With the node setup completed, double-click on the Flood Fill to Position node to display it in the 2D View window. We want this green and red position map to be visible on our screen at all times for the next step because we're going to be color picking from it. Next, using only a single click, select one of the Color to Mask nodes. Single-clicking on a node will pull up its parameters panel without replacing our Flood Fill to Position in the 2D View window.

In the Color to Mask parameters panel, click on the Color Picker icon to activate it, and then click on one of the green or red tiles located on the Flood Fill to Position map displayed in the 2D View window. We’re using the green and red RGB information from the Flood Fill to Position node to help us mask out specific tiles. Each Color to Mask node can hold only one RGB color, so repeat the process using additional Color to Mask nodes until every desired tile has been isolated in its own Color to Mask node. Blend them all using Blend Mode: Add until you have a set of complete masks.

For my material, I created a Small Tiles Mask and an Alternate Tiles Mask. These two masks coincide with two of the three color textures, made by Poly, that we are going to use to drive our marble material’s Base Color. Tiles that are excluded from these two selection masks will utilize the third texture made by Poly.

Extracting Poly’s Base Color

In this step, we will utilize the techniques described in the earlier section “Fundamentals: Flood Fill to Grayscale as a Pattern Breaker.”

Image 9: This screenshot shows the nodes used to blend Poly’s Color Maps into the Substance Designer graph.

Image 9: This screenshot shows the nodes used to blend Poly’s Color Maps into the Substance Designer graph.

Drag and drop the textures made by Poly onto the graph to load them as individual Bitmap nodes. Connect the Bitmap outputs to the inputs of the Directional Warps. For the Directional Warps’ Intensity inputs, plug in the Distance node from the Flood Fill to Random Grayscale that we prepared at the start of the project. When used as a Directional Warp’s Intensity input, the Random Grayscale will act as a pattern breaker so that each tile will look like it was made with a self-contained slab of marble.

Use a chain of Blend nodes to combine all the colors, using the Alternate Tiles Mask and Small Tiles Mask that we created in the previous step to isolate two of the textures made by Poly.

Finally, combine the composite color with a white Uniform Color node using a Blend node. Use our original Trim Mask to isolate the gap between the tiles and make it white.

To further refine the Base Color map, we can use assorted Blends to bring in other color and masking information. For this demo, I used a Dirt node to add grunge to the trim between tiles.

Image 10: This screenshot shows some of the nodes used to create the Metallic map.

Image 10: This screenshot shows some of the nodes used to create the Metallic map.

The Dirt node requires the following inputs: Ambient Occlusion, Curvature, Normal, and Mask. We can take our Heightmap and connect it to an Ambient Occlusion node and a Normal node to create two of those inputs. To create a Curvature input, connect the Normal node into a Curvature Smooth node. Lastly, connect our Trim Mask from earlier into the Dirt node’s Mask input so that all of our color adjustments are confined to the gap between the marble tiles. Tweak the Dirt node’s parameters as desired. For more control over the look of the Dirt node, insert either a Histogram Range or a Levels node from the main Heightmap and use this adjusted value range as the input for Ambient Occlusion, Normal, and Curvature Smooth.

From here, we can use the Dirt node’s output to create additional masks for blending more colors. If common metal colors are desired, such as gold, aluminum, or copper, use PBR Metal Reflectance. This node comes with presets with accurate RGB colors for common metals. Remember to connect the Trim Mask directly into the Metallic Output.

Roughness

At this stage, we have a Heightmap, Normal Map (derived from Heightmap), Ambient Occlusion (derived from Heightmap), Metallic (the Trim Mask), and Base Color. All we need now is Roughness to complete our collection of PBR maps.

Creating Roughness is a complicated topic to cover, especially in writing, and can be an entire standalone tutorial. It’s easier to learn about Roughness by watching video tutorials. I recommend two YouTube video tutorials: “Take your Roughness Maps to the next level in Substance Designer,” by Xolotl Studio, and “Creating a roughness map in Substance Designer,” by FastTrack Tutorials.

Image 11: Turning the Base Color temporarily into pure black can give a good preview of the Roughness map.

Image 11: Turning the Base Color temporarily into pure black can give a good preview of the Roughness map.

One great tip is to temporarily replace the Base Color with a black Uniform Color node when creating Roughness. It makes it easier to distinguish between rough and smooth/shiny areas.

Image 12: This screenshot shows some of the nodes used to create the Roughness map.

Image 12: This screenshot shows some of the nodes used to create the Roughness map.

Also, I recommend checking out material artist Josh Lynch’s Mask Generator. As seen in the screenshot above, this third party node can extract useful masks from any input. It does a wonderful job at isolating marble patterns from textures made by Poly. I blend these masks into my Roughness chain.

Closing Thoughts

With AI tools becoming more easily accessible, professional artists have an opportunity to discover new ways to integrate AI tools into existing professional workflows. This tutorial shows just one example of how AI can be used to enhance game asset creation. Because we used AI only to create our PBR Base Color map, we retained full artistic control over the rest of our design by building the material manually.

To conclude, here is the final Adobe Substance 3D Designer graph, along with other marble materials I created using the same techniques covered in this tutorial.

Image 13: This screenshot shows the full Adobe Substance 3D Designer graph used to create the PBR marble material covered in this tutorial.

Image 13: This screenshot shows the full Adobe Substance 3D Designer graph used to create the PBR marble material covered in this tutorial.

Image 14: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.

Image 14: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.

Image 15: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.

Image 15: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.

Image 16: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.

Image 16: This marble material was made using the workflows covered in this tutorial. The cylinder and sphere were rendered in Marmoset Toolbag.