rabidus-test/Assets/PolyFew/BatchFewShader/Editor/BatchFewShaderGUI.cs

429 lines
22 KiB
C#
Raw Permalink Normal View History

2023-10-20 13:29:44 +03:00
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
using System;
using UnityEngine;
namespace UnityEditor
{
namespace BrainFailProductions.BatchFew
{
internal class BatchFewShaderGUI : ShaderGUI
{
public enum WorkflowMode
{
Specular,
Metallic,
Dielectric
}
public enum BlendMode
{
Opaque,
Cutout,
Fade,
// Old school alpha-blending mode, fresnel does not affect amount of transparency
Transparent
// Physically plausible transparency mode, implemented as alpha pre-multiply
}
public enum SmoothnessMapChannel
{
SpecularMetallicAlpha,
AlbedoAlpha,
}
private static class Styles
{
public static GUIContent uvSetLabel = new GUIContent("UV Set");
public static GUIContent detailMode = new GUIContent("Detail Texture Mode");
public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
public static GUIContent smoothnessMapChannelText = new GUIContent("Source", "Smoothness texture and channel");
public static GUIContent highlightsText = new GUIContent("Specular Highlights", "Specular Highlights");
public static GUIContent reflectionsText = new GUIContent("Reflections", "Glossy Reflections");
public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
public static GUIContent emissionText = new GUIContent("Emission", "Emission (RGB)");
public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent propertyMapText = new GUIContent("Attributes Texture", "Texture which holds attributes for individual materials");
public static GUIContent emissionMode = new GUIContent("Emission Mode", "None, color, or array based emission");
public static GUIContent parallaxMode = new GUIContent("Parallax Mode", "None, Offset, or POM");
public static GUIContent parallaxSteps = new GUIContent("Parallax Steps", "Number of taps to perform in Parallax Occlusion Mapping, more is more expensive");
public static string primaryMapsText = "Main Maps";
public static string secondaryMapsText = "Secondary Maps";
public static string forwardText = "Forward Rendering Options";
public static string renderingMode = "Rendering Mode";
public static string advancedText = "Advanced Options";
public static GUIContent emissiveWarning = new GUIContent("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
}
MaterialProperty blendMode = null;
MaterialProperty albedoMap = null;
MaterialProperty specularMap = null;
MaterialProperty metallicMap = null;
MaterialProperty smoothnessMapChannel = null;
MaterialProperty highlights = null;
MaterialProperty reflections = null;
MaterialProperty bumpMap = null;
MaterialProperty occlusionMap = null;
MaterialProperty heightMap = null;
MaterialProperty emissionMap = null;
MaterialProperty detailMask = null;
MaterialProperty detailAlbedoMap = null;
MaterialProperty detailNormalMap = null;
MaterialProperty uvSetSecondary = null;
MaterialProperty attrImg = null;
MaterialProperty detailMode = null;
MaterialProperty emissionMode = null;
MaterialProperty parallaxMode = null;
MaterialProperty parallaxSteps = null;
MaterialProperty detailAlbedoSingle = null;
MaterialProperty detailNormalSingle = null;
MaterialEditor m_MaterialEditor;
WorkflowMode m_WorkflowMode = WorkflowMode.Specular;
bool m_FirstTimeApply = true;
public void FindProperties(MaterialProperty[] props)
{
blendMode = FindProperty("_Mode", props);
albedoMap = FindProperty("_MainTex", props);
//alphaCutoff = FindProperty("_Cutoff", props);
specularMap = FindProperty("_SpecGlossMap", props, false);
metallicMap = FindProperty("_MetallicGlossMap", props, false);
parallaxMode = FindProperty("_ParallaxMode", props);
parallaxSteps = FindProperty("_ParallaxSteps", props);
if (specularMap != null) { m_WorkflowMode = WorkflowMode.Specular; }
else if (metallicMap != null) { m_WorkflowMode = WorkflowMode.Metallic; }
else { m_WorkflowMode = WorkflowMode.Dielectric; }
smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", props, false);
highlights = FindProperty("_SpecularHighlights", props, false);
reflections = FindProperty("_GlossyReflections", props, false);
bumpMap = FindProperty("_BumpMap", props);
heightMap = FindProperty("_ParallaxMap", props);
occlusionMap = FindProperty("_OcclusionMap", props);
emissionMap = FindProperty("_EmissionMap", props);
emissionMode = FindProperty("_EmissionMode", props);
detailMask = FindProperty("_DetailMask", props);
detailAlbedoMap = FindProperty("_DetailAlbedoMap", props);
detailNormalMap = FindProperty("_DetailNormalMap", props);
detailAlbedoSingle = FindProperty("_DetailAlbedoSingle", props);
detailNormalSingle = FindProperty("_DetailNormalSingle", props);
uvSetSecondary = FindProperty("_UVSec", props);
detailMode = FindProperty("_DetailMode", props);
attrImg = FindProperty("_AttrImg", props);
}
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
{
FindProperties(props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
m_MaterialEditor = materialEditor;
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 standard shader.
// Do this before any GUI code has been issued to prevent layout issues in subsequent GUILayout statements (case 780071)
if (m_FirstTimeApply)
{
MaterialChanged(material, m_WorkflowMode);
m_FirstTimeApply = false;
}
ShaderPropertiesGUI(material);
}
public void ShaderPropertiesGUI(Material material)
{
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
BlendModePopup();
// Primary properties
GUILayout.Label(Styles.primaryMapsText, EditorStyles.boldLabel);
m_MaterialEditor.TexturePropertySingleLine(Styles.propertyMapText, attrImg);
DoAlbedoArea(material);
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap);
m_MaterialEditor.ShaderProperty(parallaxMode, Styles.parallaxMode.text);
if (material.GetFloat("_ParallaxMode") == 2)
{
m_MaterialEditor.ShaderProperty(parallaxSteps, Styles.parallaxSteps.text);
}
if (m_WorkflowMode != WorkflowMode.Metallic)
{
DoSpecularMetallicArea();
m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap);
m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap);
}
m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask);
DoEmissionArea(material);
EditorGUILayout.Space();
// Secondary properties
GUILayout.Label(Styles.secondaryMapsText, EditorStyles.boldLabel);
m_MaterialEditor.ShaderProperty(detailMode, Styles.detailMode.text);
if (detailMode.floatValue > 0.5f)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoSingle);
m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalSingle);
}
else
{
m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoMap);
m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalMap);
}
m_MaterialEditor.ShaderProperty(uvSetSecondary, Styles.uvSetLabel.text);
// Third properties
GUILayout.Label(Styles.forwardText, EditorStyles.boldLabel);
if (highlights != null) { m_MaterialEditor.ShaderProperty(highlights, Styles.highlightsText); }
if (reflections != null) { m_MaterialEditor.ShaderProperty(reflections, Styles.reflectionsText); }
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendMode.targets) { MaterialChanged((Material)obj, m_WorkflowMode); }
}
EditorGUILayout.Space();
GUILayout.Label(Styles.advancedText, EditorStyles.boldLabel);
m_MaterialEditor.RenderQueueField();
m_MaterialEditor.EnableInstancingField();
m_MaterialEditor.DoubleSidedGIField();
}
internal void DetermineWorkflow(MaterialProperty[] props)
{
if (FindProperty("_SpecGlossMap", props, false) != null) { m_WorkflowMode = WorkflowMode.Specular; }
else if (FindProperty("_MetallicGlossMap", props, false) != null) { m_WorkflowMode = WorkflowMode.Metallic; }
else { m_WorkflowMode = WorkflowMode.Dielectric; }
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
base.AssignNewShaderToMaterial(material, oldShader, newShader);
if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
{
SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
return;
}
BlendMode blendMode = BlendMode.Opaque;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
blendMode = BlendMode.Cutout;
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
blendMode = BlendMode.Fade;
}
material.SetFloat("_Mode", (float)blendMode);
DetermineWorkflow(MaterialEditor.GetMaterialProperties(new Material[] { material }));
MaterialChanged(material, m_WorkflowMode);
}
void BlendModePopup()
{
EditorGUI.showMixedValue = blendMode.hasMixedValue;
var mode = (BlendMode)blendMode.floatValue;
EditorGUI.BeginChangeCheck();
mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
if (EditorGUI.EndChangeCheck())
{
m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode");
blendMode.floatValue = (float)mode;
}
EditorGUI.showMixedValue = false;
}
void DoAlbedoArea(Material material)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap);
if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
{
// m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
}
}
void DoEmissionArea(Material material)
{
m_MaterialEditor.ShaderProperty(emissionMode, Styles.emissionMode.text);
// Texture and HDR color controls
if (material.GetFloat("_EmissionMode") == 2)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.emissionText, emissionMap);
}
// change the GI flag and fix it up with emissive as black if necessary
//m_MaterialEditor.LightmapEmissionFlagsProperty(MaterialEditor.kMiniTextureFieldLabelIndentLevel, true);
}
void DoSpecularMetallicArea()
{
if (m_WorkflowMode == WorkflowMode.Specular)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap);
}
else if (m_WorkflowMode == WorkflowMode.Metallic)
{
m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap);
}
int indentation = 2; // align with labels of texture properties
++indentation;
if (smoothnessMapChannel != null)
m_MaterialEditor.ShaderProperty(smoothnessMapChannel, Styles.smoothnessMapChannelText, indentation);
}
static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
{
switch (blendMode)
{
case BlendMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
case BlendMode.Cutout:
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
break;
case BlendMode.Fade:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
case BlendMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
}
}
static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)
{
int ch = (int)material.GetFloat("_SmoothnessTextureChannel");
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)
return SmoothnessMapChannel.AlbedoAlpha;
else
return SmoothnessMapChannel.SpecularMetallicAlpha;
}
static void SetMaterialKeywords(Material material, WorkflowMode workflowMode)
{
// 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)
SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap") || material.GetTexture("_DetailNormalMap"));
if (workflowMode == WorkflowMode.Specular && material.HasProperty("_SpecGlossMap"))
SetKeyword(material, "_SPECGLOSSMAP", material.GetTexture("_SpecGlossMap"));
else if (workflowMode == WorkflowMode.Metallic && material.HasProperty("_MetallicGlossMap"))
SetKeyword(material, "_METALLICGLOSSMAP", material.GetTexture("_MetallicGlossMap"));
material.DisableKeyword("_PARALLAXMAP");
material.DisableKeyword("_POM");
if (material.GetTexture("_ParallaxMap"))
{
float pm = material.GetFloat("_ParallaxMode");
if (pm == 1)
{
material.EnableKeyword("_PARALLAXMAP");
}
else if (pm == 2)
{
material.EnableKeyword("_POM");
}
}
SetKeyword(material, "_DETAIL_MULX2", material.GetFloat("_DetailMode") == 0 && (material.GetTexture("_DetailAlbedoMap") || material.GetTexture("_DetailNormalMap")));
SetKeyword(material, "_DETAIL_SINGLE", material.GetFloat("_DetailMode") == 1 && (material.GetTexture("_DetailAlbedoSingle") || material.GetTexture("_DetailNormalSingle")));
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
//MaterialEditor.FixupEmissiveFlag(material);
//bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
//SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
float emode = material.GetFloat("_EmissionMode");
SetKeyword(material, "_EMISSION", emode == 2 && material.GetTexture("_EmissionMap") != null);
SetKeyword(material, "_EMISSION_COLOR", emode == 1);
if (material.HasProperty("_SmoothnessTextureChannel"))
{
SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);
}
}
public static void MaterialChanged(Material material, WorkflowMode workflowMode)
{
SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
SetMaterialKeywords(material, workflowMode);
}
static void SetKeyword(Material m, string keyword, bool state)
{
if (state)
m.EnableKeyword(keyword);
else
m.DisableKeyword(keyword);
}
}
}
}