using UnityEngine; using UnityEngine.Rendering; namespace UnityEditor.Rendering.Universal.ShaderGUI { /// /// Editor script for the Lit material inspector. /// public static class LitGUI { /// /// Workflow modes for the shader. /// public enum WorkflowMode { /// /// Use this for specular workflow. /// Specular = 0, /// /// Use this for metallic workflow. /// Metallic } /// /// Options to select the texture channel where the smoothness value is stored. /// public enum SmoothnessMapChannel { /// /// Use this when smoothness is stored in the alpha channel of the Specular/Metallic Map. /// SpecularMetallicAlpha, /// /// Use this when smoothness is stored in the alpha channel of the Albedo Map. /// AlbedoAlpha, } /// /// Container for the text and tooltips used to display the shader. /// public static class Styles { /// /// The text and tooltip for the workflow Mode GUI. /// public static GUIContent workflowModeText = EditorGUIUtility.TrTextContent("Workflow Mode", "Select a workflow that fits your textures. Choose between Metallic or Specular."); /// /// The text and tooltip for the specular Map GUI. /// public static GUIContent specularMapText = EditorGUIUtility.TrTextContent("Specular Map", "Designates a Specular Map and specular color determining the apperance of reflections on this Material's surface."); /// /// The text and tooltip for the metallic Map GUI. /// public static GUIContent metallicMapText = EditorGUIUtility.TrTextContent("Metallic Map", "Sets and configures the map for the Metallic workflow."); /// /// The text and tooltip for the smoothness GUI. /// public static GUIContent smoothnessText = EditorGUIUtility.TrTextContent("Smoothness", "Controls the spread of highlights and reflections on the surface."); /// /// The text and tooltip for the smoothness source GUI. /// public static GUIContent smoothnessMapChannelText = EditorGUIUtility.TrTextContent("Source", "Specifies where to sample a smoothness map from. By default, uses the alpha channel for your map."); /// /// The text and tooltip for the specular Highlights GUI. /// public static GUIContent highlightsText = EditorGUIUtility.TrTextContent("Specular Highlights", "When enabled, the Material reflects the shine from direct lighting."); /// /// The text and tooltip for the environment Reflections GUI. /// public static GUIContent reflectionsText = EditorGUIUtility.TrTextContent("Environment Reflections", "When enabled, the Material samples reflections from the nearest Reflection Probes or Lighting Probe."); /// /// The text and tooltip for the height map GUI. /// public static GUIContent heightMapText = EditorGUIUtility.TrTextContent("Height Map", "Defines a Height Map that will drive a parallax effect in the shader making the surface seem displaced."); /// /// The text and tooltip for the occlusion map GUI. /// public static GUIContent occlusionText = EditorGUIUtility.TrTextContent("Occlusion Map", "Sets an occlusion map to simulate shadowing from ambient lighting."); /// /// The names for smoothness alpha options available for metallic workflow. /// public static readonly string[] metallicSmoothnessChannelNames = { "Metallic Alpha", "Albedo Alpha" }; /// /// The names for smoothness alpha options available for specular workflow. /// public static readonly string[] specularSmoothnessChannelNames = { "Specular Alpha", "Albedo Alpha" }; /// /// The text and tooltip for the enabling/disabling clear coat GUI. /// public static GUIContent clearCoatText = EditorGUIUtility.TrTextContent("Clear Coat", "A multi-layer material feature which simulates a thin layer of coating on top of the surface material." + "\nPerformance cost is considerable as the specular component is evaluated twice, once per layer."); /// /// The text and tooltip for the clear coat Mask GUI. /// public static GUIContent clearCoatMaskText = EditorGUIUtility.TrTextContent("Mask", "Specifies the amount of the coat blending." + "\nActs as a multiplier of the clear coat map mask value or as a direct mask value if no map is specified." + "\nThe map specifies clear coat mask in the red channel and clear coat smoothness in the green channel."); /// /// The text and tooltip for the clear coat smoothness GUI. /// public static GUIContent clearCoatSmoothnessText = EditorGUIUtility.TrTextContent("Smoothness", "Specifies the smoothness of the coating." + "\nActs as a multiplier of the clear coat map smoothness value or as a direct smoothness value if no map is specified."); } /// /// Container for the properties used in the LitGUI editor script. /// public struct LitProperties { // Surface Option Props /// /// The MaterialProperty for workflow mode. /// public MaterialProperty workflowMode; // Surface Input Props /// /// The MaterialProperty for metallic value. /// public MaterialProperty metallic; /// /// The MaterialProperty for specular color. /// public MaterialProperty specColor; /// /// The MaterialProperty for metallic Smoothness map. /// public MaterialProperty metallicGlossMap; /// /// The MaterialProperty for specular smoothness map. /// public MaterialProperty specGlossMap; /// /// The MaterialProperty for smoothness value. /// public MaterialProperty smoothness; /// /// The MaterialProperty for smoothness alpha channel. /// public MaterialProperty smoothnessMapChannel; /// /// The MaterialProperty for normal map. /// public MaterialProperty bumpMapProp; /// /// The MaterialProperty for normal map scale. /// public MaterialProperty bumpScaleProp; /// /// The MaterialProperty for height map. /// public MaterialProperty parallaxMapProp; /// /// The MaterialProperty for height map scale. /// public MaterialProperty parallaxScaleProp; /// /// The MaterialProperty for occlusion strength. /// public MaterialProperty occlusionStrength; /// /// The MaterialProperty for occlusion map. /// public MaterialProperty occlusionMap; // Advanced Props /// /// The MaterialProperty for specular highlights. /// public MaterialProperty highlights; /// /// The MaterialProperty for environment reflections. /// public MaterialProperty reflections; /// /// The MaterialProperty for enabling/disabling clear coat. /// public MaterialProperty clearCoat; // Enable/Disable dummy property /// /// The MaterialProperty for clear coat map. /// public MaterialProperty clearCoatMap; /// /// The MaterialProperty for clear coat mask. /// public MaterialProperty clearCoatMask; /// /// The MaterialProperty for clear coat smoothness. /// public MaterialProperty clearCoatSmoothness; /// /// Constructor for the LitProperties container struct. /// /// public LitProperties(MaterialProperty[] properties) { // Surface Option Props workflowMode = BaseShaderGUI.FindProperty("_WorkflowMode", properties, false); // Surface Input Props metallic = BaseShaderGUI.FindProperty("_Metallic", properties); specColor = BaseShaderGUI.FindProperty("_SpecColor", properties, false); metallicGlossMap = BaseShaderGUI.FindProperty("_MetallicGlossMap", properties); specGlossMap = BaseShaderGUI.FindProperty("_SpecGlossMap", properties, false); smoothness = BaseShaderGUI.FindProperty("_Smoothness", properties, false); smoothnessMapChannel = BaseShaderGUI.FindProperty("_SmoothnessTextureChannel", properties, false); bumpMapProp = BaseShaderGUI.FindProperty("_BumpMap", properties, false); bumpScaleProp = BaseShaderGUI.FindProperty("_BumpScale", properties, false); parallaxMapProp = BaseShaderGUI.FindProperty("_ParallaxMap", properties, false); parallaxScaleProp = BaseShaderGUI.FindProperty("_Parallax", properties, false); occlusionStrength = BaseShaderGUI.FindProperty("_OcclusionStrength", properties, false); occlusionMap = BaseShaderGUI.FindProperty("_OcclusionMap", properties, false); // Advanced Props highlights = BaseShaderGUI.FindProperty("_SpecularHighlights", properties, false); reflections = BaseShaderGUI.FindProperty("_EnvironmentReflections", properties, false); clearCoat = BaseShaderGUI.FindProperty("_ClearCoat", properties, false); clearCoatMap = BaseShaderGUI.FindProperty("_ClearCoatMap", properties, false); clearCoatMask = BaseShaderGUI.FindProperty("_ClearCoatMask", properties, false); clearCoatSmoothness = BaseShaderGUI.FindProperty("_ClearCoatSmoothness", properties, false); } } /// /// Draws the surface inputs GUI. /// /// /// /// public static void Inputs(LitProperties properties, MaterialEditor materialEditor, Material material) { DoMetallicSpecularArea(properties, materialEditor, material); BaseShaderGUI.DrawNormalArea(materialEditor, properties.bumpMapProp, properties.bumpScaleProp); if (HeightmapAvailable(material)) DoHeightmapArea(properties, materialEditor); if (properties.occlusionMap != null) { materialEditor.TexturePropertySingleLine(Styles.occlusionText, properties.occlusionMap, properties.occlusionMap.textureValue != null ? properties.occlusionStrength : null); } // Check that we have all the required properties for clear coat, // otherwise we will get null ref exception from MaterialEditor GUI helpers. if (ClearCoatAvailable(material)) DoClearCoat(properties, materialEditor, material); } private static bool ClearCoatAvailable(Material material) { return material.HasProperty("_ClearCoat") && material.HasProperty("_ClearCoatMap") && material.HasProperty("_ClearCoatMask") && material.HasProperty("_ClearCoatSmoothness"); } private static bool HeightmapAvailable(Material material) { return material.HasProperty("_Parallax") && material.HasProperty("_ParallaxMap"); } private static void DoHeightmapArea(LitProperties properties, MaterialEditor materialEditor) { materialEditor.TexturePropertySingleLine(Styles.heightMapText, properties.parallaxMapProp, properties.parallaxMapProp.textureValue != null ? properties.parallaxScaleProp : null); } private static bool ClearCoatEnabled(Material material) { return material.HasProperty("_ClearCoat") && material.GetFloat("_ClearCoat") > 0.0; } /// /// Draws the clear coat GUI. /// /// /// /// public static void DoClearCoat(LitProperties properties, MaterialEditor materialEditor, Material material) { materialEditor.ShaderProperty(properties.clearCoat, Styles.clearCoatText); var coatEnabled = material.GetFloat("_ClearCoat") > 0.0; EditorGUI.BeginDisabledGroup(!coatEnabled); { EditorGUI.indentLevel += 2; materialEditor.TexturePropertySingleLine(Styles.clearCoatMaskText, properties.clearCoatMap, properties.clearCoatMask); // Texture and HDR color controls materialEditor.ShaderProperty(properties.clearCoatSmoothness, Styles.clearCoatSmoothnessText); EditorGUI.indentLevel -= 2; } EditorGUI.EndDisabledGroup(); } /// /// Draws the metallic/specular area GUI. /// /// /// /// public static void DoMetallicSpecularArea(LitProperties properties, MaterialEditor materialEditor, Material material) { string[] smoothnessChannelNames; bool hasGlossMap = false; if (properties.workflowMode == null || (WorkflowMode)properties.workflowMode.floatValue == WorkflowMode.Metallic) { hasGlossMap = properties.metallicGlossMap.textureValue != null; smoothnessChannelNames = Styles.metallicSmoothnessChannelNames; materialEditor.TexturePropertySingleLine(Styles.metallicMapText, properties.metallicGlossMap, hasGlossMap ? null : properties.metallic); } else { hasGlossMap = properties.specGlossMap.textureValue != null; smoothnessChannelNames = Styles.specularSmoothnessChannelNames; BaseShaderGUI.TextureColorProps(materialEditor, Styles.specularMapText, properties.specGlossMap, hasGlossMap ? null : properties.specColor); } DoSmoothness(materialEditor, material, properties.smoothness, properties.smoothnessMapChannel, smoothnessChannelNames); } internal static bool IsOpaque(Material material) { bool opaque = true; if (material.HasProperty(Property.SurfaceType)) opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat(Property.SurfaceType) == BaseShaderGUI.SurfaceType.Opaque); return opaque; } /// /// Draws the smoothness GUI. /// /// /// /// /// /// public static void DoSmoothness(MaterialEditor materialEditor, Material material, MaterialProperty smoothness, MaterialProperty smoothnessMapChannel, string[] smoothnessChannelNames) { EditorGUI.indentLevel += 2; materialEditor.ShaderProperty(smoothness, Styles.smoothnessText); if (smoothnessMapChannel != null) // smoothness channel { var opaque = IsOpaque(material); EditorGUI.indentLevel++; EditorGUI.showMixedValue = smoothnessMapChannel.hasMixedValue; if (opaque) { MaterialEditor.BeginProperty(smoothnessMapChannel); EditorGUI.BeginChangeCheck(); var smoothnessSource = (int)smoothnessMapChannel.floatValue; smoothnessSource = EditorGUILayout.Popup(Styles.smoothnessMapChannelText, smoothnessSource, smoothnessChannelNames); if (EditorGUI.EndChangeCheck()) smoothnessMapChannel.floatValue = smoothnessSource; MaterialEditor.EndProperty(); } else { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.Popup(Styles.smoothnessMapChannelText, 0, smoothnessChannelNames); EditorGUI.EndDisabledGroup(); } EditorGUI.showMixedValue = false; EditorGUI.indentLevel--; } EditorGUI.indentLevel -= 2; } /// /// Retrieves the alpha channel used for smoothness. /// /// /// The Alpha channel used for Smoothness. public static SmoothnessMapChannel GetSmoothnessMapChannel(Material material) { int ch = (int)material.GetFloat("_SmoothnessTextureChannel"); if (ch == (int)SmoothnessMapChannel.AlbedoAlpha) return SmoothnessMapChannel.AlbedoAlpha; return SmoothnessMapChannel.SpecularMetallicAlpha; } // (shared by all lit shaders, including shadergraph Lit Target and Lit.shader) internal static void SetupSpecularWorkflowKeyword(Material material, out bool isSpecularWorkflow) { isSpecularWorkflow = false; // default is metallic workflow if (material.HasProperty(Property.SpecularWorkflowMode)) isSpecularWorkflow = ((WorkflowMode)material.GetFloat(Property.SpecularWorkflowMode)) == WorkflowMode.Specular; CoreUtils.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkflow); } /// /// Sets up the keywords for the Lit shader and material. /// /// public static void SetMaterialKeywords(Material material) { SetupSpecularWorkflowKeyword(material, out bool isSpecularWorkFlow); // Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation // (MaterialProperty value might come from renderer material property block) var specularGlossMap = isSpecularWorkFlow ? "_SpecGlossMap" : "_MetallicGlossMap"; var hasGlossMap = material.GetTexture(specularGlossMap) != null; CoreUtils.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap); if (material.HasProperty("_SpecularHighlights")) CoreUtils.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", material.GetFloat("_SpecularHighlights") == 0.0f); if (material.HasProperty("_EnvironmentReflections")) CoreUtils.SetKeyword(material, "_ENVIRONMENTREFLECTIONS_OFF", material.GetFloat("_EnvironmentReflections") == 0.0f); if (material.HasProperty("_OcclusionMap")) CoreUtils.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap")); if (material.HasProperty("_ParallaxMap")) CoreUtils.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap")); if (material.HasProperty("_SmoothnessTextureChannel")) { var opaque = IsOpaque(material); CoreUtils.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha && opaque); } // Clear coat keywords are independent to remove possibility of invalid combinations. if (ClearCoatEnabled(material)) { var hasMap = material.HasProperty("_ClearCoatMap") && material.GetTexture("_ClearCoatMap") != null; if (hasMap) { CoreUtils.SetKeyword(material, "_CLEARCOAT", false); CoreUtils.SetKeyword(material, "_CLEARCOATMAP", true); } else { CoreUtils.SetKeyword(material, "_CLEARCOAT", true); CoreUtils.SetKeyword(material, "_CLEARCOATMAP", false); } } else { CoreUtils.SetKeyword(material, "_CLEARCOAT", false); CoreUtils.SetKeyword(material, "_CLEARCOATMAP", false); } } } }