using UnityEngine; namespace UnityEditor.Rendering { /// /// Provides a set of extension methods for storing, retrieving, and setting expandable states of areas in a . /// Additionally, these extensions facilitate handling of various shader property drawers within the editor. /// public static class MaterialEditorExtension { #region Set of extensions to allow storing, getting and setting the expandable states const string k_KeyPrefix = "CoreRP:Material:UI_State:"; /// /// Obtains if an area is expanded in a /// /// /// The mask identifying the area to check the state /// Default value if is key is not present /// true if the area is expanded internal static bool IsAreaExpanded(this MaterialEditor editor, uint mask, uint defaultExpandedState = uint.MaxValue) { string key = editor.GetEditorPrefsKey(); if (EditorPrefs.HasKey(key)) { uint state = (uint)EditorPrefs.GetInt(key); return (state & mask) > 0; } EditorPrefs.SetInt(key, (int)defaultExpandedState); return (defaultExpandedState & mask) > 0; } /// /// Sets if the area is expanded /// /// /// The mask identifying the area to check the state internal static void SetIsAreaExpanded(this MaterialEditor editor, uint mask, bool value) { string key = editor.GetEditorPrefsKey(); uint state = (uint)EditorPrefs.GetInt(key); if (value) { state |= mask; } else { mask = ~mask; state &= mask; } EditorPrefs.SetInt(key, (int)state); } static string GetEditorPrefsKey(this MaterialEditor editor) { return k_KeyPrefix + (editor.target as Material).shader.name; } #endregion #region Set of extensions to handle more shader property drawer static Rect GetRect(MaterialProperty prop) { return EditorGUILayout.GetControlRect(true, MaterialEditor.GetDefaultPropertyHeight(prop), EditorStyles.layerMaskField); } /// /// Draw an integer property field for a float shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property /// Optional function to apply on the new value public static void IntShaderProperty(this MaterialEditor editor, MaterialProperty prop, GUIContent label, System.Func transform = null) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; int newValue = EditorGUI.IntField(GetRect(prop), label, (int)prop.floatValue); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { if (transform != null) newValue = transform(newValue); prop.floatValue = newValue; } editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); } /// /// Draw an integer slider for a range shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property public static void IntSliderShaderProperty(this MaterialEditor editor, MaterialProperty prop, GUIContent label) { var limits = prop.rangeLimits; editor.IntSliderShaderProperty(prop, (int)limits.x, (int)limits.y, label); } /// /// Draw an integer slider for a float shader property. /// /// /// The MaterialProperty to make a field for /// The value at the left end of the slider /// The value at the right end of the slider /// Label for the property public static void IntSliderShaderProperty(this MaterialEditor editor, MaterialProperty prop, int min, int max, GUIContent label) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; int newValue = EditorGUI.IntSlider(GetRect(prop), label, (int)prop.floatValue, min, max); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { editor.RegisterPropertyChangeUndo(label.text); prop.floatValue = newValue; } editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); } /// /// Draw a property field for a float shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property /// The minimum value the user can specify public static void MinFloatShaderProperty(this MaterialEditor editor, MaterialProperty prop, GUIContent label, float min) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; float newValue = EditorGUI.FloatField(GetRect(prop), label, prop.floatValue); newValue = Mathf.Max(min, newValue); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) prop.floatValue = newValue; editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); } /// /// Draw an vector3 field for a vector shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property public static void Vector3ShaderProperty(this MaterialEditor editor, MaterialProperty prop, GUIContent label) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; var vector = EditorGUILayout.Vector3Field(label, prop.vectorValue); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) prop.vectorValue = vector; editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); } /// /// Draw a popup selection field for a float shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property /// An array with the options shown in the popup /// The index of the option that has been selected by the user public static int PopupShaderProperty(this MaterialEditor editor, MaterialProperty prop, GUIContent label, string[] displayedOptions) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); int val = (int)prop.floatValue; EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; int newValue = EditorGUILayout.Popup(label, val, displayedOptions); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck() && (newValue != val || prop.hasMixedValue)) { editor.RegisterPropertyChangeUndo(label.text); prop.floatValue = val = newValue; } editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); return val; } /// /// Draw an integer popup selection field for a float shader property. /// /// /// The MaterialProperty to make a field for /// Label for the property /// An array with the options shown in the popup /// An array with the values for each option /// The value of the option that has been selected by the user public static int IntPopupShaderProperty(this MaterialEditor editor, MaterialProperty prop, string label, string[] displayedOptions, int[] optionValues) { MaterialEditor.BeginProperty(prop); editor.BeginAnimatedCheck(prop); int val = (int)prop.floatValue; EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop.hasMixedValue; int newValue = EditorGUILayout.IntPopup(label, val, displayedOptions, optionValues); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck() && (newValue != val || prop.hasMixedValue)) { editor.RegisterPropertyChangeUndo(label); prop.floatValue = val = newValue; } editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); return val; } /// /// Draw a special slider to specify a range between a min and a max for two float shader properties. /// /// /// The MaterialProperty containing the lower value of the range the slider shows /// The MaterialProperty containing the upper value of the range the slider shows /// The limit at the left end of the slider /// The limit at the right end of the slider /// Label for the property public static void MinMaxShaderProperty(this MaterialEditor editor, MaterialProperty min, MaterialProperty max, float minLimit, float maxLimit, GUIContent label) { MaterialEditor.BeginProperty(min); MaterialEditor.BeginProperty(max); editor.BeginAnimatedCheck(min); editor.BeginAnimatedCheck(max); float minValue = min.floatValue; float maxValue = max.floatValue; EditorGUI.BeginChangeCheck(); EditorGUILayout.MinMaxSlider(label, ref minValue, ref maxValue, minLimit, maxLimit); if (EditorGUI.EndChangeCheck()) { min.floatValue = minValue; max.floatValue = maxValue; } editor.EndAnimatedCheck(); editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); MaterialEditor.EndProperty(); } /// /// Draw a special slider to specify a range between a min and a max for a vector shader property. /// /// /// The MaterialProperty containing the range the slider shows in the x and y components of its vectorValue /// The limit at the left end of the slider /// The limit at the right end of the slider /// Label for the property public static void MinMaxShaderProperty(this MaterialEditor editor, MaterialProperty remapProp, float minLimit, float maxLimit, GUIContent label) { MaterialEditor.BeginProperty(remapProp); editor.BeginAnimatedCheck(remapProp); Vector2 remap = remapProp.vectorValue; EditorGUI.BeginChangeCheck(); EditorGUILayout.MinMaxSlider(label, ref remap.x, ref remap.y, minLimit, maxLimit); if (EditorGUI.EndChangeCheck()) remapProp.vectorValue = remap; editor.EndAnimatedCheck(); MaterialEditor.EndProperty(); } #endregion } }