Modify materials at runtime to avoid their multiplication

I have a material that can either take a texture or a simple parameter as roughness/metallic/normal inputs, which makes 8 combinations.
Do I have to create 8 materials, or is there a way to have a single material that I can change and rebuild?

In GLSL I would simply use a bunch of #define and #ifdef to achieve this. Is there something similar?

You could use a static switch node, but be aware that the shaders for all permutations still get built. So dont overdo it.

Errrr… hmmmm… Roughness…Ok. Metallic, also ok… but what should a simple parameter do for a normal input :confused:

BTW: You could also take a texture parameter and multiply it with a vector parameter.
if you want to use the texture, set the vector parameter to 1/1/1 and if you want to use a vector value, sample a small white dummy texture (2x2 pixels is enough :D) and then set the vector value as desired…

This shouls be the cheapest vertsion…

Thank you, this is what I was looking for.

We will not make these textures for every object, so the parameters are there as a fallback. For the normal I just input nothing instead of the texture.

Well I don’t want to sample textures for nothing, that sound like a waste, through 2x2 is probably negligible. I will need the static switch for other things than texture anyway, but ill keep in mind the permutations builds you pointed out, thanks.

It is indeed. And far less consumptive than static switches.

I don’t understand this. Isn’t the static switch executed once when the shader is built, while sampling the texture is done every frame?

Well, in a way yes. But when the shaders are built, all are built. This can lead to “shader explosion”.
So in your case, with three static switches, shaders for all 8 combinations are built.
But now imagine you are layering that material up with others that also use static switches…

See the documentation note on this: https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/ExpressionReference/Parameters/index.html#staticboolparameter

Ok I see your point, thanks.

It turns out that Static Switch work with UMaterialInstanceConstant, but not UMaterialInstanceDynamic, unless I am missing something?
I use UMaterialInstance::UpdateStaticPermutation, but there is a check(IsA(UMaterialInstanceConstant::StaticClass())) in the way.

“On the other hand, a new version of the material must be compiled out for every used combination of static parameters in a material”

Important distinction. So you end up exact same amount of different materials anyway.

Edit: Sometimes you can save great amount of ALU’s by skipping some textures. Example would be normal map. If you use normal mapping then UE4 have to send normal, tangent and bitangent from vertex shader and transfrom tangent space normal from normal map to worldspace and store to gbuffer. Without normal mapping you just need to send world space normal from vertex shader and then store that to gbuffer. You can also skip decoding normal from BC5 texture. When it make sense always use static swithces.