Search Unity

Creating Materials at runtime

Discussion in 'General Graphics' started by Cherno, Apr 4, 2015.

  1. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    I create Materials at runtime with this simple code:

    Code (csharp):
    1.  
    2. public Material oldMat;
    3.  
    4. void CreateMat() {
    5.      Material newMat = new Material(Shader.Find("Standard"));
    6.      newMat.CopyPropertiesFromMaterial(oldMat);
    7. }
    8.                            
    9.  
    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 :/
     
    dylan-hart likes this.
  2. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    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.
     
    CTN-Originals, Jabob1 and pahe like this.
  3. vatara

    vatara

    Joined:
    Feb 26, 2010
    Posts:
    22
  4. vatara

    vatara

    Joined:
    Feb 26, 2010
    Posts:
    22
    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.
     
  5. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Thank you kind sir, you helped me tremendously with your advice. I just added the lines
    Code (csharp):
    1.  
    2. newMat.EnableKeyword("_NORMALMAP")
    3. newMat.EnableKeyword("_DETAIL_MULX2")
    4.  
    after calling the CopyPropertiesFromMaterial() function and now it works as intended :)
     
    Hysim140614 and CTN-Originals like this.