Learning the Software
As this was my first ever exploration into using Substance software (and texturing in general), I need to get myself to a baseline understand on what the software does and how it work with models for texturing. In pursuit of this, I took to watching a number of GDC talks about how it is used in industry, and how to create a workflow around Substance (incl. in References & Resources section). However, all of this was quite difficult to take in without knowing much about how to use the software itself.
So I bought a Udemy course on how to use Substance Painter - this one to be exact. And worked my way through the lessons in order to learn how Substance Painter is used to paint models. Following the tutorials, I created textures for models that were provided to me & learned how to bring them into Unity. Some of the things I made from this resource can be seen here:
I was honestly amazed with how simple it was to paint onto meshes, setup included. It is so similar to art programs like Photoshop or Clip Studio Paint when it comes to the use of brushes, layers and masks. So I took to it quite fast.
Learning Through Painting Old Robot
Before we had changed direction regarding our game's robot design, I had already began texturing and fiddling with our old robot mesh to figure out how to texture a mesh I had made myself. Doing this took a lot of retries, as I had no notion how to do UV unwrapping at all when I first started. Thankfully, the Udemy course on Blender 2.8 that I had previously bought had a section that taught us how to work with mesh UVs. After going through an iterative process of unwrap->texture->problem->repeat, I ended up with the following textured robot.
Note: this was left in an unfinished state - errors still persist with UV maps & materials chosen weren't final
Here's what I learned from doing this task:
- Seams are better off along edges of a mesh and/or in areas strategic to the character's form so as to mitigate visible seams.
- How to use generators on black maps to create dirt & rust effects.
- How to create UV seams across complex meshes to mitigate Texel deformations (stretching) & overlapping UVs.
- How to use the poly selection tool in Substance Painter.
Thanks to the Udemy course and the attempts in texturing our original robot, I learned the gist of how to use Substance Painter to paint models for our game. I felt a lot more confident afterwards, and could enter the robot redesign phase with less hesitation and felt that I could get it done in a much quicker fashion than before.
Texturing the G.S.A. Tainted Robot
Preparing the Robot for Texturing
Once I had my G.S.A. Tainted robot mesh created, I needed to go from mesh to mesh and unwrap the UVs on each one. From the lessons that I learned from unwrapping the old robot, I knew some good practices in regards to the placement of seams and mitigating stretching. Since my robot character is made of lots of different, un-merged meshes I need to ensure that this was done for each one.
Unwrapped character meshes seen in Blender 2.8 (red lines = seams)
Once this was done, all I needed to do was to apply materials to each mesh in Blender. Even in their default state, these are important as they become the differing texture sets when the resulting .FBX is imported into Substance Painter. Each unique mesh was given a unique material with an accompanying name denoting the mesh it was connected to - so as to be easily identifiable in Substance Painter. I added base colours to these materials in blender to preview the colour palette I had made in the model sheets. These base colours would not transfer over to Substance, so there was no greater risk to doing so.
To bring the Robot into Substance Painter, I needed to export the robot from Blender into a .FBX, then created a new project and chose it as my source file. I kept the document resolution as default - this would become an issue later, along with other things, thanks to the way I had gone about texture setup.
I created the project, and checked to see if all materials had been translated to Texture sets. Without these present there is a risk that some parts of the model would be unable to receive texture. After making sure it was all working I was more or less ready to begin texturing in Substance Painter.
Portion of the texture set list was successfully created on project creation
The next step of setup after making sure texture sets were generated was to bake the mesh's maps. To do this, I went to the project's Texture Set Setting tab and added Ambient Occlusion & Emissive to the channel list. From there, I clicked on the Bake Mesh Maps option in order to bake, applied the settings seen in the below screenshot, then click on Bake All Maps. Due to the high volume of texture sets for this model, this baking process took between 3-5 mins to complete.
Baking these texture sets allows me to make use of any added channels that were not there by default, extending the capabilities of the texture sets.
Once this process was completed, I was finally ready to begin texturing the model.
Texturing the Robot
The texturing of the robot itself was a process that was met with some false starts, as it took me some time to get the seams correct on some parts of the Robot character, which meant that I needed to go through the preparation stage a few times. Once I had it right though, it was full steam ahead.
Identifying Materials
The first thing I needed to do was experiment with materials on different parts of the mesh's body to figure out which worked best. Since I was using a Student license of Substance, I was unable to get any 3rd part resources or materials from Substance Source or other vendors without paying. Thankfully, the base material set in Substance Painter worked well enough, and any new materials could be made myself by building one up in layers.
Here's a list of default materials I chose to use on this mesh & where:
-> I used this material on section of mesh such as the Chest Place, Thighs, Calves, and any other grey metal surface. I edited the base colour in some instances to darken certain meshes.
..Damaged -> This was applied in areas of darker metal, like the leg connectors, hinges, internal pieces, and parts of the arm.
-> This was used on the Robot's torso and chest side paneling.
-> This was used on the Rubber Bellows found at the base of the Robot's arms. I tinkered with the dirt level of the material and toned it down from its default value.
-> This was material I derived from the Plastic Rough Scratched smart material. I upped the glossiness and deepened the scratches in order to make them look more like scarring when used on the robot's many tentacles.
Completed Textured Robot tagged with materials used
Applying Dirt and Rust effects
Once I had the base materials placed on the mesh, I needed to add detail in the form of accumulated dirt and rust. This was a quite easy task, as I had already baked the Ambient Occlusion channel onto the mesh previously. The function of this channel is that it dictates where dirt accumulated when generated. To create dirt effects, I created a dark brown fill layer as the top-most layer on a given texture set, added a black mask to it, then applied a generator to said mask. From the generator's selection box, I selected either Dirt or Dripping Rust depending on the part and then played with the parameters until the effect looked how I intended it to.
Applying Decals to the Robot
In order to add some extra detail to the robot without editing its mesh, I added some Decals to its Chest and Thigh portions using some of Substance Painter's default Alphas. Attaching them to one of the brushes, I applied different decals in areas. The results can be seen below:
Painting Fleshy side of Tentacles
Part of the Robot's design was the tentacles, which included a fleshy underside. To create this in substance, I created a brown-yellow fill layer as the top most layer on a tentacle texture set, then applied a black mask. With one of Substance Painter's brushes, I painted onto the black mask with its Grayscale value set to anything above 0.5, in order to paint active areas into the black mask. I varied the grayscale in certain areas to create a smooth transition between brown and red flesh.
Painting onto the fill layer's black mask (using a Wacom Intuous Pro 5 tablet)
For other areas of the Robot character's mesh, I painted extra details (mainly dirt) to fill in areas that the software's algorithms did not reach. Once I was happy with my texture work, I moved on to exporting the textures and importing them into Unity.
Exporting Texture Sets for use with Unity's High Definition Render Pipeline (HDRP)
Once I had the robot textured inside of Substance Painter I could export the maps into Unity in order to make & apply materials to the mesh. However, since we were using the High Definition Render Pipeline, I needed to create an export option in Unity that works with Unity's HDRP format. By looking at the inputs of the HDRP/Lit material inside of Unity, I could arrange a set of outputs that had the correct data in the correct channels per texture.
Using the shader's input requirements (images above) I created a configuration inside of Substance that exports 4 maps with different data in their respective R, G, B, and A channels.
- The Mask map - (R - Metallic, G - Ambient Occlusion, B - NULL , A - Glossiness)
- The Base map - (RGB - Base Color, A - Opacity)
- The Normal map - (RGB - Normal OpenGL)
- The Emissive map - (RGB - Emissive) [OPTIONAL - Only necessary if texture has emissive maps baked onto it]
I saved this configuration as "HDRP" and then exported the textures for each texture set using it. I exported the textures as .targa files, as they are conventionally what are most suitable for storing texture data for games. These textures were exported to a directory on my desktop, and were then copied into Unity for material preparation.
Creating & Applying the Materials to the Mesh in Unity
- making the materials
Looking at my imported Robot mesh in Unity under the import settings, we can see the number of materials that the character needs in order to be fully textured. These import defaults were brought over from Blender as they were attached to the .FBX export. Using these as a Guide, I created the necessary materials in a sister directory to the Textures as HDRP/Lit, and dragged the relevant textures into each one. Each material was made by dragging the relevant map into the material's fields, as required by the HDRP/Lit shader format.
Once all of the materials were made, I opened up the Robot import again and started replacing the materials attached to the object with the ones using my Substance materials.
All of the imported Robot object's materials replaced with my new HDRP/Lit materials
Once this was done, I applied my changes and the textured Robot was brought to life! All that remained was to remove all of the old materials that were attached to the .FBX import. To do this, I needed to find the imported object, select all of the default materials attached to it, extract them from the object, then delete them completely. This was purely to take clutter out of the project since they were no longer needed.
Results / Reflection
Below is a turnaround of how the finished Textured character looked in Unity.
Note: I added a hologram shader material alongside the robot's head material on the head object to communicate that it was indeed holographic.
There are a lot of things that could be said about the quality of my work here and how I went about it, some of them being things I had only noticed / realized long after I had completed the process of texturing & implementing the robot. Whilst I'm happy with how the resulting Robot looks overall, I can't ignore some major failings on my part.
Fundamental Issues
One of the things that I only noticed much later on in development after I had left this task behind was that the massive amount of materials for this Robot character was not necessary, and was in fact detrimental to performance. When working on another project, I realized that you can batch-unwrap objects onto the same UV in blender, meaning that they take up less space and accommodate for each other. If all of these batch-unwrapped objects were to have the same material, and therefore the same texture set in Substance, it would mean that I could condense information into one texture instead of many. To edit parts of a Texture set made up of many meshes, I could just use the poly selection tool in Substance as well as masks to create what's known as a texture atlas for that group, containing all of the texture detail of each individual object.
This would have been very beneficial when compared to my current approach. If I were to have consolidated many objects under one Texture set (e.g. robot parts or tentacles) I could have brought down my character's material count to single digits. Doing this would have meant greater efficiency in terms of game performance, reducing the load on the GPU. Unity is slowed when rendering many individual materials at once instead of just a few. To make up for loss of detail using the new approach I could export the maps at a higher resolution, which would impact performance some but likely far less than having to store and reference 20+ materials for one character. The new approach would also make project navigation in Substance Painter much less time consuming.
Due to other tasks taking up my time, I was unable to implement this new approach as it would have meant restarting the Robot unwrapping and Texturing process. However, I definitely would have given the time, for the benefit of our game's performance in VR. I'm just glad that I at least learned this in the first place and can apply this better method in future projects.
One of the things I did to mitigate the impact of performance of each material on our game was to re-export the Robot's textures at a much lower resolution. Previously, all were 2048 x 2048 pixels wide, which was overkill in hindsight. In Substance, I reduced the resolution of texture sets depending on physical scale and visibility in-game. Small meshes (like the fingers) had their texture size reduced to 256 pixels, and body parts got reduced to 512 pixels. The largest textures belonged to the Robot's chest plate and Tentacle Arm, which were set to 1024 pixels as they were the character's most prominent and largest meshes.
This wasn't a perfect solution, but it did at least reduce the amount of memory taken up by these materials 4 fold in places.
Overall, I learned a massive amount about modelling, UVs, Texture maps, render pipelines, and Substance Painter itself during this process. Considering that going into this I had no knowledge of any of this stuff, it has completely shifted my understanding of how to create and manage game assets.
References & Resources
Substance 3D. (2019). Substance | The leading software solution for 3D digital materials. [online] Available at: https://www.substance3d.com/
80.lv. (2019). Benefits of Procedural Materials. [online] Available at: https://80.lv/articles/benefits-of-procedural-materials/
Innocenti, U. (2019). Comparative Case Studies: Methodological Briefs - Impact Evaluation No. 9. [online] UNICEF-IRC. Available at: https://www.unicef-irc.org/publications/754-comparative-case-studies-methodological-briefs-impact-evaluation-no-9.html
Gdcvault.com. (2019). GDC Vault. [online] Available at: https://gdcvault.com/
Gdcvault.com. (2019). Texturing Uncharted 4: a matter of Substance (presented by ALLEGORITHMIC). [online] Available at: https://gdcvault.com/play/1023488/Texturing-Uncharted-4-a-matter
Gdcvault.com. (2019). 'Marvel's Spider-Man': A Deep Dive into the Look Creation of Manhattan (Presented by Substance). [online] Available at: https://gdcvault.com/play/1026495/-Marvel-s-Spider-Man
Substance. (2019). Blade Runner 2049’s Oscar-winning Texturing Workflow at Framestore. [online] Available at: https://store.substance3d.com/blog/blade-runner-2049-s-oscar-winning-texturing-workflow-framestore
Kevin O. (2019) Learn the ART of Substance Painter. Link: https://www.udemy.com/course/learn-the-art-of-substance-painter/