Creating one master material for the whole game.

From what I know, the more materials you create the more draw calls you need to render them. Wouldn’t it be therefore more efficient to have multiple meshes create dynamic instances at runtime of that one material and just set various properties then using dynamic parameters (texture, scalars, vectors, etc)? In a lot of cases for example you might be creating a lot of materials for static meshes where the only thing you set is a texture to base color, but because these are individual materials and not dynamic instances the engine will have to dump state for the current material before processing the new one which is slow. I’m saying this because I read from another post that the engine orders objects to render by material as instanced materials don’t need to dumb state before rendering the next slightly altered material which saves processing time.

I hope I didn’t word that too poorly, but to put it concisely: is it more efficient to use one material for several meshes if I can set the parameters I need at runtime with dynamic instances?

From my amateur graphics programming knowledge, I understand it like this: Under the hood, each material generates a custom vertex, geometry and pixel shader for each type of object the material can be applied to like static mesh, skeletal mesh, landscape etc. Material instances represent different sets of parameters for the same shader code. In your material you can have parameter nodes which are fed to the gpu before each material instance is rendered, rather than being baked into the shader code itself like a constant node. So if you have a bunch of meshes that are all the same just with different diffuse, normal and specular textures you could use TextureSampleParameter2D rather than a fixed TextureSample node, and override the textures in a MaterialInstance asset. You don’t need to use dynamic material instances unless the material parameters actually need to change during runtime, instead just use a MaterialInstance asset.

When multiple meshes have different base materials, all the shaders and parameters for each material need to be changed between drawing them which can be slow. If they have the same base material with different instanced parameters, only the parameters need to be updated between drawing, which is much faster. And if they have the same material and parameters, then nothing needs to be updated and drawing is even faster. So basically yes, use as few Materials as possible and use MaterialInstances whenever you can. But don’t overload the material with tons of extra features that only some instances use, you pay the full price of all nodes in a material even when you can’t see their visual effects. So for example don’t include a grunge texture slot in your base material when you’re applying it to one dirty wall and 100 clean looking walls. Instead split it into two base materials, one with a grunge texture sampler and one without.

I saw this thread and was reminded of a rather longwinded reply I sent to somebody asking the same question a few months ago.

The tl:dr version: it may give you a small perf gain to share materials, but just do whatever is the easiest for your workflow and don’t try to make the material too crazy or you will bog yourself down debugging it etc. Also it doesn’t make it any faster if its a material instance dynamic versus material instance constant (meaning and instance you make by hand).

It would probably take a mathematician to find to absolute point at which adding to a master material becomes counter productive. It doesn’t take long before the permutations are in the trillions and it depends on how the flags are actually used in determining savings. In theory every instance could be unique and thus wouldn’t get any benefit from the shared master.

In general it is wise to break things up before the master material becomes too complex since as you guessed there can be a large tech-debt to understanding complex master material when artists have to wade through mostly options that do not apply to them. And once the combinations climb into the trillion, there could actually exist combinations that do not work nicely that you have a lower chance of discovering. So debugging could become a challenge and it may not be super efficient but other than that there is nothing stopping you from making a whole game using one material. Gears 1 and 2 used the same master material for maybe 50% of the assets but there were always people whod rather just use their own materials either because they wanted to, or the master material scared them.

There is no right or wrong way to break up the material. But you have to ask yourself what is the benefit of sharing the master material. If you are talking about mostly world geometry, master materials can be useful since they unify the way things are done. Ie, every ‘cracked wall’ material in your level would ideally use the same master material. Then you might want to also share the same crack system for floors and other types of stone as an example. That is the perfect use case for expanding a material’s functionality IMO…

But does it make sense to try to jam translucency FX options into the same master material? Technically the engine will let you do that now that you can override blend mode via instances. I would recommend against doing it though. Doing that wouldn’t give any savings since the translucent instances would need their own compiled shaders anyways so you likely just made the base master shader more complicated for no reason and it added to the time artists spend making the simple crack floor material.

So in general I would break up the master materials light based on what they do in the world. If you can get away with one single type for your whole environment, more power to you. But I would not let such a system add any limits to your creativity. There may be lots of neat little effects that you can only achieve by radpidly knocking out unique materials that would take too much time to smartly integrate into a huge master material.

When it comes to doing things that affect the game in multiple areas, we have started using a slightly different approach where we really on Material Functions that are designed to be used anywhere using the Material Attributes pin. So even if we use a few different base shaders for our various enemies, they all get the same material function for doing some of the FX hookups. So that is kind of a different way of breaking things up and using functions to define the common ground. Another similar cases exists with Material Parameter Collections. You can sometimes use a handful of MPC values to avoid doing constant updates to lots of MIDs.

Keep in mind that the point at which a shader goes “too far” in the options department can approach quickly, so sometimes the only way to know you went too far is when artists start complaining they don’t understand it. Hopefully you can work with the artists and gauge their tolerance for shader shenanigans before that happens.

I hope this helps.