Whether you’re authoring your content in Unreal Engine, Unity, or another of the many modern game engines available today, the creation of Master Materials can be an effective way to help your art team get the most out of their work.
Master Materials are both powerful and supremely versatile. The following list is a collection of engine-agnostic best practices that will help shape your approach, speed up your work flow, and empower your art team to get the best possible result.
Before we get too much further, I’d like to provide just a little background on my attitude towards material/shader development. The nine tips listed below are those that I have identified from my own experience working as a technical and visual effects artist in a medium-sized development studio. They are the guidelines I personally follow when developing my own materials and shaders. I hope that they prove useful, but as every project has different technical and design requirements, your mileage may vary.
I work mostly in Unreal and Unity, so the advice within this article is necessarily going to be most applicable to those engines. There are some superficial (and some not so superficial) differences in material/shader implementation between Unreal Engine and Unity, and so to cast as wide a net as possible I have endeavored to provide practical examples from both wherever I can.
If you’re not too sure about the terminology I use in this article, or of the differences between how Unity and/or Unreal handles its graphics pipeline when it comes to shaders, check out my Material and Shader Terminology page for a more comprehensive breakdown. You’ll find answers on what exactly a shader is, how materials interact with them, and why some of these terms can get a little confusing.
I hope all of this explains a little more about where I am coming from, and my goals in writing this post. If you’re still unsure about something you’re properly not the only one, so please reach out and let me know. The more questions I receive, the better my understanding will become!
Let’s dive into these tips.
#1) Communicate with your team
Always try to keep in mind that a Master Material is simply another tool, and it’s an aid for your art team. Whether that team is dozens of people, just one or two, or even just you yourself, the goal should be to elevate and refine their process and help them make the best art possible. Just like any other tool at their disposal, if things don’t work as expected it’s going to slow the whole process down and cause more than a little frustration.
Therefore, a practical Master Material needs to not only look good and provide the features your artists expect, but it also needs to be intuitive and designed towards achieving their specific goals. To properly understand what those goals are you need to talk to your art team. Ask questions, and find out what’s important to them.
Here are some examples of discussion starters you can try. Ask yourself these questions too – your opinion matters!
- How many versions of this shader will there be, and is that enough to justify the creation of a master material?
(Or, if asked in a different way: Is a Master Material really necessary here?)
- What specific material features would you like to use?
- Which of those material features are the most important to you, and which are you most comfortable in using?
- What input properties are you expecting?
- How would you like the shader/material to be organized?
- Are there any specific naming conventions you’d like followed?
- Are there particular limitations (skill, technical, or even design-related) that I need to be aware of?
- Can you provide some examples of practical use cases for this material?
These questions will hopefully give you some valuable insight into how your team wants to work with you. Artists have the tendency to be very opinionated about their workflow, so expect them to bring ideas to the table as to how they want their tools to work.
You should also anticipate the odd contradictory and/or impractical request, and know how to communicate why you believe they’re not feasible. As a technical artist you’re also an advocate for the technical limitations of the project, and since you’ve got a foot in both camps that balancing act is always something you’ll need to deal with.
It’s always a good idea to solicit feedback wherever and whenever you can. It will make you a better technical artist, and at the very least it shows a level of respect for those with whom you’ll be closely collaborating.
#2) Understand the impact on performance
Depending on how they are designed, Master Materials can have a significant impact on performance. By necessity they are more intricate and complicated than their static equivalent, and unless a Material Instance (Unreal) or Material (Unity) is using every single feature of the Master then you might have shader code being compiled, calculated, and stored in memory that is just taking up space.
For example, this Unreal Engine Material Instance is using a Master Material that has a range of features, including the capacity to do world displacement using a height map texture. Even though the instance isn’t using them, they’re still there behind the scenes taking up space because they could be used at any time. You can imagine, if we multiple this problem by the thousands of materials you might have in your game world, this has the capacity to hit your framerate quite hard.
There is a way to reduce this impact and that’s through the use of logic gates, although this also has an associated cost. Put simply, if we ‘gate’ a chunk of our shaders/materials, we are able to toggle them on/off as required. Keep in mind that this will force a recompile of the shader, and although this isn’t a cost we have to pay at runtime, using many logic gates will create a lot of shader permutations.
In Unreal this functionality is found in Switch Nodes. There are a few different types, but the one you’re looking for is called a Switch Parameter.
In Unity this is a little trickier, because the Shader Graph equivalent of the Switch, the Branch node, is designed to work at runtime. That means the entire graph is being compiled no matter what, which isn’t what we want. Luckily, you can get the same functionality as an Unreal Switch in the Shader Graph by creating a simple single-line Custom Function. Check out this post by Exiin for more information, and a guide on how to implement it yourself.
#3) Take a modular approach
Shaders can get complicated very quickly (this is starting to become a catchphrase of mine), and within node-based editors like Unreal’s Material Editor or Unity’s Shader Graph, they can become unmanageable before you know it.
A really good way to combat this issue (and the node spaghetti that usually follows) is to take a modular approach to its design. This involves separating the Material into logical subsections based on their purpose, similar to a programming design method called the separation of concerns.
This approach relies heavily on Material Functions (Unreal) and Shader Sub-graphs (Unity), self-contained collections of nodes that can be dropped into your graph as many times as you need.
In this Unity Shader Graph example we are using two sub-graphs (SG_BaseColor and SG_Opacity), each of which contain their own graph of nodes. Keeping these separate but interlinked sections of the shader in their own sub-graphs makes it much easier to read, maintain, and extend as things get more complicated.
#4) Only add features when you need them
With the amazing power of a modern game engine at your fingertips, it goes without saying that it can be very easy to get carried away. Try to reign yourself in when it comes to adding features that have not been specifically asked for, even if they’re really cool or ‘complete’ the shader.
Every line in your shader, or node in your material, comes with an associated cost. Complexity for complexity’s sake isn’t a good idea for a few reasons.
For starters, it will objectively make your game run slower. If your amazing ‘one size fits all‘ shader supports everything from tessellation/world displacement to subsurface scattering, that’s great – but if no one is using those features then you’re just wasting time and resources. This is particularly relevant if your performance budget is tight.
Another thing to keep in mind is that the more parameters you add, the trickier your material will become to use in actual development. No one wants to have to sift through dozens of slightly different scalar variables to make adjustments to a material surface.
As a general rule you should shoot for a material with the fewest possible parameters that still achieves your goal.
#5) All material features should be opt-in
This is a UX-related tip that will hopefully make those who use your material have an easier and more enjoyable experience. Try to make sure that as much as possible, features of your material need to be toggled on before they have a visual and performance impact.
The idea here is that when an artist assigns your shader to a new material, or creates a new instance of your Master, they will always start with a blank slate from which they can add the components they need, and only the components they need.
This kind of behaviour can be achieved through the use of logic gates, which we discussed above. As I mentioned there, these have their own impact on the number of shader permutations that need to be compiled, but in this case I am happy to sacrifice a little performance to make my material a lot easier to work with.
#6) Collapse commonly used node groups
In the same way we use Shader Sub-Graphs/Material Functions to keep our concerns separated, we should also keep an eye out for commonly used groups of nodes that can be collapsed into a single node for organizational reasons.
For example, I found I used this series of nodes a lot throughout my material to handle texture coordinate tiling/offset, so I made it into a Material Function.
If you find yourself copy pasting chunks of nodes around, it’s probably time to make it a Function/Sub Graph. It’s just so much neater that way.
#7) Keep your properties named and ordered logically
Both Unity and Unreal let you categorize and name your material properties. Taking advantage of this, and giving your properties both readable and logical names, will make the experience of using your material so much better.
It really doesn’t matter what conventions you use as much as it matters you have a convention and you stick to it. Try to approach this from the point of view of someone who is using your material. What are their needs? Where would they look for certain properties, and what would they call them?
#8) Test. Test. Test.
This last tip is easy in principle, but a lot of people (myself included at times) neglect it.
As a technical artist you may find yourself working on tools far more than you end up using them. The danger here is that you end up making decisions based on what’s convenient (or what’s exciting/interesting) to you personally, and you lose sight of why you’re making the tool in the first place: To support your art team, and help them achieve the best possible result from their work.
To avoid this trap, make sure you test your material and get some feedback. Jump into one of your project’s maps and apply some textures. Play around, but make sure what you’re testing is a practical use-case. One insightful way to trial your Master is to try reproducing an earlier material/shader that is more static. Does it look different, and why?
It’s only through testing that you’ll find the flaws in your work. Then you can fix them before anyone else notices they’re there.
Thanks a lot for reading. I hope these tips prove helpful to you in your own projects. They certainly have with mine.
The creation of Master Materials has become a contentious topic. When Unreal Engine 4 was factory fresh there was a boom in the study and development of huge materials that could do everything under the sun, but in recent years I’ve felt a bit of a backlash against them and the significant performance impacts they can often incur.
I strongly believe well-planned and implemented Master Materials still have a place in the pipeline, and I will continue to refine my approach to emphasize their strengths and minimize the drawbacks. If you have any questions, comments, or just want to tell me I’m wrong about everything, I’d love to hear from you.
Let’s talk – and make our tools better.