using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.HighDefinition; using System.Linq; // Include material common properties names using static UnityEngine.Rendering.HighDefinition.HDMaterialProperties; namespace UnityEditor.Rendering.HighDefinition { /// /// The UI block that represents Shader Graph material properties. /// This UI block displays every non-hidden property inside a shader. You can also use this with non-shadergraph shaders. /// public class ShaderGraphUIBlock : MaterialUIBlock { /// ShaderGraph UI Block features. [Flags] public enum Features { /// Nothing is displayed. None = 0, /// Display the exposed properties. ExposedProperties = 1 << 1, /// Display the default exposed diffusion profile from the graph. DiffusionProfileAsset = 1 << 2, /// Display the shadow matte options. ShadowMatte = 1 << 5, /// Display all the Unlit fields. Unlit = ExposedProperties | ShadowMatte, /// Display all the fields. All = ~0, } internal static class Styles { public const string header = "Exposed Properties"; } ExpandableBit m_ExpandableBit; Features m_Features; /// /// Constructs a ShaderGraphUIBlock based on the parameters. /// /// Bit index used to store the foldout state. /// Features enabled in the block. public ShaderGraphUIBlock(ExpandableBit expandableBit = ExpandableBit.ShaderGraph, Features features = Features.All) { m_ExpandableBit = expandableBit; m_Features = features; } /// /// Loads the material properties for the block. /// public override void LoadMaterialProperties() {} /// /// Renders the properties in the block. /// public override void OnGUI() { using (var header = new MaterialHeaderScope(Styles.header, (uint)m_ExpandableBit, materialEditor)) { if (header.expanded) DrawShaderGraphGUI(); } } MaterialProperty[] oldProperties; bool CheckPropertyChanged(MaterialProperty[] properties) { bool propertyChanged = false; if (oldProperties != null) { // Check if shader was changed (new/deleted properties) if (properties.Length != oldProperties.Length) { propertyChanged = true; } else { for (int i = 0; i < properties.Length; i++) { if (properties[i].type != oldProperties[i].type) propertyChanged = true; if (properties[i].displayName != oldProperties[i].displayName) propertyChanged = true; if (properties[i].flags != oldProperties[i].flags) propertyChanged = true; if (properties[i].name != oldProperties[i].name) propertyChanged = true; if (properties[i].floatValue != oldProperties[i].floatValue) propertyChanged = true; if (properties[i].vectorValue != oldProperties[i].vectorValue) propertyChanged = true; if (properties[i].colorValue != oldProperties[i].colorValue) propertyChanged = true; if (properties[i].textureValue != oldProperties[i].textureValue) propertyChanged = true; } } } oldProperties = properties; return propertyChanged; } void DrawShaderGraphGUI() { // Filter out properties we don't want to draw: if ((m_Features & Features.ExposedProperties) != 0) PropertiesDefaultGUI(properties); // If we change a property in a shadergraph, we trigger a material keyword reset if (CheckPropertyChanged(properties)) { foreach (var material in materials) HDShaderUtils.ResetMaterialKeywords(material); } if ((m_Features & Features.DiffusionProfileAsset) != 0) DrawDiffusionProfileUI(); if ((m_Features & Features.ShadowMatte) != 0 && materials.All(m => m.HasProperty(kShadowMatteFilter))) DrawShadowMatteToggle(); } /// /// Draws the material properties. /// /// List of Material Properties to draw protected void PropertiesDefaultGUI(MaterialProperty[] properties) { for (var i = 0; i < properties.Length; i++) { if ((properties[i].flags & (MaterialProperty.PropFlags.HideInInspector | MaterialProperty.PropFlags.PerRendererData)) != 0) continue; float h = materialEditor.GetPropertyHeight(properties[i], properties[i].displayName); Rect r = EditorGUILayout.GetControlRect(true, h, EditorStyles.layerMaskField); materialEditor.ShaderProperty(r, properties[i], properties[i].displayName); } } /// /// Draws the Shadow Matte settings. This is only available for Unlit materials. /// protected void DrawShadowMatteToggle() { uint exponent = 0b10000000; // 0 as exponent uint mantissa = 0x007FFFFF; float value = materials[0].GetFloat(HDMaterialProperties.kShadowMatteFilter); uint uValue = HDShadowUtils.Asuint(value); uint filter = uValue & mantissa; bool shadowFilterPoint = (filter & (uint)LightFeatureFlags.Punctual) != 0; bool shadowFilterDir = (filter & (uint)LightFeatureFlags.Directional) != 0; bool shadowFilterRect = (filter & (uint)LightFeatureFlags.Area) != 0; uint finalFlag = 0x00000000; finalFlag |= EditorGUILayout.Toggle("Point/Spot Shadow", shadowFilterPoint) ? (uint)LightFeatureFlags.Punctual : 0x00000000u; finalFlag |= EditorGUILayout.Toggle("Directional Shadow", shadowFilterDir) ? (uint)LightFeatureFlags.Directional : 0x00000000u; finalFlag |= EditorGUILayout.Toggle("Area Shadow", shadowFilterRect) ? (uint)LightFeatureFlags.Area : 0x00000000u; finalFlag &= mantissa; finalFlag |= exponent; materials[0].SetFloat(HDMaterialProperties.kShadowMatteFilter, HDShadowUtils.Asfloat(finalFlag)); } /// /// Draw the built-in exposed Diffusion Profile when a material uses sub-surface scattering or transmission. /// protected void DrawDiffusionProfileUI() { if (DiffusionProfileMaterialUI.IsSupported(materialEditor)) DiffusionProfileMaterialUI.OnGUI(materialEditor, FindProperty("_DiffusionProfileAsset"), FindProperty("_DiffusionProfileHash"), 0); } } }