Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Instance Material Parameters

Discussion in 'Scripting' started by nrvllrgrs, Dec 22, 2013.

  1. nrvllrgrs

    nrvllrgrs

    Joined:
    Jan 12, 2010
    Posts:
    62
    In order to minimize the number of materials that are only used for a unique GameObject, I created a script called InstanceMaterialParameters. This scans all of the materials on a GameObject and allows you to overwrite the default material parameters:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6.  
    7. [System.Serializable]
    8. [RequireComponent(typeof(Renderer))]
    9. [AddComponentMenu("Graphics/Instance Material Parameters")]
    10. public class InstanceMaterialParameters : MonoBehaviour
    11. {
    12.     [SerializeField]
    13.     public List<MaterialParameterInfo> MaterialParameters;
    14.    
    15.     void Start()
    16.     {
    17.         if (MaterialParameters == null)
    18.         {
    19.             return;
    20.         }
    21.  
    22.         foreach (MaterialParameterInfo info in MaterialParameters.Where(x => x.Color.HasValue))
    23.         {
    24.             renderer.materials[info.Index].SetColor(info.Name, info.Color.Value);
    25.         }
    26.  
    27.         foreach (MaterialParameterInfo info in MaterialParameters.Where(x => x.Vector.HasValue))
    28.         {
    29.             renderer.materials[info.Index].SetVector(info.Name, info.Vector.Value);
    30.         }
    31.  
    32.         foreach (MaterialParameterInfo info in MaterialParameters.Where(x => x.Value != null))
    33.         {
    34.             switch (info.Value.GetType().ToString())
    35.             {
    36.                 case "Float":
    37.                     renderer.materials[info.Index].SetFloat(info.Name, (float)info.Value);
    38.                     break;
    39.  
    40.                 case "Texture":
    41.                     renderer.materials[info.Index].SetTexture(info.Name, (Texture)info.Value);
    42.                     break;
    43.             }
    44.         }
    45.     }
    46.  
    47.     [System.Serializable]
    48.     public class MaterialParameterInfo
    49.     {
    50.         public string Name;
    51.         public int Index;
    52.         public object Value;
    53.  
    54.         public Color? Color;
    55.         public Vector4? Vector;
    56.     }
    57. }
    58.  
    Code (csharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Linq;
    7.  
    8. [System.Serializable]
    9. [CustomEditor(typeof(InstanceMaterialParameters))]
    10. public class InstanceMaterialParametersEditor : Editor
    11. {
    12.     void Awake()
    13.     {
    14.         InstanceMaterialParameters value = (InstanceMaterialParameters)target;
    15.         if (value.MaterialParameters == null)
    16.         {
    17.             value.MaterialParameters = new List<InstanceMaterialParameters.MaterialParameterInfo>();
    18.         }
    19.     }
    20.  
    21.     public override void OnInspectorGUI()
    22.     {
    23.         InstanceMaterialParameters value = (InstanceMaterialParameters)target;
    24.  
    25.         if (value.renderer == null)
    26.         {
    27.             return;
    28.         }
    29.  
    30.         Material[] materials = value.renderer.materials;
    31.         for (int materialIdx = 0; materialIdx < materials.Length; materialIdx++)
    32.         {
    33.             EditorGUILayout.BeginToggleGroup("Material " + materialIdx + " Parameters", true);
    34.  
    35.             Material material = materials[materialIdx];
    36.             Shader shader = material.shader;
    37.  
    38.             int count = ShaderUtil.GetPropertyCount(shader);
    39.             for (int propertyIdx = 0; propertyIdx < count; propertyIdx++)
    40.             {
    41.                 string name = ShaderUtil.GetPropertyName(shader, propertyIdx);
    42.                 InstanceMaterialParameters.MaterialParameterInfo info = value.MaterialParameters
    43.                     .FirstOrDefault(x => x.Name == name  x.Index == materialIdx);
    44.  
    45.                 if (info == null)
    46.                 {
    47.                     info = new InstanceMaterialParameters.MaterialParameterInfo()
    48.                     {
    49.                         Name = name,
    50.                         Index = materialIdx
    51.                     };
    52.                     value.MaterialParameters.Add(info);
    53.                 }
    54.  
    55.                 switch (ShaderUtil.GetPropertyType(shader, propertyIdx))
    56.                 {
    57.                     case ShaderUtil.ShaderPropertyType.Color:
    58.                         if (!info.Color.HasValue)
    59.                         {
    60.                             info.Color = material.GetColor(name);
    61.                         }
    62.  
    63.                         info.Color = EditorGUILayout.ColorField(name, info.Color.Value);
    64.                         material.SetColor(name, info.Color.Value);
    65.                         break;
    66.  
    67.                     case ShaderUtil.ShaderPropertyType.Vector:
    68.                         if (info.Vector.HasValue)
    69.                         {
    70.                             info.Vector = material.GetVector(name);
    71.                         }
    72.  
    73.                         info.Vector = EditorGUILayout.Vector4Field(name, info.Vector.Value);
    74.                         material.SetVector(name, info.Vector.Value);
    75.                         break;
    76.  
    77.                     case ShaderUtil.ShaderPropertyType.Float:
    78.                         if (info.Value == null)
    79.                         {
    80.                             info.Value = material.GetFloat(name);
    81.                         }
    82.  
    83.                         info.Value = EditorGUILayout.FloatField(name, (float)info.Value);
    84.                         material.SetFloat(name, (float)info.Value);
    85.                         break;
    86.  
    87.                     case ShaderUtil.ShaderPropertyType.Range:
    88.                         if (info.Value == null)
    89.                         {
    90.                             info.Value = material.GetFloat(name);
    91.                         }
    92.                    
    93.                         float min = ShaderUtil.GetRangeLimits(shader, propertyIdx, 1);
    94.                         float max = ShaderUtil.GetRangeLimits(shader, propertyIdx, 2);
    95.                         info.Value = EditorGUILayout.Slider(name, (float)info.Value, min, max);
    96.                         material.SetFloat(name, (float)info.Value);
    97.                         break;
    98.  
    99.                     case ShaderUtil.ShaderPropertyType.TexEnv:
    100.                         if (info.Value == null)
    101.                         {
    102.                             info.Value = material.GetTexture(name);
    103.                         }
    104.                        
    105.                         info.Value = EditorGUILayout.ObjectField(name, (Texture)info.Value, typeof(Texture), true, GUILayout.Height(60)) as Texture;
    106.                         material.SetTexture(name, (Texture)info.Value);
    107.                         break;
    108.                 }
    109.             }
    110.             EditorGUILayout.EndToggleGroup();
    111.         }
    112.  
    113.         if (GUI.changed)
    114.         {
    115.             EditorUtility.SetDirty(target);
    116.         }
    117.     }
    118. }
    119.  
    It works as intended; however, the editor does report the following error: Instantiating material due to calling renderer.material during edit mode. This will leak materials into the scene. You most likely want to use renderer.sharedMaterial instead..

    Other than this report, are there reasons why I should not use this script? Also, if there are suggestions how to improve this script (e.g. updating the MaterialParameter list when the materials change), please let me know.