Creating Materials at runtime

I create Materials at runtime with this simple code:

public Material oldMat;

void CreateMat() {
     Material newMat = new Material(Shader.Find("Standard"));
     newMat.CopyPropertiesFromMaterial(oldMat);
}

The original material uses the standard shader and has albedo map (diffuse texture) as well as a normal map. A Debug.log reveals that these maps are copied correctly into the new material. However, when I assign the new material to a gameobject, only the albeda (main texture) shows up; The normal map only becomes visible after I expand (roll out) the material view in the inspector, making the whole procedure pointless because I naturally can’t do this while playing.

So, is this just a limit of Unity I have to live with? Kinda sad because runtime Material creating is very important to me :confused:

1 Like

The Unity Standard shader uses “#pragma shader_feature” to create multiple variants of the shader based on which textures are being used in the editor. To use the correct shader variant at runtime you should be able to use the “Material.EnableKeyword()” function to activate the right keywords for the textures you are using. The editor will set the keywords automatically for you. When you create a new Material at runtime, the keywords will all be disabled by default. If you wanted the normal map, you could activate that shader variant using Material.EnableKeyword(“_NORMALMAP”). You can get the right keywords from looking at the source for the Unity built-in shaders.

Keep in mind that “#pragma shader_feature” will only create the variants that are actually used in your game so if you try to activate a combination of keywords that aren’t used anywhere in your game, the shader for them won’t exist at runtime. You can switch “shader_feature” to “multi_compile” and Unity will exhaustively create all combinations of shaders, but that can take a lot of time to compile and will bloat your build. It’s best to decide which combinations you will need in advance and make sure those combinations are created for you.

3 Likes

This sounds like the same problem I just posted about: Material not updating - Unity Engine - Unity Discussions

That was exactly it. I had no textures assigned to the height/normal/metallic/occlusion maps, so that part of the shader wasn’t getting enabled. To fix it, I just assigned empty(white/gray/black) textures to the material at compile time.

Thank you kind sir, you helped me tremendously with your advice. I just added the lines

newMat.EnableKeyword("_NORMALMAP")
newMat.EnableKeyword("_DETAIL_MULX2")

after calling the CopyPropertiesFromMaterial() function and now it works as intended :slight_smile:

2 Likes