Ishan Verma has shared a great in-depth breakdown of a new Halloween-themed material made in Substance Designer and Unreal Engine 5.
In case you missed it
You may find these articles interesting
My name is Ishan Verma. I am an Intermediate Material Artist working at Ubisoft and have been working in the games industry for the past three years. The article I'm writing covers the process of how I created Pumpkin Cookies in Substance 3D Designer and how I showcased it in Unreal Engine 5.
About the Project
October was the Halloween season and everyone was creating spooky art. I was scrolling through Instagram and saw some cookie-based posts, and I thought, why not make some Halloween cookies? My artwork was entirely unplanned, I just hopped to SD and started scribbling!
I wanted to achieve clean-looking shapes so I kept things for the height building minimal. My main focus was to spend less time on height blending and make it more realistic and detailed in the end.
In order to gather references, I created a PureRef board and gathered pictures of various kinds of cookies that were similar to the ones I had in my head. There are a number of different types and characteristics of cookies in these reference images, from the feel of the surface to the kind of treatment given or what product they are made of.
Height Building: Cookies
I started with a paraboloid shape, used the Levels node to level it up, and then used 2D resizing to resize it to an oval shape transform node. For adding a slight edge warp, I used two Perlin nodes with different sizes and did a minimal amount of Directional Warping. Next, I used a Mirror node to subtract both the top and bottom portions of the oval. Our cookie base is ready!
To create ribs on top of the cookie, I created a ring by subtracting a smaller circle from the base one. I then blended the rib shapes using 2D transforms and mirror nodes. Using multiple blur nodes, I increased the depth of the ribs and subtracted them out with the main cookie shape!
I also added a slope blur to one of the blurred-out ribs and subtracted it from the cookie to give a slight realistic depth!
Here I created a rectangular shape using a shape node, then using a Trapezoid transform node, squeezed the bottom points of the rectangle, and did a directional warp on it using a Gradient Linear 2 in the X-direction.
A level node was then used to bevel out the shape, tighten up the stem, use a Perlin noise to do a minimal Directional Warp, and then transform to a particular position and blend it with the main cookie via a Height Blend node.
Cookie Surface Noise
The surface noise began with warping two different noises, BnW Spots 2 and Moisture Noise, using a base cookie shape to give them some ideal warp iterations, and then masking out areas of the BnW noise and blurring it out!
Subtracting the slope blur from the cookie height later, added surface noise!
Expression Atlas and Tile Sampling
On my first try, I planned to generate all of the facial expressions procedurally but I thought that I could save time by creating an atlas instead. With this SVG node, I have created a 2D view atlas where all the expressions are made up using vector tools.
As soon as I completed Atlas creation, I worked on creating cookie variations, for which I used crop nodes to crop out all five alphas. After giving them a slight bevel, we transformed and resized them so that they would fit perfectly on the base cookie. We then subtracted it from the cookie to give it a dramatic look! We now have five different cookies to work on!
All five shapes are now plugged into a tile sampler.
Here are the parameters for the tile sampler I followed up with!
Then, using the cookies from the tile sampler, I drove those with a Histogram scan to create a generic mask that will be used in blending upcoming data!
I created three different sugar cube variations using Cube 3D nodes, then plugged them in a tile sampler and splattered them randomly. Using the splattered cubes as a base, I multiplied the blurry cookies by the cubes to create a slope and subtracted the stem portion from these splattered cubes.
After the sugar cubes were blended together on top of the cookies, I used the Height blend node to level up the height data, then I used the Level node to level up the cubes.
Following the sugar cubes for cookies, I then created splattered cubes that would later be layered over a wooden base.
As I did with the cubes above, I replicated the tile sampler, the only difference is I used a custom mask that came from a Grunge Map driven by a histogram select before plugging it into the mask input.
My Albedo was created by putting a Normal Map into a Curvature Smooth node and then creating orange, yellow, orange, and dark orange shades using Gradient Maps nodes and blending them using masks created from Curvature.
Adding color to the stem is accomplished by driving it with a copy of the cookie shape I created earlier and using a histogram scan to make a mask, on top of which I blend the green Gradient Color Map I made earlier for cookies.
To create sugar cubes on top of cookies, I plugged the height of the cubes I had created earlier into a normal, followed by a curvature smooth, and lastly blended colors with a Gradient Map. The same is done for the sugar cubes which are splattered on top of a wooden base.
For roughness, I first inverted the Curvature smooth, then added B&W spots on top of that using soft light blends. Then again using the same technique, I added a micro unevenness feel on top of the noise by subtracting the noise.
The sugar cubes have also been subtracted from cookie values with cubes from the tile sample in order to make them shiner and break up the flatness of the Roughness Map.
Having completed roughness creation, I decided to jump into base wooden material before fitting in the rest of the cookie maps! We'll work on the wooden base breakdown below; this will be blended in with the main cookie maps once it's completed.
Height Building: Wooden Plank Base
Here I started with a tile generator node, using it to create a rectangular tiled shape in the Y-direction. I used an edge detect node to bevel it out, and I then used a distance node to tighten it up at some point.
I did a slope blur with a Grunge Map 02, inverted it, and used a non-uniform blur on it. After that, I tightened the shape using levels and added an anisotropic blur to the crevices to create an aged appearance.
To create some surface crevices, I used a tile sampler to draw thick directional lines and then Warped and Directionally Warped it with Crystal 1. Then I inverted the image to add another Directional Warp with intensity mask as Grunge Map 02.
My method for adding surface noise started with a Perlin noise shape that was warped to a square shape, then I used a tile sampler to splatter it out and create small crevices. By transforming the height, I blended it over the main tile sampler in soft light mode. Then I blended Directional Noise 1 and Grunge Map 02 on top of the height, and finally, I did an auto-level to level up the height data.
Blending Noise on Planks
Firstly, I subtracted the big crevices from the small crevices height data, used Clouds 2, then added unevenness to the noise borders using a Directional Warp. Finally, I removed dark tones from the height data using a histogram range. Blended the plank shape created earlier with SoftLight mode, and then once more with Subtract mode and then at last multiply the same planks to achieve the edge damage effect.
As for plank roughness, I kept it very basic. I measured the height of the planks, inverted it, and then with a level node, leveled it out before blending the crevice damage into it.
In my case, I kept it dual, so one was for the Planks with deformities and another was for surface noise, then combined both with a Combined Normal node, as well as adding an Intensity Normal node to control the intensity.
As a Base Color for the planks, I started off with a flat brown shade and added crevices of dark color. Then I used Directional Noise 2, blending it with Grunge Map 02, controlled by a Gradient Map to produce light variations on the surface. I then darkened the Albedo a bit with the HSL node.
To add some depth, I layered a curvature smooth over the surface with SoftLight mode, and for more variation, I used a histogram select to mask out some portion of the grunge I created, then blended it on top of basecolor.
Later, I darkened up the base color to give depth to the spaces between planks by masking out crevices from plank height.
Layering Cookies on Planks
To begin, I blended Cookie heights with planks heights using an anisotropic blur node, and then transformed Normal to Height from planks heights, inverted the result, and layered cookies on top of the planks using a Height Blend node.
Similarly, I used the height blend node for the normals, but instead of using histogram data and cookie height data, I used a Normal Blend node.
First is the AO derived from cookies, then the planks, after which there is another AO derived very minimally for the cubes of sugar on top.
Eventually, a level node will control the intensity of Ambient Occlusion.
Specifically, I took the plank roughness and the cookie roughness separately and blended using the mask I made earlier. Additionally, I subtracted the height of both masks from the sugar cube splatter I made earlier to give some polish to the cube roughness.
I have blended both the cookie and wooden Base Color Maps that we created earlier using the cookie mask produced from the histogram scan.
Texture Export for Unreal Engine
As soon as the textures are created, they are exported as follows:
- Transmissive and Translucency Color Map
As soon as I imported the textures, I created a basic material and converted it to subsurface shading. In the following step, I plugged all the valid maps into their inputs and also created exposed parameters to control the Normal Intensity, the Subsurface Intensity and Opacity, and the Fake AO multiplier.
Houdini Mesh Displacement
I generated the displaced mesh in Houdini first by creating a geometry node and then adding a grid with primitives set to polygon and size as 10x10. Then I divided the mesh into 10x10 chunks by going into the depths of the grid.
After that, I displaced the mesh using the Height Map we generated earlier. Once the Height Map is prepared, I resized the mesh with the Displacement Map. Scaled it from 1.0 to 0.1 to fix it in the 1x1 tiling position and displaced it in the Y position with 0.38 intensity.
After computing Normals, I completed the mesh by adding normals nodes and finalizing it with UV projections and exporting it as a Nanite mesh in Unreal Engine 5.
Showcasing in the Engine
When I rendered, I first imported the displaced mesh as a Nanite mesh, then applied the material instance for the cookie material, as well as tweaking the parameters as needed.
After adding two-point lights, I turned on the Lumen lighting, the SkyLight, and Height Fog using the post-process volume to add some realism to the viewport.
A cinematic camera was created in photoshop, as well as a specific LUT and some good shots were adjusted to take final renders.
While it had been a festive week, I really enjoyed working on it and it had a huge Halloween vibe to it. I spent about four to five hours on it and really enjoyed it. It is my recommendation to all artists across the globe that whatever idea strikes them, keep pushing it into reality and make creative works out of it!
Ishan Verma, 3D Material Artist
You may find these articles interesting