You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
16 KiB
320 lines
16 KiB
using UnityEngine; |
|
using UnityEngine.Rendering; |
|
|
|
namespace UnityEditor.Rendering.Universal.ShaderGUI |
|
{ |
|
public static class LitGUI |
|
{ |
|
public enum WorkflowMode |
|
{ |
|
Specular = 0, |
|
Metallic |
|
} |
|
|
|
public enum SmoothnessMapChannel |
|
{ |
|
SpecularMetallicAlpha, |
|
AlbedoAlpha, |
|
} |
|
|
|
public static class Styles |
|
{ |
|
public static GUIContent workflowModeText = EditorGUIUtility.TrTextContent("Workflow Mode", |
|
"Select a workflow that fits your textures. Choose between Metallic or Specular."); |
|
|
|
public static GUIContent specularMapText = |
|
EditorGUIUtility.TrTextContent("Specular Map", "Designates a Specular Map and specular color determining the apperance of reflections on this Material's surface."); |
|
|
|
public static GUIContent metallicMapText = |
|
EditorGUIUtility.TrTextContent("Metallic Map", "Sets and configures the map for the Metallic workflow."); |
|
|
|
public static GUIContent smoothnessText = EditorGUIUtility.TrTextContent("Smoothness", |
|
"Controls the spread of highlights and reflections on the surface."); |
|
|
|
public static GUIContent smoothnessMapChannelText = |
|
EditorGUIUtility.TrTextContent("Source", |
|
"Specifies where to sample a smoothness map from. By default, uses the alpha channel for your map."); |
|
|
|
public static GUIContent highlightsText = EditorGUIUtility.TrTextContent("Specular Highlights", |
|
"When enabled, the Material reflects the shine from direct lighting."); |
|
|
|
public static GUIContent reflectionsText = |
|
EditorGUIUtility.TrTextContent("Environment Reflections", |
|
"When enabled, the Material samples reflections from the nearest Reflection Probes or Lighting Probe."); |
|
|
|
public static GUIContent heightMapText = EditorGUIUtility.TrTextContent("Height Map", |
|
"Defines a Height Map that will drive a parallax effect in the shader making the surface seem displaced."); |
|
|
|
public static GUIContent occlusionText = EditorGUIUtility.TrTextContent("Occlusion Map", |
|
"Sets an occlusion map to simulate shadowing from ambient lighting."); |
|
|
|
public static readonly string[] metallicSmoothnessChannelNames = { "Metallic Alpha", "Albedo Alpha" }; |
|
public static readonly string[] specularSmoothnessChannelNames = { "Specular Alpha", "Albedo Alpha" }; |
|
|
|
public static GUIContent clearCoatText = EditorGUIUtility.TrTextContent("Clear Coat", |
|
"A multi-layer material feature which simulates a thin layer of coating on top of the surface material." + |
|
"\nPerformance cost is considerable as the specular component is evaluated twice, once per layer."); |
|
|
|
public static GUIContent clearCoatMaskText = EditorGUIUtility.TrTextContent("Mask", |
|
"Specifies the amount of the coat blending." + |
|
"\nActs as a multiplier of the clear coat map mask value or as a direct mask value if no map is specified." + |
|
"\nThe map specifies clear coat mask in the red channel and clear coat smoothness in the green channel."); |
|
|
|
public static GUIContent clearCoatSmoothnessText = EditorGUIUtility.TrTextContent("Smoothness", |
|
"Specifies the smoothness of the coating." + |
|
"\nActs as a multiplier of the clear coat map smoothness value or as a direct smoothness value if no map is specified."); |
|
} |
|
|
|
public struct LitProperties |
|
{ |
|
// Surface Option Props |
|
public MaterialProperty workflowMode; |
|
|
|
// Surface Input Props |
|
public MaterialProperty metallic; |
|
public MaterialProperty specColor; |
|
public MaterialProperty metallicGlossMap; |
|
public MaterialProperty specGlossMap; |
|
public MaterialProperty smoothness; |
|
public MaterialProperty smoothnessMapChannel; |
|
public MaterialProperty bumpMapProp; |
|
public MaterialProperty bumpScaleProp; |
|
public MaterialProperty parallaxMapProp; |
|
public MaterialProperty parallaxScaleProp; |
|
public MaterialProperty occlusionStrength; |
|
public MaterialProperty occlusionMap; |
|
|
|
// Advanced Props |
|
public MaterialProperty highlights; |
|
public MaterialProperty reflections; |
|
|
|
public MaterialProperty clearCoat; // Enable/Disable dummy property |
|
public MaterialProperty clearCoatMap; |
|
public MaterialProperty clearCoatMask; |
|
public MaterialProperty clearCoatSmoothness; |
|
|
|
public LitProperties(MaterialProperty[] properties) |
|
{ |
|
// Surface Option Props |
|
workflowMode = BaseShaderGUI.FindProperty("_WorkflowMode", properties, false); |
|
// Surface Input Props |
|
metallic = BaseShaderGUI.FindProperty("_Metallic", properties); |
|
specColor = BaseShaderGUI.FindProperty("_SpecColor", properties, false); |
|
metallicGlossMap = BaseShaderGUI.FindProperty("_MetallicGlossMap", properties); |
|
specGlossMap = BaseShaderGUI.FindProperty("_SpecGlossMap", properties, false); |
|
smoothness = BaseShaderGUI.FindProperty("_Smoothness", properties, false); |
|
smoothnessMapChannel = BaseShaderGUI.FindProperty("_SmoothnessTextureChannel", properties, false); |
|
bumpMapProp = BaseShaderGUI.FindProperty("_BumpMap", properties, false); |
|
bumpScaleProp = BaseShaderGUI.FindProperty("_BumpScale", properties, false); |
|
parallaxMapProp = BaseShaderGUI.FindProperty("_ParallaxMap", properties, false); |
|
parallaxScaleProp = BaseShaderGUI.FindProperty("_Parallax", properties, false); |
|
occlusionStrength = BaseShaderGUI.FindProperty("_OcclusionStrength", properties, false); |
|
occlusionMap = BaseShaderGUI.FindProperty("_OcclusionMap", properties, false); |
|
// Advanced Props |
|
highlights = BaseShaderGUI.FindProperty("_SpecularHighlights", properties, false); |
|
reflections = BaseShaderGUI.FindProperty("_EnvironmentReflections", properties, false); |
|
|
|
clearCoat = BaseShaderGUI.FindProperty("_ClearCoat", properties, false); |
|
clearCoatMap = BaseShaderGUI.FindProperty("_ClearCoatMap", properties, false); |
|
clearCoatMask = BaseShaderGUI.FindProperty("_ClearCoatMask", properties, false); |
|
clearCoatSmoothness = BaseShaderGUI.FindProperty("_ClearCoatSmoothness", properties, false); |
|
} |
|
} |
|
|
|
public static void Inputs(LitProperties properties, MaterialEditor materialEditor, Material material) |
|
{ |
|
DoMetallicSpecularArea(properties, materialEditor, material); |
|
BaseShaderGUI.DrawNormalArea(materialEditor, properties.bumpMapProp, properties.bumpScaleProp); |
|
|
|
if (HeightmapAvailable(material)) |
|
DoHeightmapArea(properties, materialEditor); |
|
|
|
if (properties.occlusionMap != null) |
|
{ |
|
materialEditor.TexturePropertySingleLine(Styles.occlusionText, properties.occlusionMap, |
|
properties.occlusionMap.textureValue != null ? properties.occlusionStrength : null); |
|
} |
|
|
|
// Check that we have all the required properties for clear coat, |
|
// otherwise we will get null ref exception from MaterialEditor GUI helpers. |
|
if (ClearCoatAvailable(material)) |
|
DoClearCoat(properties, materialEditor, material); |
|
} |
|
|
|
private static bool ClearCoatAvailable(Material material) |
|
{ |
|
return material.HasProperty("_ClearCoat") |
|
&& material.HasProperty("_ClearCoatMap") |
|
&& material.HasProperty("_ClearCoatMask") |
|
&& material.HasProperty("_ClearCoatSmoothness"); |
|
} |
|
|
|
private static bool HeightmapAvailable(Material material) |
|
{ |
|
return material.HasProperty("_Parallax") |
|
&& material.HasProperty("_ParallaxMap"); |
|
} |
|
|
|
private static void DoHeightmapArea(LitProperties properties, MaterialEditor materialEditor) |
|
{ |
|
materialEditor.TexturePropertySingleLine(Styles.heightMapText, properties.parallaxMapProp, |
|
properties.parallaxMapProp.textureValue != null ? properties.parallaxScaleProp : null); |
|
} |
|
|
|
private static bool ClearCoatEnabled(Material material) |
|
{ |
|
return material.HasProperty("_ClearCoat") && material.GetFloat("_ClearCoat") > 0.0; |
|
} |
|
|
|
public static void DoClearCoat(LitProperties properties, MaterialEditor materialEditor, Material material) |
|
{ |
|
materialEditor.ShaderProperty(properties.clearCoat, Styles.clearCoatText); |
|
var coatEnabled = material.GetFloat("_ClearCoat") > 0.0; |
|
|
|
EditorGUI.BeginDisabledGroup(!coatEnabled); |
|
{ |
|
materialEditor.TexturePropertySingleLine(Styles.clearCoatMaskText, properties.clearCoatMap, properties.clearCoatMask); |
|
|
|
EditorGUI.indentLevel += 2; |
|
|
|
// Texture and HDR color controls |
|
materialEditor.ShaderProperty(properties.clearCoatSmoothness, Styles.clearCoatSmoothnessText); |
|
|
|
EditorGUI.indentLevel -= 2; |
|
} |
|
EditorGUI.EndDisabledGroup(); |
|
} |
|
|
|
public static void DoMetallicSpecularArea(LitProperties properties, MaterialEditor materialEditor, Material material) |
|
{ |
|
string[] smoothnessChannelNames; |
|
bool hasGlossMap = false; |
|
if (properties.workflowMode == null || |
|
(WorkflowMode)properties.workflowMode.floatValue == WorkflowMode.Metallic) |
|
{ |
|
hasGlossMap = properties.metallicGlossMap.textureValue != null; |
|
smoothnessChannelNames = Styles.metallicSmoothnessChannelNames; |
|
materialEditor.TexturePropertySingleLine(Styles.metallicMapText, properties.metallicGlossMap, |
|
hasGlossMap ? null : properties.metallic); |
|
} |
|
else |
|
{ |
|
hasGlossMap = properties.specGlossMap.textureValue != null; |
|
smoothnessChannelNames = Styles.specularSmoothnessChannelNames; |
|
BaseShaderGUI.TextureColorProps(materialEditor, Styles.specularMapText, properties.specGlossMap, |
|
hasGlossMap ? null : properties.specColor); |
|
} |
|
DoSmoothness(materialEditor, material, properties.smoothness, properties.smoothnessMapChannel, smoothnessChannelNames); |
|
} |
|
|
|
internal static bool IsOpaque(Material material) |
|
{ |
|
bool opaque = true; |
|
if (material.HasProperty(Property.SurfaceType)) |
|
opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat(Property.SurfaceType) == BaseShaderGUI.SurfaceType.Opaque); |
|
return opaque; |
|
} |
|
|
|
public static void DoSmoothness(MaterialEditor materialEditor, Material material, MaterialProperty smoothness, MaterialProperty smoothnessMapChannel, string[] smoothnessChannelNames) |
|
{ |
|
EditorGUI.indentLevel += 2; |
|
|
|
materialEditor.ShaderProperty(smoothness, Styles.smoothnessText); |
|
|
|
if (smoothnessMapChannel != null) // smoothness channel |
|
{ |
|
var opaque = IsOpaque(material); |
|
EditorGUI.indentLevel++; |
|
EditorGUI.showMixedValue = smoothnessMapChannel.hasMixedValue; |
|
if (opaque) |
|
{ |
|
EditorGUI.BeginChangeCheck(); |
|
var smoothnessSource = (int)smoothnessMapChannel.floatValue; |
|
smoothnessSource = EditorGUILayout.Popup(Styles.smoothnessMapChannelText, smoothnessSource, smoothnessChannelNames); |
|
if (EditorGUI.EndChangeCheck()) |
|
smoothnessMapChannel.floatValue = smoothnessSource; |
|
} |
|
else |
|
{ |
|
EditorGUI.BeginDisabledGroup(true); |
|
EditorGUILayout.Popup(Styles.smoothnessMapChannelText, 0, smoothnessChannelNames); |
|
EditorGUI.EndDisabledGroup(); |
|
} |
|
EditorGUI.showMixedValue = false; |
|
EditorGUI.indentLevel--; |
|
} |
|
EditorGUI.indentLevel -= 2; |
|
} |
|
|
|
public static SmoothnessMapChannel GetSmoothnessMapChannel(Material material) |
|
{ |
|
int ch = (int)material.GetFloat("_SmoothnessTextureChannel"); |
|
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha) |
|
return SmoothnessMapChannel.AlbedoAlpha; |
|
|
|
return SmoothnessMapChannel.SpecularMetallicAlpha; |
|
} |
|
|
|
// (shared by all lit shaders, including shadergraph Lit Target and Lit.shader) |
|
internal static void SetupSpecularWorkflowKeyword(Material material, out bool isSpecularWorkflow) |
|
{ |
|
isSpecularWorkflow = false; // default is metallic workflow |
|
if (material.HasProperty(Property.SpecularWorkflowMode)) |
|
isSpecularWorkflow = ((WorkflowMode)material.GetFloat(Property.SpecularWorkflowMode)) == WorkflowMode.Specular; |
|
CoreUtils.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkflow); |
|
} |
|
|
|
// setup keywords for Lit.shader |
|
public static void SetMaterialKeywords(Material material) |
|
{ |
|
SetupSpecularWorkflowKeyword(material, out bool isSpecularWorkFlow); |
|
|
|
// 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) |
|
var specularGlossMap = isSpecularWorkFlow ? "_SpecGlossMap" : "_MetallicGlossMap"; |
|
var hasGlossMap = material.GetTexture(specularGlossMap) != null; |
|
|
|
CoreUtils.SetKeyword(material, "_METALLICSPECGLOSSMAP", hasGlossMap); |
|
|
|
if (material.HasProperty("_SpecularHighlights")) |
|
CoreUtils.SetKeyword(material, "_SPECULARHIGHLIGHTS_OFF", |
|
material.GetFloat("_SpecularHighlights") == 0.0f); |
|
if (material.HasProperty("_EnvironmentReflections")) |
|
CoreUtils.SetKeyword(material, "_ENVIRONMENTREFLECTIONS_OFF", |
|
material.GetFloat("_EnvironmentReflections") == 0.0f); |
|
if (material.HasProperty("_OcclusionMap")) |
|
CoreUtils.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap")); |
|
|
|
if (material.HasProperty("_ParallaxMap")) |
|
CoreUtils.SetKeyword(material, "_PARALLAXMAP", material.GetTexture("_ParallaxMap")); |
|
|
|
if (material.HasProperty("_SmoothnessTextureChannel")) |
|
{ |
|
var opaque = IsOpaque(material); |
|
CoreUtils.SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", |
|
GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha && opaque); |
|
} |
|
|
|
// Clear coat keywords are independent to remove possiblity of invalid combinations. |
|
if (ClearCoatEnabled(material)) |
|
{ |
|
var hasMap = material.HasProperty("_ClearCoatMap") && material.GetTexture("_ClearCoatMap") != null; |
|
if (hasMap) |
|
{ |
|
CoreUtils.SetKeyword(material, "_CLEARCOAT", false); |
|
CoreUtils.SetKeyword(material, "_CLEARCOATMAP", true); |
|
} |
|
else |
|
{ |
|
CoreUtils.SetKeyword(material, "_CLEARCOAT", true); |
|
CoreUtils.SetKeyword(material, "_CLEARCOATMAP", false); |
|
} |
|
} |
|
else |
|
{ |
|
CoreUtils.SetKeyword(material, "_CLEARCOAT", false); |
|
CoreUtils.SetKeyword(material, "_CLEARCOATMAP", false); |
|
} |
|
} |
|
} |
|
}
|
|
|