In case you missed it
Learn more about Substance Designer
My name is Margot Casiro, I live in France and work as 3D Environment Artist at Ubisoft Montpellier. I’m in charge of materials for Beyond Good & Evil 2. As far as I remember, I've always been fond of video games and CGI. This led me to Game Art studies at Objectif 3D Montpellier till last year right before I ended up working at Ubisoft
3D allows us to create imaginary worlds and share them with people. It's a great way to escape reality somehow and help you dream as a child, which everyone needs I guess!
Starting with Substance Designer
I started looking into Substance Designer at school as the guys from Allegorithmic came and hold a presentation of this software. I was immediately fascinated by the infinite possibilities provided by Designer considering I was already into texturing more than anything else. The summer that followed I had the opportunity to work on a small project that allowed me to create a lot of materials and then I kept going, practicing in my free time during the last school year. The main benefits are obviously the iteration speed and the possible variations thanks to the parameters. This actually is what makes the software great and limitless.
How Substances Start
I always start my substances by creating the heightmap, that's what will drive absolutely everything else. It's important for me to have only one normal node that flows from this height line. Sometimes, I do think about the color in parallel to the height construction. It helps me anticipate issues, start the creation of the masks or modify my way of merging different heightmap layers. On my last material, I knew I would have problems with the color layering and I wanted to test it as soon as possible. My heightmap was then a pretty rough build-up. When color testing, I noticed that I needed the masks provided by the "height blend" node, which I then used to build my height. The roughness, on the other hand, is quite self-contained and does not rely on any other node chains. I do like to bring in noises that aren’t already used elsewhere.
To create a noise, I usually start by browsing the library. Sometimes, I choose one that perfectly fits my needs or I find a close one and I use the "Open Reference" option to see how it’s been designed. It gives me the information required to create the one I need with accuracy. Moreover, it's interesting to do this step even with a noise that suits us, to bring variation. For example, I often use GrungeMap 004 but I modify it because it is very recognizable. In order for this brand new noise to remain readable, it is important to focus on rhythm and let some areas stay free from shapes.
It's really important to be able to extract masks from each and every step of the height construction and then do the color layering. I most of the time use the HistogramScan node to get masks. The HistogramSelect is also interesting when working on specific ranges of the height. I also try to always get sharp and clean masks from my height in order to use the FloodFill node. It is essential to me, I’m pretty sure I use it in all my graphs. It allows tons of variations with the heightmap with BBox, Gradients or color, for instance. Sometimes, it's not that easy to get accurate masks from blended heights, in which case I use a trick. Build an ambient occlusion with low radius, adjust levels to get sharp outlines and blend this to your actual mask. You’ll then bring back useful information to help with your FloodFill.
Now, let’s do a little breakdown of the Heightmap of my Stylized Leafy Bark Material.
I created the main pattern of the bark with a TileSampler. These are paraboloids stretched on Y, Size Y = X * 4. Then we subtract the clean shape to the slightly blurred shape and contrast with a Level, it is a kind of “edge detect”. Finally, we deform with a GaussianNoise to give movement.
Then comes a NonUniformBlur to give volume. I created this function in the intensity parameter to lower it if we increase the number of patterns. The function must be set so that the first division equals 1, with 4.12 being the desired intensity value for this iteration number.
The next step is to create small horizontal lines with a TileSampler in order to cut out various vertical lengths. Then, we make a Vertical DirectionnalWap with a CreasedNoise to break the boundaries. GradientDynamic creates a noise to apply lightly to the surface of the bark.
Here, it’s about tiling the pattern and blending the different iterations in MaxLighten to obtain variations. I also use the "AverageBlending" node created by Ben Wilson to create small bumps with a PerlinNoise. Finally, I use a FloodFillToRandom Grayscale that I slightly blend in Multiply to obtain height variations in the bark.
We make a Noises slight pass:
- Use a Crystal 2 horizontally with a DirectionnalWarp to break the lines.
- Create a SlopeBlur with a large-scale MoistureNoise, multiply it slightly on the bark to alter the edges.
- Use a DirectionnalNoise in Subtract blend mode on the surface.
Finally, we make an AutoLevel to make the height full range. Then, I again use a node of Ben Wilson, "Inflate", which allows you to create volume and give a convex look to the bark shapes. I also use threshold height values with a HistogramScan and blur them slightly to create some kind of “holes” that I then subtract to my heightmap.
I started by creating a "Brush" noise by warping a square with different noises, then I blended a MoistureNoise over this shape to add texture and plugged it in a MakeItTilePatch to create the noise. Finally, I used Ben Wilson's "ColorVariation" node with a brown UniformColor.
Here, I'm going to create two GradientMaps. The first is an issue of the heightmap that I blend with the base "Brush" using GrungeMap 003 as a mask. The second is created from the height, contrasted, blurred and distorted. Then it is blended in AddSub which allows you to begin to cut the bark with more punchy colors.
After I create the noise with a BnW Spots 3 and two DirectionnalWarp, I just blend it in AddSub to add very slight grain. Finally, small stains are added with the first mask created with the GrungeMap 004 and a MakeItTilePatch, and the second mask from the noise Dirt1.
Then, I just added UniformColor with masks directly extracted from the 3 channels of the Normal. It allows placing fun color tones in the shadow and light areas.
Finally, I used the "CurvatureSmooth" and "Light" nodes in which I injected a Normal a bit strong. I exaggerated this step because my material was for static lighting, but in a video game, you have to be careful with that, so as not to distort the lights too much.
The first step for the atlas was to create different small leaves directly in color. For that, I injected a "paraboloid" shape in different GradientMaps that I distorted with Transform2D. I then assembled them with SplatterCircularColor or just some blends with a mask.
Then, I multiplied the "Brush" Noise created previously on top to bring some variations. I also extracted a grayscale version of the Atlas to convert it to Normal, AO and Mask. I created four different patterns to arrange them in Atlas.
Then, in 3ds Max, I created 4 small slightly curved planes, corresponding to the 4 parts of the atlas, the pivot point is placed at the base of the leaf. Then, I painted directly on my sphere with the "PaintObject" tool in Max.
For the shader, I just used Marmoset SSS, with Albedo as ScatterMap, and the leaf mask as Translucency and Fuzz map. Here, I'm not trying to have consistent values. I just try to get a result that I like.
Important Elements to Control Your Height
1: Manage the range of our HeightMap well:
For my Rayman-inspired material, I had 9 layers of flowers to stack. So I used 9 TileSampler instead of one to extract one mask per layer for color. To assemble them, I used the following diagram:
The HistogramRange is the best way to control the different layers of the heightmap. When creating an element, the occupied range is [0; 255], but if you want to assemble two elements, it is important to adapt their range so that they position themselves to one another as desired. In the example above, the amplitude of the range between each layer is the same, but to have a more pronounced result, we can, for example, narrow the range between the first layers so that the background pops out a little more. If the ranges are correct, you can assemble without clamping values. There are nodes that do this, like the HeightBlend, but it is important to master this concept to create consistent HeightMap.
The "Histogram" tool of the 2D view allows visualizing these values.
2: Proceed methodically to create the Shapes:
For Shapes, I start by thinking on a flat plane and creating simple shapes in the view from above. Now, it’s really easy to deform primary forms, there are a lot of nodes to do that: Transform 2D, Quad Transform, Trapezoid Transform Warp, etc. I cut out my main form according to my need by blending secondary shapes in Subtract/Add. A nice node to give volume is NonUniformBlur. Associated with a Level or CurveNode, it can quickly get the desired volume. After that, I can just stack each shape with the method seen just before!
Tips for Shadows
When creating a material, it is important to have in mind which size of the surface and what height is being represented. This is the type of information we will be able to fill in the AmbientOcclusion to create coherent shadows. With stylized art, we can, of course, exaggerate these values. The AmbientOcclusion is not the most relevant map to use as such in stylized projects, but we can tint it to create "softer" shadows, use it as a mask in the Color or drive the SSS in the shaders. As seen previously, we can separate the different channels from the normal to create masks and integrate fun colors in the shadow and light areas.
When you work on the colors, the reference is important of course, but we must leave a place for our feelings to give a soul to what we do. Sometimes, I pick a color on the reference but the result doesn't suit me, so I choose one based on my feelings and this time it's the right one. The rules of the PBR are there to guide us and ensure consistency between everyone, but above all, it is necessary to have fun and not to stop testing things because that's not necessarily logical. Don’t be boring! Here are some little tips of color that I like to use:
1. Designer Set-Up:
First, I make adjustments in the 3D view to have a good perception. I choose my HDRI Environment - in general, I take Tomoco_Studio or Gdansk_shipyard_buildings because they are rather neutral. Then, I activate the Post Effects in the settings of the camera and at the bottom, I set the Tone Mapping on Sensitometric. It is the one that comes closest to the correct answer of Albedo and respects the industry standards. You have to choose Hejl in Marmoset to get the same answer.
2. Flood Fill Node:
As I said above, it's super important to get a mask with the contours of the HeightMap. If the elements of the height are not very distinct and all mixed together, then we can try to get contours with an AO and a level. I almost always use this mask to start my color. I inject it into a FloodFill and the FloodFill to Random Grayscale which allows me to drive my GradientMap base. Each shade of gray will then point to the color of your choice, which brings a good diversity.
3. Some small stains:
Regardless of the material, I like to add small discrete stains with bright and original colors. For example, blue for wicker, purple for concrete or pink for wood!
4. Create very colorful Noises to overlay them slightly:
I really like to create a very colorful noise based precisely on my feeling with the reference. It is necessary to take every key of color present and exacerbate it thoroughly, and also choose a pattern according to the grain of the material. We can blend this map to the color in overlay with very low opacity to add very-very subtle variations.
If You Want To Start Learning SD
In the beginning, I obviously watched tutorials but I also started practicing as soon as possible. I think we remember information much better when we look for it at the precise moment we need it, rather than when it falls on us. I really like using Substance Share to poke around in graphs. Of course, there is also Allegorithmic's Youtube channel, plus I learned a lot thanks to 80 Level because I prefer written breakdowns. When you practice for fun and learning, you really need to set goals that motivate you to trigger curiosity. There's no need to start with a rock, for example, just because we heard it is the basis.
You also need to exchange feedback a lot. The Substance community is very big, and if you share your work and study others' opinions and advice, you can learn new techniques or just get a different look.