Singularity/Library/PackageCache/com.unity.render-pipelines..../Editor/ShaderGUI/BaseShaderGUI.cs
2024-05-06 11:45:45 -07:00

786 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Rendering;
using UnityEditor.Rendering.Universal;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using static Unity.Rendering.Universal.ShaderUtils;
using RenderQueue = UnityEngine.Rendering.RenderQueue;
namespace UnityEditor
{
public abstract class BaseShaderGUI : ShaderGUI
{
#region EnumsAndClasses
[Flags]
[URPHelpURL("shaders-in-universalrp")]
protected enum Expandable
{
SurfaceOptions = 1 << 0,
SurfaceInputs = 1 << 1,
Advanced = 1 << 2,
Details = 1 << 3,
}
public enum SurfaceType
{
Opaque,
Transparent
}
public enum BlendMode
{
Alpha, // Old school alpha-blending mode, fresnel does not affect amount of transparency
Premultiply, // Physically plausible transparency mode, implemented as alpha pre-multiply
Additive,
Multiply
}
public enum SmoothnessSource
{
SpecularAlpha,
BaseAlpha,
}
public enum RenderFace
{
Front = 2,
Back = 1,
Both = 0
}
public enum QueueControl
{
Auto = 0,
UserOverride = 1
}
protected class Styles
{
public static readonly string[] surfaceTypeNames = Enum.GetNames(typeof(SurfaceType));
public static readonly string[] blendModeNames = Enum.GetNames(typeof(BlendMode));
public static readonly string[] renderFaceNames = Enum.GetNames(typeof(RenderFace));
public static readonly string[] zwriteNames = Enum.GetNames(typeof(UnityEditor.Rendering.Universal.ShaderGraph.ZWriteControl));
public static readonly string[] queueControlNames = Enum.GetNames(typeof(QueueControl));
// need to skip the first entry for ztest (ZTestMode.Disabled is not a valid value)
public static readonly int[] ztestValues = ((int[])Enum.GetValues(typeof(UnityEditor.Rendering.Universal.ShaderGraph.ZTestMode))).Skip(1).ToArray();
public static readonly string[] ztestNames = Enum.GetNames(typeof(UnityEditor.Rendering.Universal.ShaderGraph.ZTestMode)).Skip(1).ToArray();
// Categories
public static readonly GUIContent SurfaceOptions =
EditorGUIUtility.TrTextContent("Surface Options", "Controls how URP Renders the material on screen.");
public static readonly GUIContent SurfaceInputs = EditorGUIUtility.TrTextContent("Surface Inputs",
"These settings describe the look and feel of the surface itself.");
public static readonly GUIContent AdvancedLabel = EditorGUIUtility.TrTextContent("Advanced Options",
"These settings affect behind-the-scenes rendering and underlying calculations.");
public static readonly GUIContent surfaceType = EditorGUIUtility.TrTextContent("Surface Type",
"Select a surface type for your texture. Choose between Opaque or Transparent.");
public static readonly GUIContent blendingMode = EditorGUIUtility.TrTextContent("Blending Mode",
"Controls how the color of the Transparent surface blends with the Material color in the background.");
public static readonly GUIContent cullingText = EditorGUIUtility.TrTextContent("Render Face",
"Specifies which faces to cull from your geometry. Front culls front faces. Back culls backfaces. None means that both sides are rendered.");
public static readonly GUIContent zwriteText = EditorGUIUtility.TrTextContent("Depth Write",
"Controls whether the shader writes depth. Auto will write only when the shader is opaque.");
public static readonly GUIContent ztestText = EditorGUIUtility.TrTextContent("Depth Test",
"Specifies the depth test mode. The default is LEqual.");
public static readonly GUIContent alphaClipText = EditorGUIUtility.TrTextContent("Alpha Clipping",
"Makes your Material act like a Cutout shader. Use this to create a transparent effect with hard edges between opaque and transparent areas.");
public static readonly GUIContent alphaClipThresholdText = EditorGUIUtility.TrTextContent("Threshold",
"Sets where the Alpha Clipping starts. The higher the value is, the brighter the effect is when clipping starts.");
public static readonly GUIContent castShadowText = EditorGUIUtility.TrTextContent("Cast Shadows",
"When enabled, this GameObject will cast shadows onto any geometry that can receive them.");
public static readonly GUIContent receiveShadowText = EditorGUIUtility.TrTextContent("Receive Shadows",
"When enabled, other GameObjects can cast shadows onto this GameObject.");
public static readonly GUIContent baseMap = EditorGUIUtility.TrTextContent("Base Map",
"Specifies the base Material and/or Color of the surface. If youve selected Transparent or Alpha Clipping under Surface Options, your Material uses the Textures alpha channel or color.");
public static readonly GUIContent emissionMap = EditorGUIUtility.TrTextContent("Emission Map",
"Determines the color and intensity of light that the surface of the material emits.");
public static readonly GUIContent normalMapText =
EditorGUIUtility.TrTextContent("Normal Map", "Designates a Normal Map to create the illusion of bumps and dents on this Material's surface.");
public static readonly GUIContent bumpScaleNotSupported =
EditorGUIUtility.TrTextContent("Bump scale is not supported on mobile platforms");
public static readonly GUIContent fixNormalNow = EditorGUIUtility.TrTextContent("Fix now",
"Converts the assigned texture to be a normal map format.");
public static readonly GUIContent queueSlider = EditorGUIUtility.TrTextContent("Sorting Priority",
"Determines the chronological rendering order for a Material. Materials with lower value are rendered first.");
public static readonly GUIContent queueControl = EditorGUIUtility.TrTextContent("Queue Control",
"Controls whether render queue is automatically set based on material surface type, or explicitly set by the user.");
public static readonly GUIContent documentationIcon = EditorGUIUtility.TrIconContent("_Help", $"Open Reference for URP Shaders.");
}
#endregion
#region Variables
protected MaterialEditor materialEditor { get; set; }
protected MaterialProperty surfaceTypeProp { get; set; }
protected MaterialProperty blendModeProp { get; set; }
protected MaterialProperty cullingProp { get; set; }
protected MaterialProperty ztestProp { get; set; }
protected MaterialProperty zwriteProp { get; set; }
protected MaterialProperty alphaClipProp { get; set; }
protected MaterialProperty alphaCutoffProp { get; set; }
protected MaterialProperty castShadowsProp { get; set; }
protected MaterialProperty receiveShadowsProp { get; set; }
// Common Surface Input properties
protected MaterialProperty baseMapProp { get; set; }
protected MaterialProperty baseColorProp { get; set; }
protected MaterialProperty emissionMapProp { get; set; }
protected MaterialProperty emissionColorProp { get; set; }
protected MaterialProperty queueOffsetProp { get; set; }
protected MaterialProperty queueControlProp { get; set; }
public bool m_FirstTimeApply = true;
// By default, everything is expanded, except advanced
readonly MaterialHeaderScopeList m_MaterialScopeList = new MaterialHeaderScopeList(uint.MaxValue & ~(uint)Expandable.Advanced);
#endregion
private const int queueOffsetRange = 50;
////////////////////////////////////
// General Functions //
////////////////////////////////////
#region GeneralFunctions
[Obsolete("MaterialChanged has been renamed ValidateMaterial", false)]
public virtual void MaterialChanged(Material material)
{
ValidateMaterial(material);
}
public virtual void FindProperties(MaterialProperty[] properties)
{
var material = materialEditor?.target as Material;
if (material == null)
return;
surfaceTypeProp = FindProperty(Property.SurfaceType, properties, false);
blendModeProp = FindProperty(Property.BlendMode, properties, false);
cullingProp = FindProperty(Property.CullMode, properties, false);
zwriteProp = FindProperty(Property.ZWriteControl, properties, false);
ztestProp = FindProperty(Property.ZTest, properties, false);
alphaClipProp = FindProperty(Property.AlphaClip, properties, false);
// ShaderGraph Lit and Unlit Subtargets only
castShadowsProp = FindProperty(Property.CastShadows, properties, false);
queueControlProp = FindProperty(Property.QueueControl, properties, false);
// ShaderGraph Lit, and Lit.shader
receiveShadowsProp = FindProperty(Property.ReceiveShadows, properties, false);
// The following are not mandatory for shadergraphs (it's up to the user to add them to their graph)
alphaCutoffProp = FindProperty("_Cutoff", properties, false);
baseMapProp = FindProperty("_BaseMap", properties, false);
baseColorProp = FindProperty("_BaseColor", properties, false);
emissionMapProp = FindProperty(Property.EmissionMap, properties, false);
emissionColorProp = FindProperty(Property.EmissionColor, properties, false);
queueOffsetProp = FindProperty(Property.QueueOffset, properties, false);
}
public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties)
{
if (materialEditorIn == null)
throw new ArgumentNullException("materialEditorIn");
materialEditor = materialEditorIn;
Material material = materialEditor.target as Material;
FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
// Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching some existing
// material to a universal shader.
if (m_FirstTimeApply)
{
OnOpenGUI(material, materialEditorIn);
m_FirstTimeApply = false;
}
ShaderPropertiesGUI(material);
}
protected virtual uint materialFilter => uint.MaxValue;
public virtual void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
var filter = (Expandable)materialFilter;
// Generate the foldouts
if (filter.HasFlag(Expandable.SurfaceOptions))
m_MaterialScopeList.RegisterHeaderScope(Styles.SurfaceOptions, (uint)Expandable.SurfaceOptions, DrawSurfaceOptions);
if (filter.HasFlag(Expandable.SurfaceInputs))
m_MaterialScopeList.RegisterHeaderScope(Styles.SurfaceInputs, (uint)Expandable.SurfaceInputs, DrawSurfaceInputs);
if (filter.HasFlag(Expandable.Details))
FillAdditionalFoldouts(m_MaterialScopeList);
if (filter.HasFlag(Expandable.Advanced))
m_MaterialScopeList.RegisterHeaderScope(Styles.AdvancedLabel, (uint)Expandable.Advanced, DrawAdvancedOptions);
}
public void ShaderPropertiesGUI(Material material)
{
m_MaterialScopeList.DrawHeaders(materialEditor, material);
}
#endregion
////////////////////////////////////
// Drawing Functions //
////////////////////////////////////
#region DrawingFunctions
internal void DrawShaderGraphProperties(Material material, IEnumerable<MaterialProperty> properties)
{
if (properties == null)
return;
ShaderGraphPropertyDrawers.DrawShaderGraphGUI(materialEditor, properties);
}
internal static void DrawFloatToggleProperty(GUIContent styles, MaterialProperty prop)
{
if (prop == null)
return;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop.hasMixedValue;
bool newValue = EditorGUILayout.Toggle(styles, prop.floatValue == 1);
if (EditorGUI.EndChangeCheck())
prop.floatValue = newValue ? 1.0f : 0.0f;
EditorGUI.showMixedValue = false;
}
public virtual void DrawSurfaceOptions(Material material)
{
DoPopup(Styles.surfaceType, surfaceTypeProp, Styles.surfaceTypeNames);
if ((surfaceTypeProp != null) && ((SurfaceType)surfaceTypeProp.floatValue == SurfaceType.Transparent))
DoPopup(Styles.blendingMode, blendModeProp, Styles.blendModeNames);
DoPopup(Styles.cullingText, cullingProp, Styles.renderFaceNames);
DoPopup(Styles.zwriteText, zwriteProp, Styles.zwriteNames);
if (ztestProp != null)
materialEditor.IntPopupShaderProperty(ztestProp, Styles.ztestText.text, Styles.ztestNames, Styles.ztestValues);
DrawFloatToggleProperty(Styles.alphaClipText, alphaClipProp);
if ((alphaClipProp != null) && (alphaCutoffProp != null) && (alphaClipProp.floatValue == 1))
materialEditor.ShaderProperty(alphaCutoffProp, Styles.alphaClipThresholdText, 1);
DrawFloatToggleProperty(Styles.castShadowText, castShadowsProp);
DrawFloatToggleProperty(Styles.receiveShadowText, receiveShadowsProp);
}
public virtual void DrawSurfaceInputs(Material material)
{
DrawBaseProperties(material);
}
public virtual void DrawAdvancedOptions(Material material)
{
// Only draw the sorting priority field if queue control is set to "auto"
bool autoQueueControl = GetAutomaticQueueControlSetting(material);
if (autoQueueControl)
DrawQueueOffsetField();
materialEditor.EnableInstancingField();
}
protected void DrawQueueOffsetField()
{
if (queueOffsetProp != null)
materialEditor.IntSliderShaderProperty(queueOffsetProp, -queueOffsetRange, queueOffsetRange, Styles.queueSlider);
}
[Obsolete("DrawAdditionalFoldouts has been deprecated. Use FillAdditionalFoldouts instead, and materialScopesList.RegisterHeaderScope", false)]
public virtual void DrawAdditionalFoldouts(Material material) { }
public virtual void FillAdditionalFoldouts(MaterialHeaderScopeList materialScopesList) { }
public virtual void DrawBaseProperties(Material material)
{
if (baseMapProp != null && baseColorProp != null) // Draw the baseMap, most shader will have at least a baseMap
{
materialEditor.TexturePropertySingleLine(Styles.baseMap, baseMapProp, baseColorProp);
}
}
private void DrawEmissionTextureProperty()
{
if ((emissionMapProp == null) || (emissionColorProp == null))
return;
using (new EditorGUI.IndentLevelScope(2))
{
materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp, emissionColorProp, false);
}
}
protected virtual void DrawEmissionProperties(Material material, bool keyword)
{
var emissive = true;
if (!keyword)
{
DrawEmissionTextureProperty();
}
else
{
emissive = materialEditor.EmissionEnabledProperty();
using (new EditorGUI.DisabledScope(!emissive))
{
DrawEmissionTextureProperty();
}
}
// If texture was assigned and color was black set color to white
if ((emissionMapProp != null) && (emissionColorProp != null))
{
var hadEmissionTexture = emissionMapProp?.textureValue != null;
var brightness = emissionColorProp.colorValue.maxColorComponent;
if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f)
emissionColorProp.colorValue = Color.white;
}
if (emissive)
{
// Change the GI emission flag and fix it up with emissive as black if necessary.
materialEditor.LightmapEmissionFlagsProperty(MaterialEditor.kMiniTextureFieldLabelIndentLevel, true);
}
}
public static void DrawNormalArea(MaterialEditor materialEditor, MaterialProperty bumpMap, MaterialProperty bumpMapScale = null)
{
if (bumpMapScale != null)
{
materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap,
bumpMap.textureValue != null ? bumpMapScale : null);
if (bumpMapScale.floatValue != 1 &&
UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(
EditorUserBuildSettings.activeBuildTarget))
if (materialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNormalNow))
bumpMapScale.floatValue = 1;
}
else
{
materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap);
}
}
protected static void DrawTileOffset(MaterialEditor materialEditor, MaterialProperty textureProp)
{
if (textureProp != null)
materialEditor.TextureScaleOffsetProperty(textureProp);
}
#endregion
////////////////////////////////////
// Material Data Functions //
////////////////////////////////////
#region MaterialDataFunctions
// this function is shared with ShaderGraph Lit/Unlit GUIs and also the hand-written GUIs
internal static void UpdateMaterialSurfaceOptions(Material material, bool automaticRenderQueue)
{
// Setup blending - consistent across all Universal RP shaders
SetupMaterialBlendModeInternal(material, out int renderQueue);
// apply automatic render queue
if (automaticRenderQueue && (renderQueue != material.renderQueue))
material.renderQueue = renderQueue;
bool isShaderGraph = material.IsShaderGraph();
// Cast Shadows
bool castShadows = true;
if (material.HasProperty(Property.CastShadows))
{
castShadows = (material.GetFloat(Property.CastShadows) != 0.0f);
}
else
{
if (isShaderGraph)
{
// Lit.shadergraph or Unlit.shadergraph, but no material control defined
// enable the pass in the material, so shader can decide...
castShadows = true;
}
else
{
// Lit.shader or Unlit.shader -- set based on transparency
castShadows = Rendering.Universal.ShaderGUI.LitGUI.IsOpaque(material);
}
}
material.SetShaderPassEnabled("ShadowCaster", castShadows);
// Receive Shadows
if (material.HasProperty(Property.ReceiveShadows))
CoreUtils.SetKeyword(material, ShaderKeywordStrings._RECEIVE_SHADOWS_OFF, material.GetFloat(Property.ReceiveShadows) == 0.0f);
}
// this function is shared between ShaderGraph and hand-written GUIs
internal static void UpdateMaterialRenderQueueControl(Material material)
{
//
// Render Queue Control handling
//
// Check for a raw render queue (the actual serialized setting - material.renderQueue has already been converted)
// setting of -1, indicating that the material property should be inherited from the shader.
// If we find this, add a new property "render queue control" set to 0 so we will
// always know to follow the surface type of the material (this matches the hand-written behavior)
// If we find another value, add the the property set to 1 so we will know that the
// user has explicitly selected a render queue and we should not override it.
//
bool isShaderGraph = material.IsShaderGraph(); // Non-shadergraph materials use automatic behavior
int rawRenderQueue = MaterialAccess.ReadMaterialRawRenderQueue(material);
if (!isShaderGraph || rawRenderQueue == -1)
{
material.SetFloat(Property.QueueControl, (float)QueueControl.Auto); // Automatic behavior - surface type override
}
else
{
material.SetFloat(Property.QueueControl, (float)QueueControl.UserOverride); // User has selected explicit render queue
}
}
internal static bool GetAutomaticQueueControlSetting(Material material)
{
// If a Shader Graph material doesn't yet have the queue control property,
// we should not engage automatic behavior until the shader gets reimported.
bool automaticQueueControl = !material.IsShaderGraph();
if (material.HasProperty(Property.QueueControl))
{
var queueControl = material.GetFloat(Property.QueueControl);
if (queueControl < 0.0f)
{
// The property was added with a negative value, indicating it needs to be validated for this material
UpdateMaterialRenderQueueControl(material);
}
automaticQueueControl = (material.GetFloat(Property.QueueControl) == (float)QueueControl.Auto);
}
return automaticQueueControl;
}
// this is the function used by Lit.shader, Unlit.shader GUIs
public static void SetMaterialKeywords(Material material, Action<Material> shadingModelFunc = null, Action<Material> shaderFunc = null)
{
UpdateMaterialSurfaceOptions(material, automaticRenderQueue: true);
// Setup double sided GI based on Cull state
if (material.HasProperty(Property.CullMode))
material.doubleSidedGI = (RenderFace)material.GetFloat(Property.CullMode) != RenderFace.Front;
// Temporary fix for lightmapping. TODO: to be replaced with attribute tag.
if (material.HasProperty("_MainTex"))
{
material.SetTexture("_MainTex", material.GetTexture("_BaseMap"));
material.SetTextureScale("_MainTex", material.GetTextureScale("_BaseMap"));
material.SetTextureOffset("_MainTex", material.GetTextureOffset("_BaseMap"));
}
if (material.HasProperty("_Color"))
material.SetColor("_Color", material.GetColor("_BaseColor"));
// Emission
if (material.HasProperty(Property.EmissionColor))
MaterialEditor.FixupEmissiveFlag(material);
bool shouldEmissionBeEnabled =
(material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
// Not sure what this is used for, I don't see this property declared by any Unity shader in our repo...
// I'm guessing it is some kind of legacy material upgrade support thing? Or maybe just dead code now...
if (material.HasProperty("_EmissionEnabled") && !shouldEmissionBeEnabled)
shouldEmissionBeEnabled = material.GetFloat("_EmissionEnabled") >= 0.5f;
CoreUtils.SetKeyword(material, ShaderKeywordStrings._EMISSION, shouldEmissionBeEnabled);
// Normal Map
if (material.HasProperty("_BumpMap"))
CoreUtils.SetKeyword(material, ShaderKeywordStrings._NORMALMAP, material.GetTexture("_BumpMap"));
// Shader specific keyword functions
shadingModelFunc?.Invoke(material);
shaderFunc?.Invoke(material);
}
internal static void SetMaterialSrcDstBlendProperties(Material material, UnityEngine.Rendering.BlendMode srcBlend, UnityEngine.Rendering.BlendMode dstBlend)
{
if (material.HasProperty(Property.SrcBlend))
material.SetFloat(Property.SrcBlend, (float)srcBlend);
if (material.HasProperty(Property.DstBlend))
material.SetFloat(Property.DstBlend, (float)dstBlend);
}
internal static void SetMaterialZWriteProperty(Material material, bool zwriteEnabled)
{
if (material.HasProperty(Property.ZWrite))
material.SetFloat(Property.ZWrite, zwriteEnabled ? 1.0f : 0.0f);
}
internal static void SetupMaterialBlendModeInternal(Material material, out int automaticRenderQueue)
{
if (material == null)
throw new ArgumentNullException("material");
bool alphaClip = false;
if (material.HasProperty(Property.AlphaClip))
alphaClip = material.GetFloat(Property.AlphaClip) >= 0.5;
CoreUtils.SetKeyword(material, ShaderKeywordStrings._ALPHATEST_ON, alphaClip);
// default is to use the shader render queue
int renderQueue = material.shader.renderQueue;
material.SetOverrideTag("RenderType", ""); // clear override tag
if (material.HasProperty(Property.SurfaceType))
{
SurfaceType surfaceType = (SurfaceType)material.GetFloat(Property.SurfaceType);
bool zwrite = false;
CoreUtils.SetKeyword(material, ShaderKeywordStrings._SURFACE_TYPE_TRANSPARENT, surfaceType == SurfaceType.Transparent);
if (surfaceType == SurfaceType.Opaque)
{
if (alphaClip)
{
renderQueue = (int)RenderQueue.AlphaTest;
material.SetOverrideTag("RenderType", "TransparentCutout");
}
else
{
renderQueue = (int)RenderQueue.Geometry;
material.SetOverrideTag("RenderType", "Opaque");
}
SetMaterialSrcDstBlendProperties(material, UnityEngine.Rendering.BlendMode.One, UnityEngine.Rendering.BlendMode.Zero);
zwrite = true;
material.DisableKeyword(ShaderKeywordStrings._ALPHAPREMULTIPLY_ON);
material.DisableKeyword(ShaderKeywordStrings._SURFACE_TYPE_TRANSPARENT);
}
else // SurfaceType Transparent
{
BlendMode blendMode = (BlendMode)material.GetFloat(Property.BlendMode);
material.DisableKeyword(ShaderKeywordStrings._ALPHAPREMULTIPLY_ON);
material.DisableKeyword(ShaderKeywordStrings._ALPHAMODULATE_ON);
// Specific Transparent Mode Settings
switch (blendMode)
{
case BlendMode.Alpha:
SetMaterialSrcDstBlendProperties(material,
UnityEngine.Rendering.BlendMode.SrcAlpha,
UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
break;
case BlendMode.Premultiply:
SetMaterialSrcDstBlendProperties(material,
UnityEngine.Rendering.BlendMode.One,
UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.EnableKeyword(ShaderKeywordStrings._ALPHAPREMULTIPLY_ON);
break;
case BlendMode.Additive:
SetMaterialSrcDstBlendProperties(material,
UnityEngine.Rendering.BlendMode.SrcAlpha,
UnityEngine.Rendering.BlendMode.One);
break;
case BlendMode.Multiply:
SetMaterialSrcDstBlendProperties(material,
UnityEngine.Rendering.BlendMode.DstColor,
UnityEngine.Rendering.BlendMode.Zero);
material.EnableKeyword(ShaderKeywordStrings._ALPHAMODULATE_ON);
break;
}
// General Transparent Material Settings
material.SetOverrideTag("RenderType", "Transparent");
zwrite = false;
material.EnableKeyword(ShaderKeywordStrings._SURFACE_TYPE_TRANSPARENT);
renderQueue = (int)RenderQueue.Transparent;
}
// check for override enum
if (material.HasProperty(Property.ZWriteControl))
{
var zwriteControl = (UnityEditor.Rendering.Universal.ShaderGraph.ZWriteControl)material.GetFloat(Property.ZWriteControl);
if (zwriteControl == UnityEditor.Rendering.Universal.ShaderGraph.ZWriteControl.ForceEnabled)
zwrite = true;
else if (zwriteControl == UnityEditor.Rendering.Universal.ShaderGraph.ZWriteControl.ForceDisabled)
zwrite = false;
}
SetMaterialZWriteProperty(material, zwrite);
material.SetShaderPassEnabled("DepthOnly", zwrite);
}
else
{
// no surface type property -- must be hard-coded by the shadergraph,
// so ensure the pass is enabled at the material level
material.SetShaderPassEnabled("DepthOnly", true);
}
// must always apply queue offset, even if not set to material control
if (material.HasProperty(Property.QueueOffset))
renderQueue += (int)material.GetFloat(Property.QueueOffset);
automaticRenderQueue = renderQueue;
}
public static void SetupMaterialBlendMode(Material material)
{
SetupMaterialBlendModeInternal(material, out int renderQueue);
// apply automatic render queue
if (renderQueue != material.renderQueue)
material.renderQueue = renderQueue;
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
// Clear all keywords for fresh start
// Note: this will nuke user-selected custom keywords when they change shaders
material.shaderKeywords = null;
base.AssignNewShaderToMaterial(material, oldShader, newShader);
// Setup keywords based on the new shader
UpdateMaterial(material, MaterialUpdateType.ChangedAssignedShader);
}
#endregion
////////////////////////////////////
// Helper Functions //
////////////////////////////////////
#region HelperFunctions
public static void TwoFloatSingleLine(GUIContent title, MaterialProperty prop1, GUIContent prop1Label,
MaterialProperty prop2, GUIContent prop2Label, MaterialEditor materialEditor, float labelWidth = 30f)
{
const int kInterFieldPadding = 2;
Rect rect = EditorGUILayout.GetControlRect();
EditorGUI.PrefixLabel(rect, title);
var indent = EditorGUI.indentLevel;
var preLabelWidth = EditorGUIUtility.labelWidth;
EditorGUI.indentLevel = 0;
EditorGUIUtility.labelWidth = labelWidth;
Rect propRect1 = new Rect(rect.x + preLabelWidth, rect.y,
(rect.width - preLabelWidth) * 0.5f - 1, EditorGUIUtility.singleLineHeight);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop1.hasMixedValue;
var prop1val = EditorGUI.FloatField(propRect1, prop1Label, prop1.floatValue);
if (EditorGUI.EndChangeCheck())
prop1.floatValue = prop1val;
Rect propRect2 = new Rect(propRect1.x + propRect1.width + kInterFieldPadding, rect.y,
propRect1.width, EditorGUIUtility.singleLineHeight);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop2.hasMixedValue;
var prop2val = EditorGUI.FloatField(propRect2, prop2Label, prop2.floatValue);
if (EditorGUI.EndChangeCheck())
prop2.floatValue = prop2val;
EditorGUI.indentLevel = indent;
EditorGUIUtility.labelWidth = preLabelWidth;
EditorGUI.showMixedValue = false;
}
public void DoPopup(GUIContent label, MaterialProperty property, string[] options)
{
if (property != null)
materialEditor.PopupShaderProperty(property, label, options);
}
// Helper to show texture and color properties
public static Rect TextureColorProps(MaterialEditor materialEditor, GUIContent label, MaterialProperty textureProp, MaterialProperty colorProp, bool hdr = false)
{
Rect rect = EditorGUILayout.GetControlRect();
EditorGUI.showMixedValue = textureProp.hasMixedValue;
materialEditor.TexturePropertyMiniThumbnail(rect, textureProp, label.text, label.tooltip);
EditorGUI.showMixedValue = false;
if (colorProp != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = colorProp.hasMixedValue;
int indentLevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
Rect rectAfterLabel = new Rect(rect.x + EditorGUIUtility.labelWidth, rect.y,
EditorGUIUtility.fieldWidth, EditorGUIUtility.singleLineHeight);
var col = EditorGUI.ColorField(rectAfterLabel, GUIContent.none, colorProp.colorValue, true,
false, hdr);
EditorGUI.indentLevel = indentLevel;
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo(colorProp.displayName);
colorProp.colorValue = col;
}
EditorGUI.showMixedValue = false;
}
return rect;
}
// Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others
public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties)
{
return FindProperty(propertyName, properties, true);
}
// Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others
public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties, bool propertyIsMandatory)
{
for (int index = 0; index < properties.Length; ++index)
{
if (properties[index] != null && properties[index].name == propertyName)
return properties[index];
}
if (propertyIsMandatory)
throw new ArgumentException("Could not find MaterialProperty: '" + propertyName + "', Num properties: " + (object)properties.Length);
return null;
}
#endregion
}
}