This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,619 @@
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
}
}

View File

@@ -0,0 +1,466 @@
using UnityEngine;
using UnityEditorInternal;
using System.Linq;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
[MovedFrom("UnityEditor.Rendering.LWRP.ShaderGUI")] public static class ParticleGUI
{
public enum ColorMode
{
Multiply,
Additive,
Subtractive,
Overlay,
Color,
Difference
}
public static class Styles
{
public static GUIContent colorMode = new GUIContent("Color Mode",
"Controls how the Particle color and the Material color blend together.");
public static GUIContent flipbookMode = new GUIContent("Flip-Book Blending",
"Blends the frames in a flip-book together in a smooth animation.");
public static GUIContent softParticlesEnabled = new GUIContent("Soft Particles",
"Makes particles fade out when they get close to intersecting with the surface of other geometry in the depth buffer.");
public static GUIContent softParticlesNearFadeDistanceText =
new GUIContent("Near",
"The distance from the other surface where the particle is completely transparent.");
public static GUIContent softParticlesFarFadeDistanceText =
new GUIContent("Far",
"The distance from the other surface where the particle is completely opaque.");
public static GUIContent cameraFadingEnabled = new GUIContent("Camera Fading",
"Makes particles fade out when they get close to the camera.");
public static GUIContent cameraNearFadeDistanceText =
new GUIContent("Near",
"The distance from the camera where the particle is completely transparent.");
public static GUIContent cameraFarFadeDistanceText =
new GUIContent("Far", "The distance from the camera where the particle is completely opaque.");
public static GUIContent distortionEnabled = new GUIContent("Distortion",
"Creates a distortion effect by making particles perform refraction with the objects drawn before them.");
public static GUIContent distortionStrength = new GUIContent("Strength",
"Controls how much the Particle distorts the background. ");
public static GUIContent distortionBlend = new GUIContent("Blend",
"Controls how visible the distortion effect is. At 0, theres no visible distortion. At 1, only the distortion effect is visible, not the background.");
public static GUIContent VertexStreams = new GUIContent("Vertex Streams",
"The vertex streams needed for this Material to function properly.");
public static string streamPositionText = "Position (POSITION.xyz)";
public static string streamNormalText = "Normal (NORMAL.xyz)";
public static string streamColorText = "Color (COLOR.xyzw)";
public static string streamColorInstancedText = "Color (INSTANCED0.xyzw)";
public static string streamUVText = "UV (TEXCOORD0.xy)";
public static string streamUV2Text = "UV2 (TEXCOORD0.zw)";
public static string streamAnimBlendText = "AnimBlend (TEXCOORD1.x)";
public static string streamAnimFrameText = "AnimFrame (INSTANCED1.x)";
public static string streamTangentText = "Tangent (TANGENT.xyzw)";
public static GUIContent streamApplyToAllSystemsText = new GUIContent("Fix Now",
"Apply the vertex stream layout to all Particle Systems using this material");
public static string undoApplyCustomVertexStreams = L10n.Tr("Apply custom vertex streams from material");
public static GUIStyle vertexStreamIcon = new GUIStyle();
}
private static ReorderableList vertexStreamList;
public struct ParticleProperties
{
// Surface Option Props
public MaterialProperty colorMode;
// Advanced Props
public MaterialProperty flipbookMode;
public MaterialProperty softParticlesEnabled;
public MaterialProperty cameraFadingEnabled;
public MaterialProperty distortionEnabled;
public MaterialProperty softParticlesNearFadeDistance;
public MaterialProperty softParticlesFarFadeDistance;
public MaterialProperty cameraNearFadeDistance;
public MaterialProperty cameraFarFadeDistance;
public MaterialProperty distortionBlend;
public MaterialProperty distortionStrength;
public ParticleProperties(MaterialProperty[] properties)
{
// Surface Option Props
colorMode = BaseShaderGUI.FindProperty("_ColorMode", properties, false);
// Advanced Props
flipbookMode = BaseShaderGUI.FindProperty("_FlipbookBlending", properties);
softParticlesEnabled = BaseShaderGUI.FindProperty("_SoftParticlesEnabled", properties);
cameraFadingEnabled = BaseShaderGUI.FindProperty("_CameraFadingEnabled", properties);
distortionEnabled = BaseShaderGUI.FindProperty("_DistortionEnabled", properties, false);
softParticlesNearFadeDistance = BaseShaderGUI.FindProperty("_SoftParticlesNearFadeDistance", properties);
softParticlesFarFadeDistance = BaseShaderGUI.FindProperty("_SoftParticlesFarFadeDistance", properties);
cameraNearFadeDistance = BaseShaderGUI.FindProperty("_CameraNearFadeDistance", properties);
cameraFarFadeDistance = BaseShaderGUI.FindProperty("_CameraFarFadeDistance", properties);
distortionBlend = BaseShaderGUI.FindProperty("_DistortionBlend", properties, false);
distortionStrength = BaseShaderGUI.FindProperty("_DistortionStrength", properties, false);
}
}
public static void SetupMaterialWithColorMode(Material material)
{
var colorMode = (ColorMode)material.GetFloat("_ColorMode");
switch (colorMode)
{
case ColorMode.Multiply:
material.DisableKeyword("_COLOROVERLAY_ON");
material.DisableKeyword("_COLORCOLOR_ON");
material.DisableKeyword("_COLORADDSUBDIFF_ON");
break;
case ColorMode.Overlay:
material.DisableKeyword("_COLORCOLOR_ON");
material.DisableKeyword("_COLORADDSUBDIFF_ON");
material.EnableKeyword("_COLOROVERLAY_ON");
break;
case ColorMode.Color:
material.DisableKeyword("_COLOROVERLAY_ON");
material.DisableKeyword("_COLORADDSUBDIFF_ON");
material.EnableKeyword("_COLORCOLOR_ON");
break;
case ColorMode.Difference:
material.DisableKeyword("_COLOROVERLAY_ON");
material.DisableKeyword("_COLORCOLOR_ON");
material.EnableKeyword("_COLORADDSUBDIFF_ON");
material.SetVector("_BaseColorAddSubDiff", new Vector4(-1.0f, 1.0f, 0.0f, 0.0f));
break;
case ColorMode.Additive:
material.DisableKeyword("_COLOROVERLAY_ON");
material.DisableKeyword("_COLORCOLOR_ON");
material.EnableKeyword("_COLORADDSUBDIFF_ON");
material.SetVector("_BaseColorAddSubDiff", new Vector4(1.0f, 0.0f, 0.0f, 0.0f));
break;
case ColorMode.Subtractive:
material.DisableKeyword("_COLOROVERLAY_ON");
material.DisableKeyword("_COLORCOLOR_ON");
material.EnableKeyword("_COLORADDSUBDIFF_ON");
material.SetVector("_BaseColorAddSubDiff", new Vector4(-1.0f, 0.0f, 0.0f, 0.0f));
break;
}
}
public static void FadingOptions(Material material, MaterialEditor materialEditor, ParticleProperties properties)
{
// Z write doesn't work with fading
bool hasZWrite = (material.GetFloat("_ZWrite") > 0.0f);
if (!hasZWrite)
{
// Soft Particles
{
EditorGUI.showMixedValue = properties.softParticlesEnabled.hasMixedValue;
var enabled = properties.softParticlesEnabled.floatValue;
EditorGUI.BeginChangeCheck();
enabled = EditorGUILayout.Toggle(Styles.softParticlesEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo("Soft Particles Enabled");
properties.softParticlesEnabled.floatValue = enabled;
}
if (enabled >= 0.5f)
{
UniversalRenderPipelineAsset urpAsset = UniversalRenderPipeline.asset;
if (urpAsset != null && !urpAsset.supportsCameraDepthTexture)
{
GUIStyle warnStyle = new GUIStyle(GUI.skin.label);
warnStyle.fontStyle = FontStyle.BoldAndItalic;
warnStyle.wordWrap = true;
EditorGUILayout.HelpBox("Soft Particles require depth texture. Please enable \"Depth Texture\" in the Universal Render Pipeline settings.", MessageType.Warning);
}
EditorGUI.indentLevel++;
BaseShaderGUI.TwoFloatSingleLine(new GUIContent("Surface Fade"),
properties.softParticlesNearFadeDistance,
Styles.softParticlesNearFadeDistanceText,
properties.softParticlesFarFadeDistance,
Styles.softParticlesFarFadeDistanceText,
materialEditor);
EditorGUI.indentLevel--;
}
}
// Camera Fading
{
EditorGUI.showMixedValue = properties.cameraFadingEnabled.hasMixedValue;
var enabled = properties.cameraFadingEnabled.floatValue;
EditorGUI.BeginChangeCheck();
enabled = EditorGUILayout.Toggle(Styles.cameraFadingEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo("Camera Fading Enabled");
properties.cameraFadingEnabled.floatValue = enabled;
}
if (enabled >= 0.5f)
{
EditorGUI.indentLevel++;
BaseShaderGUI.TwoFloatSingleLine(new GUIContent("Distance"),
properties.cameraNearFadeDistance,
Styles.cameraNearFadeDistanceText,
properties.cameraFarFadeDistance,
Styles.cameraFarFadeDistanceText,
materialEditor);
EditorGUI.indentLevel--;
}
}
// Distortion
if (properties.distortionEnabled != null)
{
EditorGUI.showMixedValue = properties.distortionEnabled.hasMixedValue;
var enabled = properties.distortionEnabled.floatValue;
EditorGUI.BeginChangeCheck();
enabled = EditorGUILayout.Toggle(Styles.distortionEnabled, enabled != 0.0f) ? 1.0f : 0.0f;
if (EditorGUI.EndChangeCheck())
{
materialEditor.RegisterPropertyChangeUndo("Distortion Enabled");
properties.distortionEnabled.floatValue = enabled;
}
if (enabled >= 0.5f)
{
EditorGUI.indentLevel++;
materialEditor.ShaderProperty(properties.distortionStrength, Styles.distortionStrength);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.distortionStrength.hasMixedValue;
var blend = EditorGUILayout.Slider(Styles.distortionBlend, properties.distortionBlend.floatValue, 0f, 1f);
if (EditorGUI.EndChangeCheck())
properties.distortionBlend.floatValue = blend;
EditorGUI.indentLevel--;
}
}
EditorGUI.showMixedValue = false;
}
}
public static void DoVertexStreamsArea(Material material, List<ParticleSystemRenderer> renderers, bool useLighting = false)
{
EditorGUILayout.Space();
// Display list of streams required to make this shader work
bool useNormalMap = false;
bool useFlipbookBlending = (material.GetFloat("_FlipbookBlending") > 0.0f);
if (material.HasProperty("_BumpMap"))
useNormalMap = material.GetTexture("_BumpMap");
bool useGPUInstancing = ShaderUtil.HasProceduralInstancing(material.shader);
if (useGPUInstancing && renderers.Count > 0)
{
if (!renderers[0].enableGPUInstancing || renderers[0].renderMode != ParticleSystemRenderMode.Mesh)
useGPUInstancing = false;
}
// Build the list of expected vertex streams
List<ParticleSystemVertexStream> streams = new List<ParticleSystemVertexStream>();
List<string> streamList = new List<string>();
streams.Add(ParticleSystemVertexStream.Position);
streamList.Add(Styles.streamPositionText);
if (useLighting || useNormalMap)
{
streams.Add(ParticleSystemVertexStream.Normal);
streamList.Add(Styles.streamNormalText);
if (useNormalMap)
{
streams.Add(ParticleSystemVertexStream.Tangent);
streamList.Add(Styles.streamTangentText);
}
}
streams.Add(ParticleSystemVertexStream.Color);
streamList.Add(useGPUInstancing ? Styles.streamColorInstancedText : Styles.streamColorText);
streams.Add(ParticleSystemVertexStream.UV);
streamList.Add(Styles.streamUVText);
List<ParticleSystemVertexStream> instancedStreams = new List<ParticleSystemVertexStream>(streams);
if (useGPUInstancing)
{
instancedStreams.Add(ParticleSystemVertexStream.AnimFrame);
streamList.Add(Styles.streamAnimFrameText);
}
else if (useFlipbookBlending && !useGPUInstancing)
{
streams.Add(ParticleSystemVertexStream.UV2);
streamList.Add(Styles.streamUV2Text);
streams.Add(ParticleSystemVertexStream.AnimBlend);
streamList.Add(Styles.streamAnimBlendText);
}
vertexStreamList = new ReorderableList(streamList, typeof(string), false, true, false, false);
vertexStreamList.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "Vertex Streams");
};
vertexStreamList.DoLayoutList();
// Display a warning if any renderers have incorrect vertex streams
string Warnings = "";
List<ParticleSystemVertexStream> rendererStreams = new List<ParticleSystemVertexStream>();
foreach (ParticleSystemRenderer renderer in renderers)
{
renderer.GetActiveVertexStreams(rendererStreams);
bool streamsValid;
if (useGPUInstancing && renderer.renderMode == ParticleSystemRenderMode.Mesh && renderer.supportsMeshInstancing)
streamsValid = CompareVertexStreams(rendererStreams, instancedStreams);
else
streamsValid = CompareVertexStreams(rendererStreams, instancedStreams);
if (!streamsValid)
Warnings += "-" + renderer.name + "\n";
}
if (!string.IsNullOrEmpty(Warnings))
{
EditorGUILayout.HelpBox(
"The following Particle System Renderers are using this material with incorrect Vertex Streams:\n" +
Warnings, MessageType.Error, true);
// Set the streams on all systems using this material
if (GUILayout.Button(Styles.streamApplyToAllSystemsText, EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
Undo.RecordObjects(renderers.Where(r => r != null).ToArray(), Styles.undoApplyCustomVertexStreams);
foreach (ParticleSystemRenderer renderer in renderers)
{
if (useGPUInstancing && renderer.renderMode == ParticleSystemRenderMode.Mesh && renderer.supportsMeshInstancing)
renderer.SetActiveVertexStreams(instancedStreams);
else
renderer.SetActiveVertexStreams(streams);
}
}
}
}
private static bool CompareVertexStreams(IEnumerable<ParticleSystemVertexStream> a, IEnumerable<ParticleSystemVertexStream> b)
{
var differenceA = a.Except(b);
var differenceB = b.Except(a);
var difference = differenceA.Union(differenceB).Distinct();
if (!difference.Any())
return true;
// If normals are the only difference, ignore them, because the default particle streams include normals, to make it easy for users to switch between lit and unlit
if (difference.Count() == 1)
{
if (difference.First() == ParticleSystemVertexStream.Normal)
return true;
}
return false;
}
public static void SetMaterialKeywords(Material material)
{
// Setup particle + material color blending
SetupMaterialWithColorMode(material);
// Is the material transparent, this is set in BaseShaderGUI
bool isTransparent = material.GetTag("RenderType", false) == "Transparent";
// Z write doesn't work with distortion/fading
bool hasZWrite = (material.GetFloat("_ZWrite") > 0.0f);
// Flipbook blending
if (material.HasProperty("_FlipbookBlending"))
{
var useFlipbookBlending = (material.GetFloat("_FlipbookBlending") > 0.0f);
CoreUtils.SetKeyword(material, "_FLIPBOOKBLENDING_ON", useFlipbookBlending);
}
// Soft particles
var useSoftParticles = false;
if (material.HasProperty("_SoftParticlesEnabled"))
{
useSoftParticles = (material.GetFloat("_SoftParticlesEnabled") > 0.0f && isTransparent);
if (useSoftParticles)
{
var softParticlesNearFadeDistance = material.GetFloat("_SoftParticlesNearFadeDistance");
var softParticlesFarFadeDistance = material.GetFloat("_SoftParticlesFarFadeDistance");
// clamp values
if (softParticlesNearFadeDistance < 0.0f)
{
softParticlesNearFadeDistance = 0.0f;
material.SetFloat("_SoftParticlesNearFadeDistance", 0.0f);
}
if (softParticlesFarFadeDistance < 0.0f)
{
softParticlesFarFadeDistance = 0.0f;
material.SetFloat("_SoftParticlesFarFadeDistance", 0.0f);
}
// set keywords
material.SetVector("_SoftParticleFadeParams",
new Vector4(softParticlesNearFadeDistance,
1.0f / (softParticlesFarFadeDistance - softParticlesNearFadeDistance), 0.0f, 0.0f));
}
else
{
material.SetVector("_SoftParticleFadeParams", new Vector4(0.0f, 0.0f, 0.0f, 0.0f));
}
CoreUtils.SetKeyword(material, "_SOFTPARTICLES_ON", useSoftParticles);
}
// Camera fading
var useCameraFading = false;
if (material.HasProperty("_CameraFadingEnabled") && isTransparent)
{
useCameraFading = (material.GetFloat("_CameraFadingEnabled") > 0.0f);
if (useCameraFading)
{
var cameraNearFadeDistance = material.GetFloat("_CameraNearFadeDistance");
var cameraFarFadeDistance = material.GetFloat("_CameraFarFadeDistance");
// clamp values
if (cameraNearFadeDistance < 0.0f)
{
cameraNearFadeDistance = 0.0f;
material.SetFloat("_CameraNearFadeDistance", 0.0f);
}
if (cameraFarFadeDistance < 0.0f)
{
cameraFarFadeDistance = 0.0f;
material.SetFloat("_CameraFarFadeDistance", 0.0f);
}
// set keywords
material.SetVector("_CameraFadeParams",
new Vector4(cameraNearFadeDistance, 1.0f / (cameraFarFadeDistance - cameraNearFadeDistance),
0.0f, 0.0f));
}
else
{
material.SetVector("_CameraFadeParams", new Vector4(0.0f, Mathf.Infinity, 0.0f, 0.0f));
}
}
// Distortion
if (material.HasProperty("_DistortionEnabled"))
{
var useDistortion = (material.GetFloat("_DistortionEnabled") > 0.0f) && isTransparent;
CoreUtils.SetKeyword(material, "_DISTORTION_ON", useDistortion);
if (useDistortion)
material.SetFloat("_DistortionStrengthScaled", material.GetFloat("_DistortionStrength") * 0.1f);
}
var useFading = (useSoftParticles || useCameraFading) && !hasZWrite;
CoreUtils.SetKeyword(material, "_FADING_ON", useFading);
}
}
} // namespace UnityEditor

View File

@@ -0,0 +1,107 @@
using System;
using UnityEngine;
using UnityEditor.Rendering.Universal;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class BakedLitShader : BaseShaderGUI
{
// Properties
private BakedLitGUI.BakedLitProperties shadingModelProperties;
// collect properties from the material properties
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
shadingModelProperties = new BakedLitGUI.BakedLitProperties(properties);
}
// material changed check
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material);
}
// material main surface options
public override void DrawSurfaceOptions(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
// material main surface inputs
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
BakedLitGUI.Inputs(shadingModelProperties, materialEditor);
DrawTileOffset(materialEditor, baseMapProp);
}
public override void DrawAdvancedOptions(Material material)
{
EditorGUI.BeginChangeCheck();
base.DrawAdvancedOptions(material);
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
if (material == null)
throw new ArgumentNullException("material");
// _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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (float)blendMode);
MaterialChanged(material);
}
}
}

View File

@@ -0,0 +1,150 @@
using System;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class LitShader : BaseShaderGUI
{
private LitGUI.LitProperties litProperties;
private LitDetailGUI.LitProperties litDetailProperties;
private SavedBool m_DetailInputsFoldout;
public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
base.OnOpenGUI(material, materialEditor);
m_DetailInputsFoldout = new SavedBool($"{headerStateKey}.DetailInputsFoldout", true);
}
public override void DrawAdditionalFoldouts(Material material)
{
m_DetailInputsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_DetailInputsFoldout.value, LitDetailGUI.Styles.detailInputs);
if (m_DetailInputsFoldout.value)
{
LitDetailGUI.DoDetailArea(litDetailProperties, materialEditor);
EditorGUILayout.Space();
}
EditorGUILayout.EndFoldoutHeaderGroup();
}
// collect properties from the material properties
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
litProperties = new LitGUI.LitProperties(properties);
litDetailProperties = new LitDetailGUI.LitProperties(properties);
}
// material changed check
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material, LitGUI.SetMaterialKeywords, LitDetailGUI.SetMaterialKeywords);
}
// material main surface options
public override void DrawSurfaceOptions(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
if (litProperties.workflowMode != null)
{
DoPopup(LitGUI.Styles.workflowModeText, litProperties.workflowMode, Enum.GetNames(typeof(LitGUI.WorkflowMode)));
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
base.DrawSurfaceOptions(material);
}
// material main surface inputs
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
LitGUI.Inputs(litProperties, materialEditor, material);
DrawEmissionProperties(material, true);
DrawTileOffset(materialEditor, baseMapProp);
}
// material main advanced options
public override void DrawAdvancedOptions(Material material)
{
if (litProperties.reflections != null && litProperties.highlights != null)
{
EditorGUI.BeginChangeCheck();
materialEditor.ShaderProperty(litProperties.highlights, LitGUI.Styles.highlightsText);
materialEditor.ShaderProperty(litProperties.reflections, LitGUI.Styles.reflectionsText);
if (EditorGUI.EndChangeCheck())
{
MaterialChanged(material);
}
}
base.DrawAdvancedOptions(material);
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
if (material == null)
throw new ArgumentNullException("material");
// _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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (float)blendMode);
if (oldShader.name.Equals("Standard (Specular setup)"))
{
material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Specular);
Texture texture = material.GetTexture("_SpecGlossMap");
if (texture != null)
material.SetTexture("_MetallicSpecGlossMap", texture);
}
else
{
material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Metallic);
Texture texture = material.GetTexture("_MetallicGlossMap");
if (texture != null)
material.SetTexture("_MetallicSpecGlossMap", texture);
}
MaterialChanged(material);
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class ParticlesLitShader : BaseShaderGUI
{
// Properties
private LitGUI.LitProperties litProperties;
private ParticleGUI.ParticleProperties particleProps;
// List of renderers using this material in the scene, used for validating vertex streams
List<ParticleSystemRenderer> m_RenderersUsingThisMaterial = new List<ParticleSystemRenderer>();
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
litProperties = new LitGUI.LitProperties(properties);
particleProps = new ParticleGUI.ParticleProperties(properties);
}
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material, LitGUI.SetMaterialKeywords, ParticleGUI.SetMaterialKeywords);
}
public override void DrawSurfaceOptions(Material material)
{
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
DoPopup(ParticleGUI.Styles.colorMode, particleProps.colorMode, Enum.GetNames(typeof(ParticleGUI.ColorMode)));
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
LitGUI.Inputs(litProperties, materialEditor, material);
DrawEmissionProperties(material, true);
}
public override void DrawAdvancedOptions(Material material)
{
EditorGUI.BeginChangeCheck();
{
materialEditor.ShaderProperty(particleProps.flipbookMode, ParticleGUI.Styles.flipbookMode);
ParticleGUI.FadingOptions(material, materialEditor, particleProps);
ParticleGUI.DoVertexStreamsArea(material, m_RenderersUsingThisMaterial, true);
if (EditorGUI.EndChangeCheck())
{
MaterialChanged(material);
}
}
DrawQueueOffsetField();
}
public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
CacheRenderersUsingThisMaterial(material);
base.OnOpenGUI(material, materialEditor);
}
void CacheRenderersUsingThisMaterial(Material material)
{
m_RenderersUsingThisMaterial.Clear();
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsOfType(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[];
foreach (ParticleSystemRenderer renderer in renderers)
{
if (renderer.sharedMaterial == material)
m_RenderersUsingThisMaterial.Add(renderer);
}
}
}
} // namespace UnityEditor

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class ParticlesSimpleLitShader : BaseShaderGUI
{
// Properties
private SimpleLitGUI.SimpleLitProperties shadingModelProperties;
private ParticleGUI.ParticleProperties particleProps;
// List of renderers using this material in the scene, used for validating vertex streams
List<ParticleSystemRenderer> m_RenderersUsingThisMaterial = new List<ParticleSystemRenderer>();
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
shadingModelProperties = new SimpleLitGUI.SimpleLitProperties(properties);
particleProps = new ParticleGUI.ParticleProperties(properties);
}
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material, SimpleLitGUI.SetMaterialKeywords, ParticleGUI.SetMaterialKeywords);
}
public override void DrawSurfaceOptions(Material material)
{
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
DoPopup(ParticleGUI.Styles.colorMode, particleProps.colorMode, Enum.GetNames(typeof(ParticleGUI.ColorMode)));
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
SimpleLitGUI.Inputs(shadingModelProperties, materialEditor, material);
DrawEmissionProperties(material, true);
}
public override void DrawAdvancedOptions(Material material)
{
SimpleLitGUI.Advanced(shadingModelProperties);
EditorGUI.BeginChangeCheck();
{
materialEditor.ShaderProperty(particleProps.flipbookMode, ParticleGUI.Styles.flipbookMode);
ParticleGUI.FadingOptions(material, materialEditor, particleProps);
ParticleGUI.DoVertexStreamsArea(material, m_RenderersUsingThisMaterial, true);
if (EditorGUI.EndChangeCheck())
{
MaterialChanged(material);
}
}
DrawQueueOffsetField();
}
public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
CacheRenderersUsingThisMaterial(material);
base.OnOpenGUI(material, materialEditor);
}
void CacheRenderersUsingThisMaterial(Material material)
{
m_RenderersUsingThisMaterial.Clear();
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsOfType(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[];
foreach (ParticleSystemRenderer renderer in renderers)
{
if (renderer.sharedMaterial == material)
m_RenderersUsingThisMaterial.Add(renderer);
}
}
}
} // namespace UnityEditor

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class ParticlesUnlitShader : BaseShaderGUI
{
// Properties
private BakedLitGUI.BakedLitProperties shadingModelProperties;
private ParticleGUI.ParticleProperties particleProps;
// List of renderers using this material in the scene, used for validating vertex streams
List<ParticleSystemRenderer> m_RenderersUsingThisMaterial = new List<ParticleSystemRenderer>();
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
shadingModelProperties = new BakedLitGUI.BakedLitProperties(properties);
particleProps = new ParticleGUI.ParticleProperties(properties);
}
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material, null, ParticleGUI.SetMaterialKeywords);
}
public override void DrawSurfaceOptions(Material material)
{
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
DoPopup(ParticleGUI.Styles.colorMode, particleProps.colorMode, Enum.GetNames(typeof(ParticleGUI.ColorMode)));
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
BakedLitGUI.Inputs(shadingModelProperties, materialEditor);
DrawEmissionProperties(material, true);
}
public override void DrawAdvancedOptions(Material material)
{
EditorGUI.BeginChangeCheck();
{
materialEditor.ShaderProperty(particleProps.flipbookMode, ParticleGUI.Styles.flipbookMode);
ParticleGUI.FadingOptions(material, materialEditor, particleProps);
ParticleGUI.DoVertexStreamsArea(material, m_RenderersUsingThisMaterial);
if (EditorGUI.EndChangeCheck())
{
MaterialChanged(material);
}
}
DrawQueueOffsetField();
}
public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
{
CacheRenderersUsingThisMaterial(material);
base.OnOpenGUI(material, materialEditor);
}
void CacheRenderersUsingThisMaterial(Material material)
{
m_RenderersUsingThisMaterial.Clear();
ParticleSystemRenderer[] renderers = UnityEngine.Object.FindObjectsOfType(typeof(ParticleSystemRenderer)) as ParticleSystemRenderer[];
foreach (ParticleSystemRenderer renderer in renderers)
{
if (renderer.sharedMaterial == material)
m_RenderersUsingThisMaterial.Add(renderer);
}
}
}
} // namespace UnityEditor

View File

@@ -0,0 +1,103 @@
using System;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class SimpleLitShader : BaseShaderGUI
{
// Properties
private SimpleLitGUI.SimpleLitProperties shadingModelProperties;
// collect properties from the material properties
public override void FindProperties(MaterialProperty[] properties)
{
base.FindProperties(properties);
shadingModelProperties = new SimpleLitGUI.SimpleLitProperties(properties);
}
// material changed check
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material, SimpleLitGUI.SetMaterialKeywords);
}
// material main surface options
public override void DrawSurfaceOptions(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
// material main surface inputs
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
SimpleLitGUI.Inputs(shadingModelProperties, materialEditor, material);
DrawEmissionProperties(material, true);
DrawTileOffset(materialEditor, baseMapProp);
}
public override void DrawAdvancedOptions(Material material)
{
SimpleLitGUI.Advanced(shadingModelProperties);
base.DrawAdvancedOptions(material);
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
if (material == null)
throw new ArgumentNullException("material");
// _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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (float)blendMode);
MaterialChanged(material);
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using UnityEngine;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class UnlitShader : BaseShaderGUI
{
// material changed check
public override void MaterialChanged(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
SetMaterialKeywords(material);
}
// material main surface options
public override void DrawSurfaceOptions(Material material)
{
if (material == null)
throw new ArgumentNullException("material");
// Use default labelWidth
EditorGUIUtility.labelWidth = 0f;
// Detect any changes to the material
EditorGUI.BeginChangeCheck();
{
base.DrawSurfaceOptions(material);
}
if (EditorGUI.EndChangeCheck())
{
foreach (var obj in blendModeProp.targets)
MaterialChanged((Material)obj);
}
}
// material main surface inputs
public override void DrawSurfaceInputs(Material material)
{
base.DrawSurfaceInputs(material);
DrawTileOffset(materialEditor, baseMapProp);
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
{
if (material == null)
throw new ArgumentNullException("material");
// _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/"))
{
SetupMaterialBlendMode(material);
return;
}
SurfaceType surfaceType = SurfaceType.Opaque;
BlendMode blendMode = BlendMode.Alpha;
if (oldShader.name.Contains("/Transparent/Cutout/"))
{
surfaceType = SurfaceType.Opaque;
material.SetFloat("_AlphaClip", 1);
}
else if (oldShader.name.Contains("/Transparent/"))
{
// NOTE: legacy shaders did not provide physically based transparency
// therefore Fade mode
surfaceType = SurfaceType.Transparent;
blendMode = BlendMode.Alpha;
}
material.SetFloat("_Surface", (float)surfaceType);
material.SetFloat("_Blend", (float)blendMode);
MaterialChanged(material);
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
[MovedFrom("UnityEditor.Rendering.LWRP.ShaderGUI")] public static class BakedLitGUI
{
public struct BakedLitProperties
{
// Surface Input Props
public MaterialProperty bumpMapProp;
public BakedLitProperties(MaterialProperty[] properties)
{
// Surface Input Props
bumpMapProp = BaseShaderGUI.FindProperty("_BumpMap", properties, false);
}
}
public static void Inputs(BakedLitProperties properties, MaterialEditor materialEditor)
{
BaseShaderGUI.DrawNormalArea(materialEditor, properties.bumpMapProp);
}
}
}

View File

@@ -0,0 +1,68 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
internal class LitDetailGUI
{
public static class Styles
{
public static readonly GUIContent detailInputs = new GUIContent("Detail Inputs",
"These settings let you add details to the surface.");
public static readonly GUIContent detailMaskText = new GUIContent("Mask",
"Select a mask for the Detail maps. The mask uses the alpha channel of the selected texture. The __Tiling__ and __Offset__ settings have no effect on the mask.");
public static readonly GUIContent detailAlbedoMapText = new GUIContent("Base Map",
"Select the texture containing the surface details.");
public static readonly GUIContent detailNormalMapText = new GUIContent("Normal Map",
"Select the texture containing the normal vector data.");
public static readonly GUIContent detailAlbedoMapScaleInfo = new GUIContent("Setting the scaling factor to a value other than 1 results in a less performant shader variant.");
}
public struct LitProperties
{
public MaterialProperty detailMask;
public MaterialProperty detailAlbedoMapScale;
public MaterialProperty detailAlbedoMap;
public MaterialProperty detailNormalMapScale;
public MaterialProperty detailNormalMap;
public LitProperties(MaterialProperty[] properties)
{
detailMask = BaseShaderGUI.FindProperty("_DetailMask", properties, false);
detailAlbedoMapScale = BaseShaderGUI.FindProperty("_DetailAlbedoMapScale", properties, false);
detailAlbedoMap = BaseShaderGUI.FindProperty("_DetailAlbedoMap", properties, false);
detailNormalMapScale = BaseShaderGUI.FindProperty("_DetailNormalMapScale", properties, false);
detailNormalMap = BaseShaderGUI.FindProperty("_DetailNormalMap", properties, false);
}
}
public static void DoDetailArea(LitProperties properties, MaterialEditor materialEditor)
{
materialEditor.TexturePropertySingleLine(Styles.detailMaskText, properties.detailMask);
materialEditor.TexturePropertySingleLine(Styles.detailAlbedoMapText, properties.detailAlbedoMap,
properties.detailAlbedoMap.textureValue != null ? properties.detailAlbedoMapScale : null);
if (properties.detailAlbedoMapScale.floatValue != 1.0f)
{
EditorGUILayout.HelpBox(Styles.detailAlbedoMapScaleInfo.text, MessageType.Info, true);
}
materialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, properties.detailNormalMap,
properties.detailNormalMap.textureValue != null ? properties.detailNormalMapScale : null);
materialEditor.TextureScaleOffsetProperty(properties.detailAlbedoMap);
}
public static void SetMaterialKeywords(Material material)
{
if (material.HasProperty("_DetailAlbedoMap") && material.HasProperty("_DetailNormalMap") && material.HasProperty("_DetailAlbedoMapScale"))
{
bool isScaled = material.GetFloat("_DetailAlbedoMapScale") != 1.0f;
bool hasDetailMap = material.GetTexture("_DetailAlbedoMap") || material.GetTexture("_DetailNormalMap");
CoreUtils.SetKeyword(material, "_DETAIL_MULX2", !isScaled && hasDetailMap);
CoreUtils.SetKeyword(material, "_DETAIL_SCALED", isScaled && hasDetailMap);
}
}
}
}

View File

@@ -0,0 +1,331 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
[MovedFrom("UnityEditor.Rendering.LWRP.ShaderGUI")] public static class LitGUI
{
public enum WorkflowMode
{
Specular = 0,
Metallic
}
public enum SmoothnessMapChannel
{
SpecularMetallicAlpha,
AlbedoAlpha,
}
public static class Styles
{
public static GUIContent workflowModeText = new GUIContent("Workflow Mode",
"Select a workflow that fits your textures. Choose between Metallic or Specular.");
public static GUIContent specularMapText =
new GUIContent("Specular Map", "Sets and configures the map and color for the Specular workflow.");
public static GUIContent metallicMapText =
new GUIContent("Metallic Map", "Sets and configures the map for the Metallic workflow.");
public static GUIContent smoothnessText = new GUIContent("Smoothness",
"Controls the spread of highlights and reflections on the surface.");
public static GUIContent smoothnessMapChannelText =
new GUIContent("Source",
"Specifies where to sample a smoothness map from. By default, uses the alpha channel for your map.");
public static GUIContent highlightsText = new GUIContent("Specular Highlights",
"When enabled, the Material reflects the shine from direct lighting.");
public static GUIContent reflectionsText =
new GUIContent("Environment Reflections",
"When enabled, the Material samples reflections from the nearest Reflection Probes or Lighting Probe.");
public static GUIContent heightMapText = new GUIContent("Height Map",
"Specifies the Height Map (G) for this Material.");
public static GUIContent occlusionText = new GUIContent("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 = new GUIContent("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 = new GUIContent("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 = new GUIContent("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)
{
var coatEnabled = ClearCoatEnabled(material);
EditorGUI.BeginChangeCheck();
EditorGUI.Toggle(EditorGUILayout.GetControlRect(), Styles.clearCoatText, coatEnabled);
if (EditorGUI.EndChangeCheck())
{
if (coatEnabled)
material.SetFloat("_ClearCoat", 0); // Toggle off
else
material.SetFloat("_ClearCoat", 1);
coatEnabled = !coatEnabled;
}
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);
}
EditorGUI.indentLevel++;
DoSmoothness(properties, material, smoothnessChannelNames);
EditorGUI.indentLevel--;
}
public static void DoSmoothness(LitProperties properties, Material material, string[] smoothnessChannelNames)
{
var opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat("_Surface") ==
BaseShaderGUI.SurfaceType.Opaque);
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.smoothness.hasMixedValue;
var smoothness = EditorGUILayout.Slider(Styles.smoothnessText, properties.smoothness.floatValue, 0f, 1f);
if (EditorGUI.EndChangeCheck())
properties.smoothness.floatValue = smoothness;
EditorGUI.showMixedValue = false;
if (properties.smoothnessMapChannel != null) // smoothness channel
{
EditorGUI.indentLevel++;
EditorGUI.BeginDisabledGroup(!opaque);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.smoothnessMapChannel.hasMixedValue;
var smoothnessSource = (int)properties.smoothnessMapChannel.floatValue;
if (opaque)
smoothnessSource = EditorGUILayout.Popup(Styles.smoothnessMapChannelText, smoothnessSource,
smoothnessChannelNames);
else
EditorGUILayout.Popup(Styles.smoothnessMapChannelText, 0, smoothnessChannelNames);
if (EditorGUI.EndChangeCheck())
properties.smoothnessMapChannel.floatValue = smoothnessSource;
EditorGUI.showMixedValue = false;
EditorGUI.EndDisabledGroup();
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
}
public static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)
{
int ch = (int)material.GetFloat("_SmoothnessTextureChannel");
if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)
return SmoothnessMapChannel.AlbedoAlpha;
return SmoothnessMapChannel.SpecularMetallicAlpha;
}
public 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)
var hasGlossMap = false;
var isSpecularWorkFlow = false;
var opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat("_Surface") ==
BaseShaderGUI.SurfaceType.Opaque);
if (material.HasProperty("_WorkflowMode"))
{
isSpecularWorkFlow = (WorkflowMode)material.GetFloat("_WorkflowMode") == WorkflowMode.Specular;
if (isSpecularWorkFlow)
hasGlossMap = material.GetTexture("_SpecGlossMap") != null;
else
hasGlossMap = material.GetTexture("_MetallicGlossMap") != null;
}
else
{
hasGlossMap = material.GetTexture("_MetallicGlossMap") != null;
}
CoreUtils.SetKeyword(material, "_SPECULAR_SETUP", isSpecularWorkFlow);
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"))
{
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);
}
}
}
}

View File

@@ -0,0 +1,157 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEditor.Rendering.Universal.ShaderGUI
{
[MovedFrom("UnityEditor.Rendering.LWRP.ShaderGUI")] public static class SimpleLitGUI
{
public enum SpecularSource
{
SpecularTextureAndColor,
NoSpecular
}
public enum SmoothnessMapChannel
{
SpecularAlpha,
AlbedoAlpha,
}
public static class Styles
{
public static GUIContent specularMapText =
new GUIContent("Specular Map", "Sets and configures a Specular map and color for your Material.");
public static GUIContent smoothnessText = new GUIContent("Smoothness",
"Controls the spread of highlights and reflections on the surface.");
public static GUIContent smoothnessMapChannelText =
new GUIContent("Source",
"Specifies where to sample a smoothness map from. By default, uses the alpha channel for your map.");
public static GUIContent highlightsText = new GUIContent("Specular Highlights",
"When enabled, the Material reflects the shine from direct lighting.");
}
public struct SimpleLitProperties
{
// Surface Input Props
public MaterialProperty specColor;
public MaterialProperty specGlossMap;
public MaterialProperty specHighlights;
public MaterialProperty smoothnessMapChannel;
public MaterialProperty smoothness;
public MaterialProperty bumpMapProp;
public SimpleLitProperties(MaterialProperty[] properties)
{
// Surface Input Props
specColor = BaseShaderGUI.FindProperty("_SpecColor", properties);
specGlossMap = BaseShaderGUI.FindProperty("_SpecGlossMap", properties, false);
specHighlights = BaseShaderGUI.FindProperty("_SpecularHighlights", properties, false);
smoothnessMapChannel = BaseShaderGUI.FindProperty("_SmoothnessSource", properties, false);
smoothness = BaseShaderGUI.FindProperty("_Smoothness", properties, false);
bumpMapProp = BaseShaderGUI.FindProperty("_BumpMap", properties, false);
}
}
public static void Inputs(SimpleLitProperties properties, MaterialEditor materialEditor, Material material)
{
DoSpecularArea(properties, materialEditor, material);
BaseShaderGUI.DrawNormalArea(materialEditor, properties.bumpMapProp);
}
public static void Advanced(SimpleLitProperties properties)
{
SpecularSource specularSource = (SpecularSource)properties.specHighlights.floatValue;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.specHighlights.hasMixedValue;
bool enabled = EditorGUILayout.Toggle(Styles.highlightsText, specularSource == SpecularSource.SpecularTextureAndColor);
if (EditorGUI.EndChangeCheck())
properties.specHighlights.floatValue = enabled ? (float)SpecularSource.SpecularTextureAndColor : (float)SpecularSource.NoSpecular;
EditorGUI.showMixedValue = false;
}
public static void DoSpecularArea(SimpleLitProperties properties, MaterialEditor materialEditor, Material material)
{
SpecularSource specSource = (SpecularSource)properties.specHighlights.floatValue;
EditorGUI.BeginDisabledGroup(specSource == SpecularSource.NoSpecular);
BaseShaderGUI.TextureColorProps(materialEditor, Styles.specularMapText, properties.specGlossMap, properties.specColor, true);
DoSmoothness(properties, material);
EditorGUI.EndDisabledGroup();
}
public static void DoSmoothness(SimpleLitProperties properties, Material material)
{
var opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat("_Surface") ==
BaseShaderGUI.SurfaceType.Opaque);
EditorGUI.indentLevel += 2;
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.smoothness.hasMixedValue;
var smoothnessSource = (int)properties.smoothnessMapChannel.floatValue;
var smoothness = properties.smoothness.floatValue;
smoothness = EditorGUILayout.Slider(Styles.smoothnessText, smoothness, 0f, 1f);
if (EditorGUI.EndChangeCheck())
{
properties.smoothness.floatValue = smoothness;
}
EditorGUI.showMixedValue = false;
EditorGUI.indentLevel++;
EditorGUI.BeginDisabledGroup(!opaque);
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.smoothnessMapChannel.hasMixedValue;
if (opaque)
smoothnessSource = EditorGUILayout.Popup(Styles.smoothnessMapChannelText, smoothnessSource, Enum.GetNames(typeof(SmoothnessMapChannel)));
else
EditorGUILayout.Popup(Styles.smoothnessMapChannelText, 0, Enum.GetNames(typeof(SmoothnessMapChannel)));
if (EditorGUI.EndChangeCheck())
properties.smoothnessMapChannel.floatValue = smoothnessSource;
EditorGUI.showMixedValue = false;
EditorGUI.indentLevel -= 3;
EditorGUI.EndDisabledGroup();
}
public static void SetMaterialKeywords(Material material)
{
UpdateMaterialSpecularSource(material);
}
private static void UpdateMaterialSpecularSource(Material material)
{
var opaque = ((BaseShaderGUI.SurfaceType)material.GetFloat("_Surface") ==
BaseShaderGUI.SurfaceType.Opaque);
SpecularSource specSource = (SpecularSource)material.GetFloat("_SpecularHighlights");
if (specSource == SpecularSource.NoSpecular)
{
CoreUtils.SetKeyword(material, "_SPECGLOSSMAP", false);
CoreUtils.SetKeyword(material, "_SPECULAR_COLOR", false);
CoreUtils.SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", false);
}
else
{
var smoothnessSource = (SmoothnessMapChannel)material.GetFloat("_SmoothnessSource");
bool hasMap = material.GetTexture("_SpecGlossMap");
CoreUtils.SetKeyword(material, "_SPECGLOSSMAP", hasMap);
CoreUtils.SetKeyword(material, "_SPECULAR_COLOR", !hasMap);
if (opaque)
CoreUtils.SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", smoothnessSource == SmoothnessMapChannel.AlbedoAlpha);
else
CoreUtils.SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", false);
string color;
if (smoothnessSource != SmoothnessMapChannel.AlbedoAlpha || !opaque)
color = "_SpecColor";
else
color = "_BaseColor";
var col = material.GetColor(color);
col.a = material.GetFloat("_Smoothness");
material.SetColor(color, col);
}
}
}
}

View File

@@ -0,0 +1,324 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
using UnityEngine.Experimental.Rendering;
namespace UnityEditor.Rendering.Universal
{
internal class TerrainLitShaderGUI : UnityEditor.ShaderGUI, ITerrainLayerCustomUI
{
private class StylesLayer
{
public readonly GUIContent warningHeightBasedBlending = new GUIContent("Height-based blending is disabled if you have more than four TerrainLayer materials!");
public readonly GUIContent enableHeightBlend = new GUIContent("Enable Height-based Blend", "Blend terrain layers based on height values.");
public readonly GUIContent heightTransition = new GUIContent("Height Transition", "Size in world units of the smooth transition between layers.");
public readonly GUIContent enableInstancedPerPixelNormal = new GUIContent("Enable Per-pixel Normal", "Enable per-pixel normal when the terrain uses instanced rendering.");
public readonly GUIContent diffuseTexture = new GUIContent("Diffuse");
public readonly GUIContent colorTint = new GUIContent("Color Tint");
public readonly GUIContent opacityAsDensity = new GUIContent("Opacity as Density", "Enable Density Blend (if unchecked, opacity is used as Smoothness)");
public readonly GUIContent normalMapTexture = new GUIContent("Normal Map");
public readonly GUIContent normalScale = new GUIContent("Normal Scale");
public readonly GUIContent maskMapTexture = new GUIContent("Mask", "R: Metallic\nG: AO\nB: Height\nA: Smoothness");
public readonly GUIContent maskMapTextureWithoutHeight = new GUIContent("Mask Map", "R: Metallic\nG: AO\nA: Smoothness");
public readonly GUIContent channelRemapping = new GUIContent("Channel Remapping");
public readonly GUIContent defaultValues = new GUIContent("Channel Default Values");
public readonly GUIContent metallic = new GUIContent("R: Metallic");
public readonly GUIContent ao = new GUIContent("G: AO");
public readonly GUIContent height = new GUIContent("B: Height");
public readonly GUIContent heightParametrization = new GUIContent("Parametrization");
public readonly GUIContent heightAmplitude = new GUIContent("Amplitude (cm)");
public readonly GUIContent heightBase = new GUIContent("Base (cm)");
public readonly GUIContent heightMin = new GUIContent("Min (cm)");
public readonly GUIContent heightMax = new GUIContent("Max (cm)");
public readonly GUIContent heightCm = new GUIContent("B: Height (cm)");
public readonly GUIContent smoothness = new GUIContent("A: Smoothness");
}
static StylesLayer s_Styles = null;
private static StylesLayer styles { get { if (s_Styles == null) s_Styles = new StylesLayer(); return s_Styles; } }
public TerrainLitShaderGUI()
{
}
// Height blend params
MaterialProperty enableHeightBlend = null;
const string kEnableHeightBlend = "_EnableHeightBlend";
MaterialProperty heightTransition = null;
const string kHeightTransition = "_HeightTransition";
// Per-pixel Normal (while instancing)
MaterialProperty enableInstancedPerPixelNormal = null;
const string kEnableInstancedPerPixelNormal = "_EnableInstancedPerPixelNormal";
private bool m_ShowChannelRemapping = false;
enum HeightParametrization
{
Amplitude,
MinMax
};
private HeightParametrization m_HeightParametrization = HeightParametrization.Amplitude;
private static bool DoesTerrainUseMaskMaps(TerrainLayer[] terrainLayers)
{
for (int i = 0; i < terrainLayers.Length; ++i)
{
if (terrainLayers[i].maskMapTexture != null)
return true;
}
return false;
}
protected void FindMaterialProperties(MaterialProperty[] props)
{
enableHeightBlend = FindProperty(kEnableHeightBlend, props, false);
heightTransition = FindProperty(kHeightTransition, props, false);
enableInstancedPerPixelNormal = FindProperty(kEnableInstancedPerPixelNormal, props, false);
}
static public void SetupMaterialKeywords(Material material)
{
bool enableHeightBlend = (material.HasProperty(kEnableHeightBlend) && material.GetFloat(kEnableHeightBlend) > 0);
CoreUtils.SetKeyword(material, "_TERRAIN_BLEND_HEIGHT", enableHeightBlend);
bool enableInstancedPerPixelNormal = material.GetFloat(kEnableInstancedPerPixelNormal) > 0.0f;
CoreUtils.SetKeyword(material, "_TERRAIN_INSTANCED_PERPIXEL_NORMAL", enableInstancedPerPixelNormal);
}
static public bool TextureHasAlpha(Texture2D inTex)
{
if (inTex != null)
{
return GraphicsFormatUtility.HasAlphaChannel(GraphicsFormatUtility.GetGraphicsFormat(inTex.format, true));
}
return false;
}
public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties)
{
if (materialEditorIn == null)
throw new ArgumentNullException("materialEditorIn");
FindMaterialProperties(properties);
bool optionsChanged = false;
EditorGUI.BeginChangeCheck();
{
if (enableHeightBlend != null)
{
EditorGUI.indentLevel++;
materialEditorIn.ShaderProperty(enableHeightBlend, styles.enableHeightBlend);
if (enableHeightBlend.floatValue > 0)
{
EditorGUI.indentLevel++;
EditorGUILayout.HelpBox(styles.warningHeightBasedBlending.text, MessageType.Info);
materialEditorIn.ShaderProperty(heightTransition, styles.heightTransition);
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
}
EditorGUILayout.Space();
}
if (EditorGUI.EndChangeCheck())
{
optionsChanged = true;
}
bool enablePerPixelNormalChanged = false;
// Since Instanced Per-pixel normal is actually dependent on instancing enabled or not, it is not
// important to check it in the GUI. The shader will make sure it is enabled/disabled properly.s
if (enableInstancedPerPixelNormal != null)
{
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
materialEditorIn.ShaderProperty(enableInstancedPerPixelNormal, styles.enableInstancedPerPixelNormal);
enablePerPixelNormalChanged = EditorGUI.EndChangeCheck();
EditorGUI.indentLevel--;
}
if (optionsChanged || enablePerPixelNormalChanged)
{
foreach (var obj in materialEditorIn.targets)
{
SetupMaterialKeywords((Material)obj);
}
}
// We should always do this call at the end
materialEditorIn.serializedObject.ApplyModifiedProperties();
}
bool ITerrainLayerCustomUI.OnTerrainLayerGUI(TerrainLayer terrainLayer, Terrain terrain)
{
var terrainLayers = terrain.terrainData.terrainLayers;
// Don't use the member field enableHeightBlend as ShaderGUI.OnGUI might not be called if the material UI is folded.
// heightblend shouldn't be available if we are in multi-pass mode, because it is guaranteed to be broken.
bool heightBlendAvailable = (terrainLayers.Length <= 4);
bool heightBlend = heightBlendAvailable && terrain.materialTemplate.HasProperty(kEnableHeightBlend) && (terrain.materialTemplate.GetFloat(kEnableHeightBlend) > 0);
terrainLayer.diffuseTexture = EditorGUILayout.ObjectField(styles.diffuseTexture, terrainLayer.diffuseTexture, typeof(Texture2D), false) as Texture2D;
TerrainLayerUtility.ValidateDiffuseTextureUI(terrainLayer.diffuseTexture);
var diffuseRemapMin = terrainLayer.diffuseRemapMin;
var diffuseRemapMax = terrainLayer.diffuseRemapMax;
EditorGUI.BeginChangeCheck();
bool enableDensity = false;
if (terrainLayer.diffuseTexture != null)
{
var rect = GUILayoutUtility.GetLastRect();
rect.y += 16 + 4;
rect.width = EditorGUIUtility.labelWidth + 64;
rect.height = 16;
++EditorGUI.indentLevel;
var diffuseTint = new Color(diffuseRemapMax.x, diffuseRemapMax.y, diffuseRemapMax.z);
diffuseTint = EditorGUI.ColorField(rect, styles.colorTint, diffuseTint, true, false, false);
diffuseRemapMax.x = diffuseTint.r;
diffuseRemapMax.y = diffuseTint.g;
diffuseRemapMax.z = diffuseTint.b;
diffuseRemapMin.x = diffuseRemapMin.y = diffuseRemapMin.z = 0;
if (!heightBlend)
{
rect.y = rect.yMax + 2;
enableDensity = EditorGUI.Toggle(rect, styles.opacityAsDensity, diffuseRemapMin.w > 0);
}
--EditorGUI.indentLevel;
}
diffuseRemapMax.w = 1;
diffuseRemapMin.w = enableDensity ? 1 : 0;
if (EditorGUI.EndChangeCheck())
{
terrainLayer.diffuseRemapMin = diffuseRemapMin;
terrainLayer.diffuseRemapMax = diffuseRemapMax;
}
// Display normal map UI
terrainLayer.normalMapTexture = EditorGUILayout.ObjectField(styles.normalMapTexture, terrainLayer.normalMapTexture, typeof(Texture2D), false) as Texture2D;
TerrainLayerUtility.ValidateNormalMapTextureUI(terrainLayer.normalMapTexture, TerrainLayerUtility.CheckNormalMapTextureType(terrainLayer.normalMapTexture));
if (terrainLayer.normalMapTexture != null)
{
var rect = GUILayoutUtility.GetLastRect();
rect.y += 16 + 4;
rect.width = EditorGUIUtility.labelWidth + 64;
rect.height = 16;
++EditorGUI.indentLevel;
terrainLayer.normalScale = EditorGUI.FloatField(rect, styles.normalScale, terrainLayer.normalScale);
--EditorGUI.indentLevel;
}
// Display the mask map UI and the remap controls
terrainLayer.maskMapTexture = EditorGUILayout.ObjectField(heightBlend ? styles.maskMapTexture : styles.maskMapTextureWithoutHeight, terrainLayer.maskMapTexture, typeof(Texture2D), false) as Texture2D;
TerrainLayerUtility.ValidateMaskMapTextureUI(terrainLayer.maskMapTexture);
var maskMapRemapMin = terrainLayer.maskMapRemapMin;
var maskMapRemapMax = terrainLayer.maskMapRemapMax;
var smoothness = terrainLayer.smoothness;
var metallic = terrainLayer.metallic;
++EditorGUI.indentLevel;
EditorGUI.BeginChangeCheck();
m_ShowChannelRemapping = EditorGUILayout.Foldout(m_ShowChannelRemapping, terrainLayer.maskMapTexture != null ? s_Styles.channelRemapping : s_Styles.defaultValues);
if (m_ShowChannelRemapping)
{
if (terrainLayer.maskMapTexture != null)
{
float min, max;
min = maskMapRemapMin.x; max = maskMapRemapMax.x;
EditorGUILayout.MinMaxSlider(s_Styles.metallic, ref min, ref max, 0, 1);
maskMapRemapMin.x = min; maskMapRemapMax.x = max;
min = maskMapRemapMin.y; max = maskMapRemapMax.y;
EditorGUILayout.MinMaxSlider(s_Styles.ao, ref min, ref max, 0, 1);
maskMapRemapMin.y = min; maskMapRemapMax.y = max;
if (heightBlend)
{
EditorGUILayout.LabelField(styles.height);
++EditorGUI.indentLevel;
m_HeightParametrization = (HeightParametrization)EditorGUILayout.EnumPopup(styles.heightParametrization, m_HeightParametrization);
if (m_HeightParametrization == HeightParametrization.Amplitude)
{
// (height - heightBase) * amplitude
float amplitude = Mathf.Max(maskMapRemapMax.z - maskMapRemapMin.z, Mathf.Epsilon); // to avoid divide by zero
float heightBase = maskMapRemapMin.z / amplitude;
amplitude = EditorGUILayout.FloatField(styles.heightAmplitude, amplitude * 100) / 100;
heightBase = EditorGUILayout.FloatField(styles.heightBase, heightBase * 100) / 100;
maskMapRemapMin.z = heightBase * amplitude;
maskMapRemapMax.z = (1.0f - heightBase) * amplitude;
}
else
{
maskMapRemapMin.z = EditorGUILayout.FloatField(styles.heightMin, maskMapRemapMin.z * 100) / 100;
maskMapRemapMax.z = EditorGUILayout.FloatField(styles.heightMax, maskMapRemapMax.z * 100) / 100;
}
--EditorGUI.indentLevel;
}
min = maskMapRemapMin.w; max = maskMapRemapMax.w;
EditorGUILayout.MinMaxSlider(s_Styles.smoothness, ref min, ref max, 0, 1);
maskMapRemapMin.w = min; maskMapRemapMax.w = max;
}
else
{
metallic = EditorGUILayout.Slider(s_Styles.metallic, metallic, 0, 1);
// AO and Height are still exclusively controlled via the maskRemap controls
// metallic and smoothness have their own values as fields within the LayerData.
maskMapRemapMax.y = EditorGUILayout.Slider(s_Styles.ao, maskMapRemapMax.y, 0, 1);
if (heightBlend)
{
maskMapRemapMax.z = EditorGUILayout.FloatField(s_Styles.heightCm, maskMapRemapMax.z * 100) / 100;
}
// There's a possibility that someone could slide max below the existing min value
// so we'll just protect against that by locking the min value down a little bit.
// In the case of height (Z), we are trying to set min to no lower than zero value unless
// max goes negative. Zero is a good sensible value for the minimum. For AO (Y), we
// don't need this extra protection step because the UI blocks us from going negative
// anyway. In both cases, pushing the slider below the min value will lock them together,
// but min will be "left behind" if you go back up.
maskMapRemapMin.y = Mathf.Min(maskMapRemapMin.y, maskMapRemapMax.y);
maskMapRemapMin.z = Mathf.Min(Mathf.Max(0, maskMapRemapMin.z), maskMapRemapMax.z);
if (TextureHasAlpha(terrainLayer.diffuseTexture))
{
GUIStyle warnStyle = new GUIStyle(GUI.skin.label);
warnStyle.wordWrap = true;
GUILayout.Label("Smoothness is controlled by diffuse alpha channel", warnStyle);
}
else
smoothness = EditorGUILayout.Slider(s_Styles.smoothness, smoothness, 0, 1);
}
}
if (EditorGUI.EndChangeCheck())
{
terrainLayer.maskMapRemapMin = maskMapRemapMin;
terrainLayer.maskMapRemapMax = maskMapRemapMax;
terrainLayer.smoothness = smoothness;
terrainLayer.metallic = metallic;
}
--EditorGUI.indentLevel;
EditorGUILayout.Space();
TerrainLayerUtility.TilingSettingsUI(terrainLayer);
return true;
}
}
}