您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
419 行
20 KiB
419 行
20 KiB
using System;
|
|
using UnityEditor.Experimental.Rendering.LightweightPipeline;
|
|
using UnityEngine;
|
|
|
|
namespace UnityEditor
|
|
{
|
|
internal class LightweightStandardGUI : ShaderGUI
|
|
{
|
|
public enum WorkflowMode : int
|
|
{
|
|
Specular = 0,
|
|
Metallic
|
|
}
|
|
|
|
public enum BlendMode : int
|
|
{
|
|
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 : int
|
|
{
|
|
SpecularMetallicAlpha,
|
|
AlbedoAlpha,
|
|
}
|
|
|
|
private static class Styles
|
|
{
|
|
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 smoothnessText = new GUIContent("Smoothness", "Smoothness value");
|
|
public static GUIContent smoothnessScaleText = new GUIContent("Smoothness", "Smoothness scale factor");
|
|
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 occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
|
|
public static GUIContent emissionText = new GUIContent("Color", "Emission (RGB)");
|
|
public static GUIContent bumpScaleNotSupported = new GUIContent("Bump scale is not supported on mobile platforms");
|
|
public static GUIContent fixNow = new GUIContent("Fix now");
|
|
|
|
public static string primaryMapsText = "Main Maps";
|
|
public static string secondaryMapsText = "Secondary Maps";
|
|
public static string forwardText = "Forward Rendering Options";
|
|
public static string workflowModeText = "Workflow Mode";
|
|
public static string renderingMode = "Rendering Mode";
|
|
public static string advancedText = "Advanced Options";
|
|
public static readonly string[] workflowNames = Enum.GetNames(typeof(WorkflowMode));
|
|
public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
|
|
public static readonly string[] metallicSmoothnessChannelNames = {"Metallic Alpha", "Albedo Alpha"};
|
|
public static readonly string[] specularSmoothnessChannelNames = {"Specular Alpha", "Albedo Alpha"};
|
|
}
|
|
|
|
#pragma warning disable 0414
|
|
private MaterialProperty workflowMode;
|
|
private MaterialProperty blendMode;
|
|
|
|
private MaterialProperty albedoColor;
|
|
private MaterialProperty albedoMap;
|
|
private MaterialProperty alphaCutoff;
|
|
|
|
private MaterialProperty smoothness;
|
|
private MaterialProperty smoothnessScale;
|
|
private MaterialProperty smoothnessMapChannel;
|
|
|
|
private MaterialProperty metallic;
|
|
private MaterialProperty specColor;
|
|
private MaterialProperty metallicGlossMap;
|
|
private MaterialProperty specGlossMap;
|
|
private MaterialProperty highlights;
|
|
private MaterialProperty reflections;
|
|
|
|
private MaterialProperty bumpScale;
|
|
private MaterialProperty bumpMap;
|
|
private MaterialProperty occlusionStrength;
|
|
private MaterialProperty occlusionMap;
|
|
private MaterialProperty emissionColorForRendering;
|
|
private MaterialProperty emissionMap;
|
|
|
|
private MaterialEditor m_MaterialEditor;
|
|
|
|
private bool m_FirstTimeApply = true;
|
|
#pragma warning restore 0414
|
|
|
|
public void FindProperties(MaterialProperty[] props)
|
|
{
|
|
workflowMode = FindProperty("_WorkflowMode", props);
|
|
blendMode = FindProperty("_Mode", props);
|
|
albedoColor = FindProperty("_Color", props);
|
|
albedoMap = FindProperty("_MainTex", props);
|
|
alphaCutoff = FindProperty("_Cutoff", props);
|
|
|
|
smoothness = FindProperty("_Glossiness", props);
|
|
smoothnessScale = FindProperty("_GlossMapScale", props, false);
|
|
smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", props, false);
|
|
|
|
metallic = FindProperty("_Metallic", props);
|
|
specColor = FindProperty("_SpecColor", props);
|
|
metallicGlossMap = FindProperty("_MetallicGlossMap", props);
|
|
specGlossMap = FindProperty("_SpecGlossMap", props);
|
|
highlights = FindProperty("_SpecularHighlights", props);
|
|
reflections = FindProperty("_GlossyReflections", props);
|
|
|
|
bumpScale = FindProperty("_BumpScale", props);
|
|
bumpMap = FindProperty("_BumpMap", props);
|
|
occlusionStrength = FindProperty("_OcclusionStrength", props);
|
|
occlusionMap = FindProperty("_OcclusionMap", props);
|
|
emissionColorForRendering = FindProperty("_EmissionColor", props);
|
|
emissionMap = FindProperty("_EmissionMap", 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 lightweight shader.
|
|
if (m_FirstTimeApply)
|
|
{
|
|
MaterialChanged(material);
|
|
m_FirstTimeApply = false;
|
|
}
|
|
|
|
ShaderPropertiesGUI(material);
|
|
}
|
|
|
|
public void ShaderPropertiesGUI(Material material)
|
|
{
|
|
// Use default labelWidth
|
|
EditorGUIUtility.labelWidth = 0f;
|
|
|
|
// Detect any changes to the material
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
DoPopup(Styles.workflowModeText, workflowMode, Styles.workflowNames);
|
|
DoPopup(Styles.renderingMode, blendMode, Styles.blendNames);
|
|
|
|
// Primary properties
|
|
GUILayout.Label(Styles.primaryMapsText, EditorStyles.boldLabel);
|
|
DoAlbedoArea(material);
|
|
DoMetallicSpecularArea();
|
|
DoNormalArea();
|
|
|
|
m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null);
|
|
|
|
DoEmissionArea(material);
|
|
EditorGUI.BeginChangeCheck();
|
|
m_MaterialEditor.TextureScaleOffsetProperty(albedoMap);
|
|
if (EditorGUI.EndChangeCheck())
|
|
emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
m_MaterialEditor.ShaderProperty(highlights, Styles.highlightsText);
|
|
m_MaterialEditor.ShaderProperty(reflections, Styles.reflectionsText);
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
foreach (var obj in blendMode.targets)
|
|
MaterialChanged((Material)obj);
|
|
}
|
|
|
|
EditorGUILayout.Space();
|
|
|
|
// NB renderqueue editor is not shown on purpose: we want to override it based on blend mode
|
|
GUILayout.Label(Styles.advancedText, EditorStyles.boldLabel);
|
|
m_MaterialEditor.EnableInstancingField();
|
|
m_MaterialEditor.DoubleSidedGIField();
|
|
}
|
|
|
|
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
|
|
{
|
|
// _Emission property is lost after assigning Standard shader to the material
|
|
// thus transfer it before assigning the new shader
|
|
if (material.HasProperty("_Emission"))
|
|
{
|
|
material.SetColor("_EmissionColor", material.GetColor("_Emission"));
|
|
}
|
|
|
|
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);
|
|
|
|
if (oldShader.name.Equals("Standard (Specular setup)"))
|
|
{
|
|
material.SetFloat("_WorkflowMode", (float) WorkflowMode.Specular);
|
|
Texture texture = material.GetTexture("_SpecGlossMap");
|
|
if (texture != null)
|
|
material.SetTexture("_MetallicSpecGlossMap", texture);
|
|
}
|
|
else
|
|
{
|
|
material.SetFloat("_WorkflowMode", (float) WorkflowMode.Metallic);
|
|
Texture texture = material.GetTexture("_MetallicGlossMap");
|
|
if (texture != null)
|
|
material.SetTexture("_MetallicSpecGlossMap", texture);
|
|
}
|
|
|
|
MaterialChanged(material);
|
|
}
|
|
|
|
private void DoPopup(string label, MaterialProperty property, string[] options)
|
|
{
|
|
EditorGUI.showMixedValue = property.hasMixedValue;
|
|
|
|
var mode = property.floatValue;
|
|
EditorGUI.BeginChangeCheck();
|
|
mode = EditorGUILayout.Popup(label, (int) mode, options);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
m_MaterialEditor.RegisterPropertyChangeUndo(label);
|
|
property.floatValue = (float)mode;
|
|
}
|
|
|
|
EditorGUI.showMixedValue = false;
|
|
}
|
|
|
|
void DoNormalArea()
|
|
{
|
|
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
|
|
if (bumpScale.floatValue != 1 && UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(EditorUserBuildSettings.activeBuildTarget))
|
|
if (m_MaterialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNow))
|
|
bumpScale.floatValue = 1;
|
|
}
|
|
|
|
void DoAlbedoArea(Material material)
|
|
{
|
|
m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
|
|
if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
|
|
{
|
|
m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
|
|
}
|
|
}
|
|
|
|
void DoEmissionArea(Material material)
|
|
{
|
|
// Emission for GI?
|
|
if (m_MaterialEditor.EmissionEnabledProperty())
|
|
{
|
|
bool hadEmissionTexture = emissionMap.textureValue != null;
|
|
|
|
// Texture and HDR color controls
|
|
m_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionText, emissionMap, emissionColorForRendering, false);
|
|
|
|
// If texture was assigned and color was black set color to white
|
|
float brightness = emissionColorForRendering.colorValue.maxColorComponent;
|
|
if (emissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f)
|
|
emissionColorForRendering.colorValue = Color.white;
|
|
|
|
// LW does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right.
|
|
material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.BakedEmissive;
|
|
if (brightness <= 0f)
|
|
material.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
|
|
}
|
|
}
|
|
|
|
void DoMetallicSpecularArea()
|
|
{
|
|
string[] metallicSpecSmoothnessChannelName;
|
|
bool hasGlossMap = false;
|
|
if ((WorkflowMode) workflowMode.floatValue == WorkflowMode.Metallic)
|
|
{
|
|
hasGlossMap = metallicGlossMap.textureValue != null;
|
|
metallicSpecSmoothnessChannelName = Styles.metallicSmoothnessChannelNames;
|
|
m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicGlossMap,
|
|
hasGlossMap ? null : metallic);
|
|
}
|
|
else
|
|
{
|
|
hasGlossMap = specGlossMap.textureValue != null;
|
|
metallicSpecSmoothnessChannelName = Styles.specularSmoothnessChannelNames;
|
|
m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specGlossMap,
|
|
hasGlossMap ? null : specColor);
|
|
}
|
|
|
|
bool showSmoothnessScale = hasGlossMap;
|
|
if (smoothnessMapChannel != null)
|
|
{
|
|
int smoothnessChannel = (int)smoothnessMapChannel.floatValue;
|
|
if (smoothnessChannel == (int)SmoothnessMapChannel.AlbedoAlpha)
|
|
showSmoothnessScale = true;
|
|
}
|
|
|
|
int indentation = 2; // align with labels of texture properties
|
|
m_MaterialEditor.ShaderProperty(showSmoothnessScale ? smoothnessScale : smoothness, showSmoothnessScale ? Styles.smoothnessScaleText : Styles.smoothnessText, indentation);
|
|
|
|
int prevIndentLevel = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = 3;
|
|
if (smoothnessMapChannel != null)
|
|
DoPopup(Styles.smoothnessMapChannelText.text, smoothnessMapChannel, metallicSpecSmoothnessChannelName);
|
|
EditorGUI.indentLevel = prevIndentLevel;
|
|
}
|
|
|
|
public 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)
|
|
{
|
|
// 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)
|
|
bool isSpecularWorkFlow = (WorkflowMode)material.GetFloat("_WorkflowMode") == WorkflowMode.Specular;
|
|
bool hasGlossMap = false;
|
|
if (isSpecularWorkFlow)
|
|
hasGlossMap = material.GetTexture("_SpecGlossMap");
|
|
else
|
|
hasGlossMap = material.GetTexture("_MetallicGlossMap");
|
|
|
|
LightweightShaderHelper.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkFlow);
|
|
|
|
LightweightShaderHelper.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap);
|
|
LightweightShaderHelper.SetKeyword(material, "_SPECGLOSSMAP", hasGlossMap && isSpecularWorkFlow);
|
|
LightweightShaderHelper.SetKeyword(material, "_METALLICGLOSSMAP", hasGlossMap && !isSpecularWorkFlow);
|
|
|
|
LightweightShaderHelper.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
|
|
|
|
LightweightShaderHelper.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", material.GetFloat("_SpecularHighlights") == 0.0f);
|
|
LightweightShaderHelper.SetKeyword(material, "_GLOSSYREFLECTIONS_OFF", material.GetFloat("_GlossyReflections") == 0.0f);
|
|
|
|
LightweightShaderHelper.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap"));
|
|
LightweightShaderHelper.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap"));
|
|
LightweightShaderHelper.SetKeyword(material, "_DETAIL_MULX2", material.GetTexture("_DetailAlbedoMap") || material.GetTexture("_DetailNormalMap"));
|
|
|
|
// 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;
|
|
LightweightShaderHelper.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
|
|
|
|
if (material.HasProperty("_SmoothnessTextureChannel"))
|
|
{
|
|
LightweightShaderHelper.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);
|
|
}
|
|
}
|
|
|
|
static void MaterialChanged(Material material)
|
|
{
|
|
material.shaderKeywords = null;
|
|
SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
|
|
SetMaterialKeywords(material);
|
|
}
|
|
}
|
|
}
|