Files
PixelJumperHero/Library/PackageCache/com.unity.render-pipelines.universal@11.0.0/Editor/ShaderGUI/BaseShaderGUI.cs
2021-06-13 10:28:03 +02:00

620 lines
27 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 UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.Rendering.Universal;
namespace UnityEditor
{
public abstract class BaseShaderGUI : ShaderGUI
{
#region EnumsAndClasses
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
{
BaseAlpha,
SpecularAlpha
}
public enum RenderFace
{
Front = 2,
Back = 1,
Both = 0
}
protected class Styles
{
// Catergories
public static readonly GUIContent SurfaceOptions =
new GUIContent("Surface Options", "Controls how Universal RP renders the Material on a screen.");
public static readonly GUIContent SurfaceInputs = new GUIContent("Surface Inputs",
"These settings describe the look and feel of the surface itself.");
public static readonly GUIContent AdvancedLabel = new GUIContent("Advanced",
"These settings affect behind-the-scenes rendering and underlying calculations.");
public static readonly GUIContent surfaceType = new GUIContent("Surface Type",
"Select a surface type for your texture. Choose between Opaque or Transparent.");
public static readonly GUIContent blendingMode = new GUIContent("Blending Mode",
"Controls how the color of the Transparent surface blends with the Material color in the background.");
public static readonly GUIContent cullingText = new GUIContent("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 alphaClipText = new GUIContent("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 = new GUIContent("Threshold",
"Sets where the Alpha Clipping starts. The higher the value is, the brighter the effect is when clipping starts.");
public static readonly GUIContent receiveShadowText = new GUIContent("Receive Shadows",
"When enabled, other GameObjects can cast shadows onto this GameObject.");
public static readonly GUIContent baseMap = new GUIContent("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 = new GUIContent("Emission Map",
"Sets a Texture map to use for emission. You can also select a color with the color picker. Colors are multiplied over the Texture.");
public static readonly GUIContent normalMapText =
new GUIContent("Normal Map", "Assigns a tangent-space normal map.");
public static readonly GUIContent bumpScaleNotSupported =
new GUIContent("Bump scale is not supported on mobile platforms");
public static readonly GUIContent fixNormalNow = new GUIContent("Fix now",
"Converts the assigned texture to be a normal map format.");
public static readonly GUIContent queueSlider = new GUIContent("Priority",
"Determines the chronological rendering order for a Material. High values are rendered first.");
}
#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 alphaClipProp { get; set; }
protected MaterialProperty alphaCutoffProp { 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; }
public bool m_FirstTimeApply = true;
private const string k_KeyPrefix = "UniversalRP:Material:UI_State:";
private string m_HeaderStateKey = null;
protected string headerStateKey { get { return m_HeaderStateKey; } }
// Header foldout states
SavedBool m_SurfaceOptionsFoldout;
SavedBool m_SurfaceInputsFoldout;
SavedBool m_AdvancedFoldout;
#endregion
private const int queueOffsetRange = 50;
////////////////////////////////////
// General Functions //
////////////////////////////////////
#region GeneralFunctions
public abstract void MaterialChanged(Material material);
public virtual void FindProperties(MaterialProperty[] properties)
{
surfaceTypeProp = FindProperty("_Surface", properties);
blendModeProp = FindProperty("_Blend", properties);
cullingProp = FindProperty("_Cull", properties);
alphaClipProp = FindProperty("_AlphaClip", properties);
alphaCutoffProp = FindProperty("_Cutoff", properties);
receiveShadowsProp = FindProperty("_ReceiveShadows", properties, false);
baseMapProp = FindProperty("_BaseMap", properties, false);
baseColorProp = FindProperty("_BaseColor", properties, false);
emissionMapProp = FindProperty("_EmissionMap", properties, false);
emissionColorProp = FindProperty("_EmissionColor", properties, false);
queueOffsetProp = FindProperty("_QueueOffset", properties, false);
}
public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties)
{
if (materialEditorIn == null)
throw new ArgumentNullException("materialEditorIn");
FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
materialEditor = materialEditorIn;
Material material = materialEditor.target as Material;
// 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);
}
public virtual void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
// Foldout states
m_HeaderStateKey = k_KeyPrefix + material.shader.name; // Create key string for editor prefs
m_SurfaceOptionsFoldout = new SavedBool($"{m_HeaderStateKey}.SurfaceOptionsFoldout", true);
m_SurfaceInputsFoldout = new SavedBool($"{m_HeaderStateKey}.SurfaceInputsFoldout", true);
m_AdvancedFoldout = new SavedBool($"{m_HeaderStateKey}.AdvancedFoldout", false);
foreach (var obj in materialEditor.targets)
MaterialChanged((Material)obj);
}
public void ShaderPropertiesGUI(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
EditorGUI.BeginChangeCheck();
m_SurfaceOptionsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceOptionsFoldout.value, Styles.SurfaceOptions);
if (m_SurfaceOptionsFoldout.value)
{
DrawSurfaceOptions(material);
EditorGUILayout.Space();
}
EditorGUILayout.EndFoldoutHeaderGroup();
m_SurfaceInputsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceInputsFoldout.value, Styles.SurfaceInputs);
if (m_SurfaceInputsFoldout.value)
{
DrawSurfaceInputs(material);
EditorGUILayout.Space();
}
EditorGUILayout.EndFoldoutHeaderGroup();
DrawAdditionalFoldouts(material);
m_AdvancedFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_AdvancedFoldout.value, Styles.AdvancedLabel);
if (m_AdvancedFoldout.value)
{
DrawAdvancedOptions(material);
EditorGUILayout.Space();
}
EditorGUILayout.EndFoldoutHeaderGroup();
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in materialEditor.targets)
MaterialChanged((Material)obj);
}
}
#endregion
////////////////////////////////////
// Drawing Functions //
////////////////////////////////////
#region DrawingFunctions
public virtual void DrawSurfaceOptions(Material material)
{
DoPopup(Styles.surfaceType, surfaceTypeProp, Enum.GetNames(typeof(SurfaceType)));
if ((SurfaceType)material.GetFloat("_Surface") == SurfaceType.Transparent)
DoPopup(Styles.blendingMode, blendModeProp, Enum.GetNames(typeof(BlendMode)));
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = cullingProp.hasMixedValue;
var culling = (RenderFace)cullingProp.floatValue;
culling = (RenderFace)EditorGUILayout.EnumPopup(Styles.cullingText, culling);
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo(Styles.cullingText.text);
cullingProp.floatValue = (float)culling;
material.doubleSidedGI = (RenderFace)cullingProp.floatValue != RenderFace.Front;
}
EditorGUI.showMixedValue = false;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = alphaClipProp.hasMixedValue;
var alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClipProp.floatValue == 1);
if (EditorGUI.EndChangeCheck())
alphaClipProp.floatValue = alphaClipEnabled ? 1 : 0;
EditorGUI.showMixedValue = false;
if (alphaClipProp.floatValue == 1)
materialEditor.ShaderProperty(alphaCutoffProp, Styles.alphaClipThresholdText, 1);
if (receiveShadowsProp != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = receiveShadowsProp.hasMixedValue;
var receiveShadows =
EditorGUILayout.Toggle(Styles.receiveShadowText, receiveShadowsProp.floatValue == 1.0f);
if (EditorGUI.EndChangeCheck())
receiveShadowsProp.floatValue = receiveShadows ? 1.0f : 0.0f;
EditorGUI.showMixedValue = false;
}
}
public virtual void DrawSurfaceInputs(Material material)
{
DrawBaseProperties(material);
}
public virtual void DrawAdvancedOptions(Material material)
{
materialEditor.EnableInstancingField();
DrawQueueOffsetField();
}
protected void DrawQueueOffsetField()
{
if (queueOffsetProp != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = queueOffsetProp.hasMixedValue;
var queue = EditorGUILayout.IntSlider(Styles.queueSlider, (int)queueOffsetProp.floatValue, -queueOffsetRange, queueOffsetRange);
if (EditorGUI.EndChangeCheck())
queueOffsetProp.floatValue = queue;
EditorGUI.showMixedValue = false;
}
}
public virtual void DrawAdditionalFoldouts(Material material) {}
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);
// TODO Temporary fix for lightmapping, to be replaced with attribute tag.
if (material.HasProperty("_MainTex"))
{
material.SetTexture("_MainTex", baseMapProp.textureValue);
var baseMapTiling = baseMapProp.textureScaleAndOffset;
material.SetTextureScale("_MainTex", new Vector2(baseMapTiling.x, baseMapTiling.y));
material.SetTextureOffset("_MainTex", new Vector2(baseMapTiling.z, baseMapTiling.w));
}
}
}
protected virtual void DrawEmissionProperties(Material material, bool keyword)
{
var emissive = true;
var hadEmissionTexture = emissionMapProp.textureValue != null;
if (!keyword)
{
materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp, emissionColorProp,
false);
}
else
{
// Emission for GI?
emissive = materialEditor.EmissionEnabledProperty();
EditorGUI.BeginDisabledGroup(!emissive);
{
// Texture and HDR color controls
materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp,
emissionColorProp,
false);
}
EditorGUI.EndDisabledGroup();
}
// If texture was assigned and color was black set color to white
var brightness = emissionColorProp.colorValue.maxColorComponent;
if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f)
emissionColorProp.colorValue = Color.white;
// UniversalRP does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right.
if (emissive)
{
var oldFlags = material.globalIlluminationFlags;
var newFlags = MaterialGlobalIlluminationFlags.BakedEmissive;
if (brightness <= 0f)
newFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
if (newFlags != oldFlags)
material.globalIlluminationFlags = newFlags;
}
}
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)
{
materialEditor.TextureScaleOffsetProperty(textureProp);
}
#endregion
////////////////////////////////////
// Material Data Functions //
////////////////////////////////////
#region MaterialDataFunctions
public static void SetMaterialKeywords(Material material, Action<Material> shadingModelFunc = null, Action<Material> shaderFunc = null)
{
// Clear all keywords for fresh start
material.shaderKeywords = null;
// Setup blending - consistent across all Universal RP shaders
SetupMaterialBlendMode(material);
// Receive Shadows
if (material.HasProperty("_ReceiveShadows"))
CoreUtils.SetKeyword(material, "_RECEIVE_SHADOWS_OFF", material.GetFloat("_ReceiveShadows") == 0.0f);
// Emission
if (material.HasProperty("_EmissionColor"))
MaterialEditor.FixupEmissiveFlag(material);
bool shouldEmissionBeEnabled =
(material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
if (material.HasProperty("_EmissionEnabled") && !shouldEmissionBeEnabled)
shouldEmissionBeEnabled = material.GetFloat("_EmissionEnabled") >= 0.5f;
CoreUtils.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
// Normal Map
if (material.HasProperty("_BumpMap"))
CoreUtils.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
// Shader specific keyword functions
shadingModelFunc?.Invoke(material);
shaderFunc?.Invoke(material);
}
public static void SetupMaterialBlendMode(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
bool alphaClip = false;
if (material.HasProperty("_AlphaClip"))
alphaClip = material.GetFloat("_AlphaClip") >= 0.5;
if (alphaClip)
{
material.EnableKeyword("_ALPHATEST_ON");
}
else
{
material.DisableKeyword("_ALPHATEST_ON");
}
if (material.HasProperty("_Surface"))
{
SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface");
if (surfaceType == SurfaceType.Opaque)
{
if (alphaClip)
{
material.renderQueue = (int)RenderQueue.AlphaTest;
material.SetOverrideTag("RenderType", "TransparentCutout");
}
else
{
material.renderQueue = (int)RenderQueue.Geometry;
material.SetOverrideTag("RenderType", "Opaque");
}
material.renderQueue += material.HasProperty("_QueueOffset") ? (int)material.GetFloat("_QueueOffset") : 0;
material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.One);
material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.Zero);
material.SetFloat("_ZWrite", 1.0f);
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.SetShaderPassEnabled("ShadowCaster", true);
}
else
{
BlendMode blendMode = (BlendMode)material.GetFloat("_Blend");
// Specific Transparent Mode Settings
switch (blendMode)
{
case BlendMode.Alpha:
material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
break;
case BlendMode.Premultiply:
material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.One);
material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
break;
case BlendMode.Additive:
material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.One);
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
break;
case BlendMode.Multiply:
material.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.DstColor);
material.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.Zero);
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.EnableKeyword("_ALPHAMODULATE_ON");
break;
}
// General Transparent Material Settings
material.SetOverrideTag("RenderType", "Transparent");
material.SetFloat("_ZWrite", 0.0f);
material.renderQueue = (int)RenderQueue.Transparent;
material.renderQueue += material.HasProperty("_QueueOffset") ? (int)material.GetFloat("_QueueOffset") : 0;
material.SetShaderPassEnabled("ShadowCaster", false);
}
}
}
#endregion
////////////////////////////////////
// Helper Functions //
////////////////////////////////////
#region HelperFunctions
public static void TwoFloatSingleLine(GUIContent title, MaterialProperty prop1, GUIContent prop1Label,
MaterialProperty prop2, GUIContent prop2Label, MaterialEditor materialEditor, float labelWidth = 30f)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop1.hasMixedValue || prop2.hasMixedValue;
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, EditorGUIUtility.singleLineHeight);
var prop1val = EditorGUI.FloatField(propRect1, prop1Label, prop1.floatValue);
Rect propRect2 = new Rect(propRect1.x + propRect1.width, rect.y,
propRect1.width, EditorGUIUtility.singleLineHeight);
var prop2val = EditorGUI.FloatField(propRect2, prop2Label, prop2.floatValue);
EditorGUI.indentLevel = indent;
EditorGUIUtility.labelWidth = preLabelWidth;
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo(title.text);
prop1.floatValue = prop1val;
prop2.floatValue = prop2val;
}
EditorGUI.showMixedValue = false;
}
public void DoPopup(GUIContent label, MaterialProperty property, string[] options)
{
DoPopup(label, property, options, materialEditor);
}
public static void DoPopup(GUIContent label, MaterialProperty property, string[] options, MaterialEditor materialEditor)
{
if (property == null)
throw new ArgumentNullException("property");
EditorGUI.showMixedValue = property.hasMixedValue;
var mode = property.floatValue;
EditorGUI.BeginChangeCheck();
mode = EditorGUILayout.Popup(label, (int)mode, options);
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo(label.text);
property.floatValue = mode;
}
EditorGUI.showMixedValue = false;
}
// 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
}
}