Michail Mavronas told us about making these gorgeous materials in ZBrush and Substance Designer and explained how Unreal Engine 5 makes the workflow easier.
In case you missed it
You may find these articles interesting
Introduction
My name is Michail Mavronas and I am currently the Lead Artist at Rogue Sun in Guildford, UK. I am originally from the island of Corfu in Greece and I have been working in the games industry for the past 12 years. I was initially a self-taught artist studying a course in Music and sound design. Soon after my graduation, I decided to change paths and join the games industry as a 3D artist. During the recent past, my work has mainly gravitated towards VR, with the two racing titles Radial-G and Radial-G: Proteus.
I am here today to talk about my abstract work in Substance Designer and showcase a simple way we can use the pixel processor to obtain interesting results. We are also going to take a step further and render our final substance outside of SD using ZBrush and Unreal Engine 5.
Getting Into Material Creation
I first got into Substance Designer around 2015. This was around the same time I started working in UE4 which exposed me to the magic of node-based material creation. At this point, SD became an indispensable resource for generating materials and VFX. It provided an amazing level of flexibility in generating “support” textures for shaders such as gradients, noise textures, Normal Maps, etc.
What really inspired me to continue learning Designer was the amazing work from the artist Daniel Thiger. Especially the look achieved in his final presentations convinced me to look at SD from a slightly different angle. I started treating SD from the perspective of generating concept materials during the early stages of look development. These “concept” PBR materials would then drive the art direction process alongside any other piece of concept art.
In the following example from my personal work, I was working on a sand material in Designer. This resulted in an alien and colorful landscape that inspired me to create my portfolio piece, Wasp. Even though I designed the ship in parallel, the final texture and few of the elements on the model were directly inspired by the aesthetic and dynamics of the substance material.
Abstract Materials
As an artist, I often draw inspiration from the works of Moebius, Enki Bilal, H.R Giger, and Katsuhiro Otomo. I always loved the aesthetic of advanced but age-worn technology and I wanted to investigate this style through Substance Designer.
Somewhere along the way, I decided to focus more on the overall composition and feel of a material rather than the recreation of specific items. In some ways, you can consider the result to be pieces of R&D with an artistic outlook. Even though the nature of these designs is abstract, I still try to think and work as a 3D artist. I am investigating composition, lighting PBR shading and I still work towards creating a final presentation.
Techniques
I often look at techniques that I learned in the material editor in Unreal and try to apply them within the pixel processor in Substance Designer. The pixel processor can actually be an extremely powerful tool even with simple math operations. On our main presentation graph, I am going to be driving most of the generated shapes through a custom pixel processor node. So before we dive into the main graph I would like to explain a bit about the technique and also give you an example of how we can practically use this.
The technique is actually fairly simple. We are essentially processing an input gradient through a sine node. This will practically force the sine to plot along with the gradient values. The abs node is then used to return any negative values to positive, visually closing the gaps that would normally appear when a sine goes below 0. Multiplying the input gradient prior to the sine will increase the sine frequency, essentially increasing the amount of visible “folds”.
For those who are interested in the Unreal Engine side of things, it’s worth noting that you do not need to multiply with Pi to achieve the same result. This is most likely due to a different implementation of the sine node.
With our basic pixel processor complete, we can now create any kind of gradient and run it through the node. This technique is really useful in generating parallel cables, pipes, and ornaments. In this following example, I used the main sine function and a shape mapper to create a simple ornament that could be used as part of a design or even exported as an alpha for a custom brush in ZBrush. In order to make things easier, I created a new input for the pixel processor which is then referenced inside the function. This allowed me to control the number of “folds” without having to edit the pixel processor in a new window.
These simple math functions can also generate base patterns that can lead to interesting designs. The resulting shapes are easy to iterate and they can be used in wallpapers, floors, or textiles and they can even provide inspiration for HUD and UI elements.
Generating the Initial Pattern
In order to discuss the process used in my more abstract work, I wanted to create something new for the 80 Level showcase. My previous R&D work on the Sine Circuit example was perhaps a bit too generative to be used as a case study. This time I wanted to create a design with more structure so I started by setting some ground rules. I decided that I would focus on a few strong overarching shapes and deliver something reminiscent of an Alien movie wall panel. The process began by focusing on a large central element similar to a Celtic cross as my basic shape.
Main Shape
I started the graph by laying down the basic element for my cross shape and then ran the resulting gradient through the pixel processor. Initially, this produced a “planar” set of parallel features. In order to get more elevation on the overall shape, I created a secondary bevel and blended the two together. Most of the shapes that follow will use the same technique in order to “extrude” the surface and allow for varying elevations throughout the tile.
Creating Relationships
At this stage, it was important to add an element that would generate a relationship between my main shapes. One thing that is really useful when dealing with abstract designs is to create a correlation between the larger shapes early on. In order to achieve this, I duplicated the main shape and then created a tile half the size. This trick immediately added detail and created a relationship between these two primary elements.
As a third step, I wanted to add an element that would give the feeling of a support structure to the overall design. So I decided to build an X-shaped frame. Initially, the result of the “X” meeting at the center didn’t look right so I broke the shape apart with a ring. The ring was then duplicated and scaled with the addition of some smaller canister-looking elements.
At this stage, all the three primary shapes were brought together in the Height Map. This created the core design that will be used to drive the rest of the substance forward. As we can see from the image below I now have distinct areas that are busy and others that are completely empty. From this point onwards the process will be 100% “additive”. I will follow the flow of the shapes and add elements in different areas to create a more intricate design.
Additional Shapes
The sine process worked well on the previous shapes so I decided to build on that and generate the following shapes with a truchet pattern. In order to avoid the randomness of a truchet tile, I used two mirror nodes to create a symmetrical design that would better match the larger shapes. I ended up making three different truchet patterns that were then used to fill different height areas. A high-frequency tile for the gaps at the base, a mid-size pattern at a center height, and a wider pattern that was eventually placed at a lower level height.
If you want more information on this technique please have a look at my work Xenotile-III.
Outer Frame
At this stage, I noticed that adding an edge frame would help to bring things into focus. In our case, it also created a support structure for the larger X-frame. The frame actually has three components. An outer frame, an inner frame, and a corner piece.
The final step was to generate a few more “filler” shapes. I made a large circle to provide some additional height to the midsection, a mask to cover some smaller gaps, and a new cross shape that was placed at the very base of the Height Map.
Bringing Everything Together
Blending Height Layers
One thing to note is that blending the height between shapes required quite a bit of iteration. As is often the case, these intricate patterns can become fairly busy right from the start. Multiple pipe-like structures can especially become challenging to blend in different height layers. This is the reason why at the very start I decided to combine the parallel lines with a beveled version of the same shape. The bevel gradients allowed me to adjust the height where different elements meet and produce far cleaner results.
In an ideal production environment, it is preferable to split each element into subgraphs and rebuild the graph with the new components. This will not only optimise the graph itself but it will also allow for easier navigation and overall control in your graph(s).
Color
For the color, I wanted to add something reminiscent of copper. I really wanted to focus on the flow of the design so I decided to go for a basic two colour scheme. We have a primary copper color with brighter worn parts and a cyan base mainly for the underlying elements. The “copper color” was also multiplied with a reddish AO pass to add some variation. In the end, I also added a dirt and highlight pass based on the curvature and a couple of dirt mask generators. The same dirt masks were also used for the roughness and metallic outputs.
Normals
The normals were mainly based on the Height Map with the addition of a subtle scratch generator. I felt that the design was already too busy so avoided adding stronger damage elements.
Roughness & Metallic
For the Roughness and Metallic, I kept it simple and gave it an overall dusty look. I based my Roughness on a base grayscale color and modified it with a Grunge Map. I then added an inverted AO Map to represent roughness in crevices prior to adding the dirt masks created earlier. The Metallic Map was created in a similar but slightly simpler way.
Emissive
Finally, I created an emissive mask for that classic sci-fi look. Here, I needed to generate a series of blend nodes based on our primary shapes. This was necessary to isolate the gaps alongside the high-frequency details present at the base of the Height Map.
The Final Graph
Rendering
I usually render most of the final substances in designer with iRay, but in the spirit of R&D, we are going to have a look at getting our final render in UE5 using Nanite.
Textures
For the main material in UE5, I exported 3 main Maps, the base colour texture, the Normal Map and a PBR mask combining the AO, Roughness and Metallic channels. These were exported as Targa files at 8K resolution. In preparation for ZBrush, I also exported the base colour texture and a 16-bit 8K Height Map as PSD files.
Base Mesh
The base mesh was prepared in Maya. I created a 2m by 1m curved plane with a high subdivision level at 250K triangles. Our texture is also tiling twice across the surface. The curved geometry will allow us to be more creative in our final composition.
ZBrush
The base mesh was then imported into ZBrush and subdivided to roughly 8 million points. After importing the base Color and Heigh Map PSDs I extruded the mesh with the Displacement Map feature in ZBrush. I then decimated the mesh down to 5 million points and exported it as a .fbx file. Optimizing the mesh helped to speed up iterations and also lowered the fbx file size which was 360MB.
Unreal Engine 5
The setup in UE5 was fairly simple, I imported the mesh and enabled Nanite in the import settings. I then created a basic PBR material and used 3 instances to vary the emissive values across the scene.
The level was built by duplicating the nanite mesh and creating a tunnel-like structure. One of the challenges here was the fact there are no defined light sources in the scene other than the emissive areas. To solve this, I added quite a few point lights across the level. This helped me to achieve more localized lighting and build the overall mood. I then added a Volumetric Height Fog and adjusted the levels to fit the overall composition.
For the final pass, I added a post-process volume. I adjusted the levels and added bloom, lens flare, and vignette effects. The final render was done at 4K with a Cine camera animated in a level sequencer.
Final Presentation
Challenges
Sometimes the results of procedural patterns can be too generative and it can take multiple iterations in order to get a usable design. In this case, I managed to avoid this by deciding on some central features right at the start.
The main challenge for this graph was blending the height of multiple pipe-like layers. These shapes were continuous across the tile and that generates a few blending issues. I had to create additional masks and subtract areas of the shapes with each other prior to using a height blend node. The additive process also creates a level of complication that makes optimization a bit hard when working on the graph.
Customizing Substances
Procedural patterns like these can have quite a large number of iterations due to the fact that all the elements of the pattern can be generated from a single shape node. In our case, I am using 3 basic shapes that are controlled by multiswitch nodes. Changing the input selection will result in a change across the entire pattern. There is a slight limitation due to the truchet patterns but with some adjustment, we could improve the iterations on that part as well.
Useful Tutorials
Substance Designer can appear a bit daunting at first so it is always good to work with some real-life reference in mind. In many ways, you can treat it in a similar way to modeling in a 3D package. We might be using masks and heightmaps instead of vertices but it is important to plan ahead and break down your reference into individual elements.
As a beginner, it is always good to start with a simple material such as a cracked stone floor tile. This will give you a good introduction to the various nodes and blending techniques. After that, you can move to something a bit more complex such as a train track or a pavement. This will teach you how to combine elements with different shapes and materials.
If you are interested in more advanced techniques using the pixel processor I would strongly recommend following the Facebook group Inside the node which is organized by the extremely talented Andrei Zelenco and Marco Vitale. The group often hosts mind-blowing work from various members and shares useful information and tutorials in relation to more programmatic techniques in Substance Designer.
Afterword
I enjoyed working on this presentation piece quite a lot. The most exciting part was the final stage of importing the high-resolution mesh in ZBrush and UE5. It made me wonder about the future possibilities outside the scope of rendering a simple substance tile. Being able to generate and use this kind of dense procedural meshes also means that we get a much higher resolution on vertex colors and vertex painting. This could prove quite interesting in terms of shading and material generation exclusively within the engine.
Finally, I would like to thank 80 Level for the opportunity to showcase my work and I hope that my presentation will be useful to artists that want to take a further look into Substance Designer. You can view more of my works on my ArtStation page.
Michail Mavronas, Lead Artist
Interview conducted by Arti Sergeev
Keep reading
You may find these articles interesting