200 lines
8.0 KiB
C#
200 lines
8.0 KiB
C#
using System;
|
|
using UnityEditor.ShaderGraph;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.Rendering.Universal.Internal;
|
|
|
|
namespace UnityEditor.Rendering.Universal
|
|
{
|
|
/// <summary>
|
|
/// Scope that indicates start of <see cref="DecalProjector"/> GUI.
|
|
/// </summary>
|
|
internal class DecalProjectorScope : GUI.Scope
|
|
{
|
|
public DecalProjectorScope()
|
|
{
|
|
DecalShaderGraphGUI.isDecalProjectorGUI = true;
|
|
}
|
|
|
|
protected override void CloseScope()
|
|
{
|
|
DecalShaderGraphGUI.isDecalProjectorGUI = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents the GUI for Decal Shader Graph materials.
|
|
/// </summary>
|
|
internal class DecalShaderGraphGUI : UnityEditor.ShaderGUI
|
|
{
|
|
internal class Styles
|
|
{
|
|
public static GUIContent inputs = new GUIContent("Inputs");
|
|
public static GUIContent advancedOptions = new GUIContent("Advanced Options");
|
|
|
|
public static GUIContent meshDecalBiasType = new GUIContent("Mesh Bias Type", "Set the type of bias that is applied to the mesh decal. Depth Bias applies a bias to the final depth value, while View bias applies a world space bias (in meters) alongside the view vector.");
|
|
public static GUIContent meshDecalDepthBiasText = new GUIContent("Depth Bias", "Sets a depth bias to stop the decal's Mesh from overlapping with other Meshes.");
|
|
public static GUIContent meshDecalViewBiasText = new GUIContent("View Bias", "Sets a world-space bias alongside the view vector to stop the decal's Mesh from overlapping with other Meshes. The unit is meters.");
|
|
public static GUIContent drawOrderText = new GUIContent("Priority", "Controls the draw order of Decal Projectors. URP draws decals with lower values first.");
|
|
}
|
|
|
|
protected enum Expandable
|
|
{
|
|
Inputs = 1 << 0,
|
|
Advanced = 1 << 1,
|
|
}
|
|
|
|
public static bool isDecalProjectorGUI { get; set; }
|
|
|
|
const string kDecalMeshBiasType = "_DecalMeshBiasType";
|
|
const string kDecalMeshDepthBias = "_DecalMeshDepthBias";
|
|
const string kDecalViewDepthBias = "_DecalMeshViewBias";
|
|
const string kDrawOrder = "_DrawOrder";
|
|
|
|
readonly MaterialHeaderScopeList m_MaterialScopeList = new MaterialHeaderScopeList(uint.MaxValue & ~((uint)Expandable.Advanced));
|
|
|
|
MaterialEditor m_MaterialEditor;
|
|
MaterialProperty[] m_Properties;
|
|
|
|
MaterialProperty decalMeshBiasType;
|
|
MaterialProperty decalMeshDepthBias;
|
|
MaterialProperty decalMeshViewBias;
|
|
MaterialProperty drawOrder;
|
|
|
|
public DecalShaderGraphGUI()
|
|
{
|
|
m_MaterialScopeList.RegisterHeaderScope(Styles.inputs, Expandable.Inputs, DrawExposedProperties);
|
|
m_MaterialScopeList.RegisterHeaderScope(Styles.advancedOptions, Expandable.Advanced, DrawSortingProperties);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override this function to implement your custom GUI. To display a user interface similar to HDRP shaders, use a MaterialUIBlockList.
|
|
/// </summary>
|
|
/// <param name="materialEditor">The current material editor.</param>
|
|
/// <param name="props">The list of properties the material has.</param>
|
|
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
|
|
{
|
|
DecalMeshWarning();
|
|
|
|
m_MaterialEditor = materialEditor;
|
|
FindProperties(props);
|
|
|
|
Material material = materialEditor.target as Material;
|
|
|
|
using (var changed = new EditorGUI.ChangeCheckScope())
|
|
{
|
|
m_MaterialScopeList.DrawHeaders(materialEditor, material);
|
|
}
|
|
|
|
// We should always do this call at the end
|
|
materialEditor.serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
private void FindProperties(MaterialProperty[] properties)
|
|
{
|
|
decalMeshBiasType = FindProperty(kDecalMeshBiasType, properties);
|
|
decalMeshViewBias = FindProperty(kDecalViewDepthBias, properties);
|
|
decalMeshDepthBias = FindProperty(kDecalMeshDepthBias, properties);
|
|
drawOrder = FindProperty(kDrawOrder, properties);
|
|
|
|
m_Properties = properties;
|
|
}
|
|
|
|
private void DrawExposedProperties(Material material)
|
|
{
|
|
MaterialProperty[] properties = m_Properties;
|
|
MaterialEditor materialEditor = m_MaterialEditor;
|
|
|
|
// TODO: scope
|
|
var fieldWidth = EditorGUIUtility.fieldWidth;
|
|
var labelWidth = EditorGUIUtility.labelWidth;
|
|
|
|
// Copy of MaterialEditor.PropertiesDefaultGUI that excludes properties of PerRendererData
|
|
materialEditor.SetDefaultGUIWidths();
|
|
for (var i = 0; i < properties.Length; i++)
|
|
{
|
|
if ((properties[i].flags & (MaterialProperty.PropFlags.HideInInspector | MaterialProperty.PropFlags.PerRendererData)) != 0)
|
|
continue;
|
|
|
|
float h = materialEditor.GetPropertyHeight(properties[i], properties[i].displayName);
|
|
Rect r = EditorGUILayout.GetControlRect(true, h, EditorStyles.layerMaskField);
|
|
|
|
materialEditor.ShaderProperty(r, properties[i], properties[i].displayName);
|
|
}
|
|
|
|
EditorGUIUtility.fieldWidth = fieldWidth;
|
|
EditorGUIUtility.labelWidth = labelWidth;
|
|
}
|
|
|
|
private void DrawSortingProperties(Material material)
|
|
{
|
|
MaterialEditor materialEditor = m_MaterialEditor;
|
|
|
|
materialEditor.EnableInstancingField();
|
|
DrawOrder();
|
|
materialEditor.ShaderProperty(decalMeshBiasType, Styles.meshDecalBiasType);
|
|
|
|
DecalMeshDepthBiasType decalBias = (DecalMeshDepthBiasType)decalMeshBiasType.floatValue;
|
|
EditorGUI.indentLevel++;
|
|
switch (decalBias)
|
|
{
|
|
case DecalMeshDepthBiasType.DepthBias:
|
|
materialEditor.ShaderProperty(decalMeshDepthBias, Styles.meshDecalDepthBiasText);
|
|
break;
|
|
case DecalMeshDepthBiasType.ViewBias:
|
|
materialEditor.ShaderProperty(decalMeshViewBias, Styles.meshDecalViewBiasText);
|
|
break;
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
private void DrawOrder()
|
|
{
|
|
MaterialEditor materialEditor = m_MaterialEditor;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUI.showMixedValue = drawOrder.hasMixedValue;
|
|
var queue = EditorGUILayout.IntSlider(Styles.drawOrderText, (int)drawOrder.floatValue, -50, 50);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
foreach (var target in materialEditor.targets)
|
|
{
|
|
var material = target as Material;
|
|
material.renderQueue = 2000 + queue;
|
|
}
|
|
drawOrder.floatValue = queue;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
}
|
|
|
|
private void DecalMeshWarning()
|
|
{
|
|
if (isDecalProjectorGUI)
|
|
return;
|
|
|
|
var urp = UniversalRenderPipeline.asset;
|
|
if (urp == null)
|
|
return;
|
|
|
|
bool hasDecalScreenSpace = false;
|
|
var renderers = urp.m_RendererDataList;
|
|
foreach (var renderer in renderers)
|
|
{
|
|
if (renderer.TryGetRendererFeature(out DecalRendererFeature decalRendererFeature))
|
|
{
|
|
var technique = decalRendererFeature.GetTechnique(renderer);
|
|
if (technique == DecalTechnique.ScreenSpace || technique == DecalTechnique.GBuffer)
|
|
{
|
|
hasDecalScreenSpace = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasDecalScreenSpace)
|
|
EditorGUILayout.HelpBox("Decals with Screen Space technique only support rendering with DecalProjector component.", MessageType.Warning);
|
|
}
|
|
}
|
|
}
|