Amir Habibi shared the workflow behind the Rocky Ground project, explaining how he used nodes to create the stones and then blend them with the ground, and how he added more details such as veins, color variation, dirt, and edge wear.
Introduction
Hello everyone. I'm Amir Habibi, an Iranian Material Artist with about four years of experience in the field. My journey into 3D art began when I applied to the 3D Artist course at Futuregames, a school located in Stockholm, Sweden. After being accepted, I went through a variety of programs that helped me learn different software and explore various roles within the game industry.
Initially, I planned to become an Environment Artist. But as I progressed through my education, I realized that material art was the path I truly wanted to pursue. As a material artist, I not only create materials for environments, but I also bring those environments to life through proper lighting, which is incredibly exciting to me.
I've always been detail-oriented, and material creation demands a deep focus on subtle details to achieve realism. That challenge keeps me motivated and passionate about my work. To improve my skills, I've watched many tutorials, mostly from Joshua Lynch, Daniel Thiger, Enrico Tammekänd, and other talented artists. But beyond just watching, I spend time thinking critically about how they build their materials and how I can combine their insights with my own experience to create unique projects.
Over the past few years, I've contributed to several projects, both independently and as part of collaborative teams. One of my most significant experiences was working on a student game project during my time at Futuregames, where I was responsible for creating environment materials using Substance 3D Designer and Unreal Engine.
I've also developed a series of personal material studies, including realistic wood, Oregon caves, dry lava, and sci-fi surfaces, which I've showcased on ArtStation. These projects have helped me refine my workflow and experiment with storytelling through texture and surface detail.
Workflow
When I want to create a material but haven't decided on a specific type yet, I usually start by browsing websites that offer high-resolution photos, like Getty Images, Pinterest, and Alamy, to see what catches my eye. That's exactly how the Rocky Ground project began. I was scrolling through references when I came across a set of rocky terrain images that immediately sparked my interest. The complexity of the surface felt like the perfect challenge to push my skills further.
Once I chose the topic, I began gathering reference images. I believe this stage is crucial and can significantly influence the entire creative process. Finding accurate and consistent references often takes time, sometimes more than a day. The images I collect need to support each other, meaning they should collectively cover key aspects like patterns, color variations, roughness levels, and overall surface behavior.
For the Rocky Ground project, I paid special attention to how erosion and moisture affected the surface. I also used scan data in my references, which allowed me to observe fine details more clearly and sample true colors without interference from lighting or environmental reflections, something that regular photos often distort. This helped me build a more realistic and grounded material.
Overall, the Rocky Ground project was inspired by a mix of curiosity and a desire to challenge myself. I wanted to see how far I could push the realism and detail in my materials. It also helped me improve my workflow and better understand how textures can tell a story.
Before diving into the graph and highlighting its various components, I'd like to begin by explaining how I've set up my outputs. Previously, I used Standard Normal and Ambient Occlusion (AO) nodes, connecting them directly to their outputs. This approach relied heavily on guesswork when adjusting the normal and AO settings. However, I recently learned a more precise method from Enrico Tammekänd that delivers significantly more accurate results.
This workflow utilizes World Units, allowing me to control both the size and depth of the surface simultaneously, which is incredibly powerful. For this material, I've defined the surface size as 200×200 cm and the surface depth as 24 cm.
Let's return to the beginning of the graph. In general, my workflow for creating materials in Substance 3D Designer starts with building macro shapes and gradually refining them into micro details. I organize my nodes from left to right and top to bottom; this layout feels logical to me.
To kick off this project, I began with the ground. I chose not to scatter stones randomly across the surface; instead, I wanted them to stack and interact with each other, allowing the ground's undulation to remain visible. To achieve this, I used the Clouds 2 node as a base and began introducing directional patterns. The GIF below illustrates how I progressively added different noise patterns to the ground to match my reference:
The next step was handling the large stones. I began by creating the basic patterns for the stones, then used a Tile Sampler to scatter them in a simple layout. Since these large stones form the core of the height map, with smaller stones scattered around them, I wanted to dedicate extra time to refining their appearance to match my reference.
To achieve this, I used the Flood Fill node twice and introduced additional details, such as a cliff-like pattern (which I'll explain later), to make the stones look as realistic as possible.
The medium stones are similar to the large ones but contain fewer details. I used only the Flood Fill node for sculpting the stones and applied a few additional adjustments to shape them.
The cliff pattern was used to carve details into the stones. As before, I started by shaping the initial patterns, then hooked them up to two Tile Samplers and blended them using the Min Darken blending mode. After generating the result, I sculpted the hard lines created by the blended patterns to better match my reference.
After creating all my stones, it was time to blend them with the ground. Before starting, I used the Transformation 2D node with Auto Crop Greyscale to isolate each stone individually. I began by blending the large stones using the Shape Splatter node, carefully adjusting the scatter settings to achieve the desired distribution. I chose this node because it generates a grayscale mask, which I could later use for Albedo creation or to scatter additional details.
One drawback of the Shape Splatter node is that it doesn't support size randomization, so I had to apply it manually. To do that, I used the Transformation 2D node and squeezed some stones along the X or Y axis. As I added more stones, I gradually reduced their size until a certain area of the ground was fully covered, aiming to match my reference as closely as possible.
For the sake of optimization, I set the resolution of the last two Shape Splatter nodes to 512, since they were used for tiny stones. These stones were intended to fill the gaps between the medium and large ones and appear on top of the surface, so a lower resolution was sufficient without compromising visual quality.
I also used AO and Shadows nodes as masks for the stones, a great technique I learned from Daniel Thiger to scatter patterns more naturally. Once the stone scattering was complete, I moved to refining the surface details. One effective method was hooking up a noise to the Normal to Height HQ node, following a workflow from Derk Elshof.
Albedo and Roughness
Once I completed the height map, I moved to creating the Albedo and Roughness. For this stage, I prepared a color palette to guide the entire Albedo process. I began by using the Height Map to extract various patterns for color sampling. Then, I blended different noise textures to generate something visually interesting and integrate it into the chain.
As I progressed with the base color, I continued adding more details such as veins, color variation, dirt, and edge wear. Finally, I blended the finished height map with ambient occlusion to enhance the overall shape and depth.
After finishing the albedo, I moved on to Roughness creation. To start, I connected the final albedo node to a Greyscale Conversion node to convert the RGB values into greyscale. Then, using a Levels node, I adjusted the range to begin shaping my roughness. As I progressed, I blended in the same patterns I had used for the albedo to maintain consistency and add depth.
Scan Data
Once I was happy with the material, I decided to incorporate scan data for the first time to push the realism of the project even further. After purchasing the assets from Textures.com, I used the Atlas Scatter node to distribute them across the surface. I wanted the scattered elements to appear everywhere except on the large stones, which I masked out accordingly.
A key challenge during the height map stage was balancing detail and clarity. I wanted it to drive variation across other outputs, but too much complexity made the surface feel noisy. It took several iterations to refine the shapes and keep everything readable.
The cool thing about Substance 3D Designer is that it allows you to create procedural materials, meaning you can tweak every part of your graph. My material follows this principle. I didn't expose any parameters because I didn't have specific controls in mind, nor did I need to adjust multiple parameters simultaneously, so I left them unexposed.
Marmoset Toolbag
In Marmoset Toolbag, I use a simple plane and drag and drop my material onto it for quick setup. The shader is built from Substance 3D Designer outputs like Base Color, Normal, Roughness, Height, and Ambient Occlusion. I light the scene with two opposed directional lights to balance shadows and highlight surface detail, often testing different times of day to see how the material reacts.
Renders are done at 4096 × 4096 resolution with ray tracing and advanced light sampling enabled. I also tweak the lens and post-effects to give the scene a more cinematic feel.
I also used the PBR Render node inside Substance 3D Designer to render a few shots. It's quite easy to use. After connecting my final outputs to the appropriate slots, I selected a suitable environment and captured the renders. To control lighting within this node, I used the Plane Light node, which allowed me to position the light and define the direction I wanted.
Conclusion
I spent almost two and a half weeks on this project, and I didn't force myself to finish it quickly because I didn't want to sacrifice quality just to publish my artwork prematurely. What I enjoyed most was seeing all the rocks come together perfectly; it was incredibly satisfying to watch the composition take shape just as I envisioned.
I also really enjoyed working with the PBR Render node and rendering in Marmoset, which helped me achieve some highly realistic shots that brought the whole scene to life.
I learned several lessons from this study. For example, when using the Shape Splatter node, I need to be cautious; it's a heavy node that can significantly increase the memory budget, so it's best used selectively in specific areas.
Another takeaway is that the PBR Render node is a great option for rendering. It can produce some really impressive results, and I’m excited to incorporate it into my future projects. I'd love to share some tutorials that have been really helpful to me: Fundamentals Part 1: Pattern Creation and Natural Scattering, Creating Herringbone Bricks in Substance Designer: Bundle, and Advanced Material Creation in Substance 3D Designer.