By ALVARO CLAVER and IAN FAILES
The award-winning definitive authority on all things visual effects in the world of film, TV, gaming, virtual reality, commercials, theme parks, and other new media.
Winner of three prestigious Folio Awards for excellence in publishing.
By ALVARO CLAVER and IAN FAILES
In visual effects, 3D models are partly brought to life by texture artists who might paint colors and textures onto everything from CG characters, to flying ships, to forest environments. Two main software tools stand out from the crowd in 3D texture painting: Foundry’s Mari and Adobe’s Substance Painter.
To get a handle on how each tool tends to be used in high-level film and television work, VFX Voice asked texture and lookdev artist Alvaro Claver () to demonstrate how a CG asset can be textured using Mari and using Substance Painter.
Alvaro currently works at Sony Pictures Imageworks and is also an on-campus instructor and online supervisor at Think Tank Training Center in Vancouver. His credits include WandaVision, Avengers: Infinity War, Avengers: Endgame, Captain Marvel, Thor: Ragnarok, Black Widow, Morbius, A Wrinkle in Time and Lost in Space.
To demonstrate, Alvaro utilizes a trooper helmet asset to showcase the two different 3D texturing workflows artists can follow to paint physically accurate texture maps in Mari and Substance Painter. First, he outlines some background about the two tools and the methodology behind his suggested workflows before setting out each step.
A QUICK BACKGROUND TO SUBSTANCE PAINTER AND MARI
Substance Painter can show a very accurate representation of the final result in the viewport thanks to a smart implementation of real-time shaders. It excels in medium-to-small assets that don’t require a large number of extra channels. Its integrated mesh map baking can be a real time-saver as it synergizes with the rest of its features, like the mask generators. It comes from the get-go with a nice collection of alphas, procedural layers and tileable maps. Painter can be used in a VFX production environment as a standalone texturing tool or in combination with Mari.
Mari has an incredible amount of raw power and can deal with any asset you throw at it. It can work with high-poly meshes with a ridiculous amount of texture sets (once I painted one character with more than 500 UDIMS). Mari also has the best projection system in the industry, with a paint buffer acting as an intermediary between your images and the mesh. Thanks to this, it is possible to project high-resolution raw images up to 32 bit, like the ones used for skin details. It takes more time to set up a project at the beginning in order to share channels to use them as layer masks inside other channels but, after that, building the maps is way faster. Mari is a powerful tool that is best suited for painting big VFX assets.
I have kept the workflow as close as possible for each tool to obtain similar results. The tileable maps I used were shared among the two. Final renders were done in the viewports using the shader options that each software has. Painter uses by default a simple but very accurate PBR metal roughness material, and Mari a generic principled BRDF material with many extra options.
Step 1. Baking the mesh maps
This first step will give us a collection of useful maps we can use to generate surface details like accumulation of dust in the occluded parts of the model, weathering, drips, grime, and much more. We need these maps to drive some masks and to give the asset a realistic look. The ones I tend to use the most are ambient occlusion, world space normals, curvature (which includes convexity and concavity) and position. When working on an organic model I also bake a thickness map, but I’ll skip that step as this is a hard-surface asset.
Substance Painter: I prefer the legacy workflow, so when creating a new project, I select Create a texture set per UDIM tile. After the project is set and saved, the next step is to go to the Texture Set Settings palette and press the Bake Mesh Maps button. Once in the baking settings, I usually choose an output size of 2048, as the resulting maps will be blurred and modified heavily. As for which maps to select, I will go with World Space Normals, Ambient Occlusion, Curvature and Position. Confirm by pressing the Bake All Texture Sets button and wait until the process is done. In some cases where the UVs are not organized by material in different UDIMs, it can be useful to bake an ID map and use it to mask by materials.
Mari: After creating a new project and the three channels we will be using (diffuse color, bump and roughness), we will create a new channel, rename it to Ambient Occlusion and bake our AO by going to Objects/Ambient Occlusion. That will bake the map, but in order to see it and use it we will create a new channel with an Ambient Occlusion procedural layer inverted, and with a Levels adjustment so we can use it as a mask. Now, instead of the world space normal, we will use an Axis Mask procedural layer when needed, which is a tri-planar projection in the x, y and z axis, with positive or negative values. For the curvature we will use another procedural layer called Curvature capable of outputting convexity, concavity or both. At this stage, I also like to create a channel for the convexity so I can mask the edges using it.
Step 2. Creating ISO and RGB masks
One of the most important elements when working on the texture maps are masks. They give us the power to control different areas in a model without affecting the others, and we can use them to separate parts by material, create paint decals, and much more. What’s even better is that this way we can work in an almost complete procedural workflow that will allow us to make quick corrections and adjustments down the line. After all, we always get notes before anything is approved, right? We will also export these masks so we can make fine adjustments in each material in lookdev and comp.
Substance Painter: Thanks to having the UVs for each part of the helmet in a different texture set, we can apply materials and work on each of them individually. We will still have to create extra user channels for each of the texture sets, name them as our RGB ISOs, and assign the color that will go to each of those channels in each material. This needs to be done for all of them. We will then layer at least dust, dirt and grime on top of each material using mask generators with either tileable or procedural alphas. For the helmet there is only one mask we need to manually project on top, the blood smear, which will require some manual painting.
Mari: The way I like to set my workflow is by using channel masks. I first create the ISO channels with the selection masks and surfacing imperfections. Then the RGB ISO channels with each of the red, green and blue colors with a screen blending mode, and mask them using those previously created ISO channels. It takes some time to set this up but once it’s done, we can always call those ISOs from their channels and, if we make any changes to the original ISO channels, they will automatically propagate to the rest of the channels. For example, if later on the grime needs to be contrasted, we will just go to our grime ISO channel, modify its levels, and it will reflect those changes in the rest of the channels it’s being shared to.
Step 3. Painting the diffuse color channel
Thanks to all the prep work we did before now, we should be able to create a very fast first pass for our diffuse color. For me, it’s important to get to that first 90% of the final look relatively quickly to have more time later on to finesse the extra detail. There will be some adjustments we will have to do to the masks later on, including manual painting and projections, which will take longer.
Substance Painter: After working on each material separately, now I choose to view only the base color in the viewport to help me start tweaking the general look of it. At this point I make sure the masks are working as intended and not looking too procedural, especially the ones driven by occlusion or curvature. For this, it’s good to break the silhouette by using some filters like the warp on top of that pesky mask, tiling other alphas and multiplying them on top and, to finalize it, paint out or add some areas manually. As usual, keep the reference at hand to get as close as possible to it.
Mari: I usually start by creating a base color for each material with a general breakup. Procedural noises will help us to achieve an interesting base to build on top. Once we have a base color for all our different parts, we can start layering the dirt, dust, grime and more on top. It can be as easy as creating a procedural color layer, and then masking it with the corresponding channel mask that we created before. In some cases, like the blood smear in the helmet, it can be better to use a noise procedural layer for its color to give it additional variation. After building our color channel, we will then assess what needs to be improved and modify it by tweaking the channel masks that are being used to drive them.
Step 4. Creating the bump channel
To keep this not too complicated, I’ll be using only a bump map instead of a combination of bump and displacement. Ideally, you may want to keep the smaller details like high-frequency noises in the bump and the more visible details in the displacement: apart from not breaking the silhouette, the bump can’t catch well-defined highlights with the same detail as the displacement.
Substance Painter: At this stage, creating surface details is a matter of making sure the layers with the detail that we want are populating the bump channel in the material properties of each. We also need to give them an individual value that, in this case, will have a 0.5 gray middle point, as we are using 16 bits of information per channel to retain as much detail as possible and to get clean gradients. It takes some time to set up. For this, it’s very useful to switch the viewport preview to the bump channel in order to see the exact result of the map we will be exporting later on. It’s also a good idea to check how the surface is reacting to these values in the material view, as we can rotate the light rig around and check those volumes in a very convenient way.
Mari: The approach in Mari is slightly different, as we have all the layers inside our bump channel affecting all the texture sets at the same time. Here is where all the channel masks that we created and set up in advance will come in handy and save us precious time. Same as I did in Painter, I first create a base layer with a soft cloud to give the overall surface a little bit of wobbling, and on top I tile the blood smears and the holes of the front mesh. If this were a production asset the process would be more complicated, as you will want to separate each of those surface details in their own bump and displacement channels to have more control in lookdev.
Step 5. Creating the gloss/roughness channel
Depending on your personal preference, or the company pipeline guidelines if you are at work, you will be creating and exporting either a glossiness or a roughness map. If you use the specular/roughness workflow, you will paint a specular channel along with your roughness, so your shader knows the reflectance information for both metal and dielectrics (non-metal) surfaces. However, if you use the metal/roughness workflow, you will need a metallic channel instead. This time we are following the metal/roughness workflow, so we will still need that metallic channel. It will be all black except for the little metal piece at the left side of the chin.
Substance Painter: Same as we did with the bump map, we will set the viewport to preview the roughness and start dialing our values. I tend to do this first and then check how it looks in the material view. It is a good mental exercise to not forget what values work for your needs. If you tend to work only in the material view, you can fall into a guessing game that can produce the desired results most of the time, but can also lead to big mistakes. For example, Painter can’t accurately display displacement in the viewport: it calculates a rough look by approaching it like it will do with the bump. If we are not careful, we can lose the middle point for it and we will not know it until the map has been exported.
Mari: Like we did with the bump channel, now is the time to layer things up. I like to use plain color procedural layers and mask them with their corresponding channel masks. I have a good grasp of how each value will modify the reflectivity qualities of the materials thanks to my experience texturing and shading, but there will always be some adjustments to do later on depending on each specific asset and its use scenario. Thanks to the non-destructive approach we are using, those notes can be easily addressed in a very quick turnaround.