forked from BilalY/Rasagar
326 lines
19 KiB
C#
326 lines
19 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEngine.Rendering.HighDefinition.Compositor;
|
|
using UnityEngine.Experimental.Rendering;
|
|
|
|
using UnityEditorInternal;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition.Compositor
|
|
{
|
|
internal class CompositionLayerUI
|
|
{
|
|
static partial class Styles
|
|
{
|
|
// main layer
|
|
static public readonly GUIContent k_Resolution = EditorGUIUtility.TrTextContent("Resolution", "Specifies the resolution of this layer's render target. Lower resolution increases the performance at the expense of visual quality.");
|
|
static public readonly GUIContent k_BufferFormat = EditorGUIUtility.TrTextContent("Format", "Specifies the color buffer format of this layer. ");
|
|
static public readonly GUIContent k_OutputRenderer = EditorGUIUtility.TrTextContent("Output Renderer", "Redirects the output of this layer to the surface which is drawn by the selected mesh renderer. ");
|
|
static public readonly GUIContent k_AOVs = EditorGUIUtility.TrTextContent("AOVs", "Specifies the Arbitrary Output Variable (AOV) that will be drawn on this layer. This option affects all cameras that are stacked on this layer.");
|
|
|
|
// Sub layer
|
|
static public readonly GUIContent k_NameContent = EditorGUIUtility.TrTextContent("Layer Name", "Specifies the name of this layer.");
|
|
static public readonly GUIContent k_Camera = EditorGUIUtility.TrTextContent("Source Camera", "Specifies the camera of the scene that will provide the content for this sublayer.");
|
|
static public readonly GUIContent k_Image = EditorGUIUtility.TrTextContent("Source Image", "Specifies the image that will provide the content for this sublayer.");
|
|
static public readonly GUIContent k_Video = EditorGUIUtility.TrTextContent("Source Video", "Specifies the video that will provide the content for this sublayer.");
|
|
static public readonly GUIContent k_ClearDepth = EditorGUIUtility.TrTextContent("Clear Depth", "If enabled, the depth buffer will be cleared before rendering this layer. Not clearing the depth can be useful when stacking sublayers. The first sublayer of a stack always clears the depth.");
|
|
static public readonly GUIContent k_ClearAlpha = EditorGUIUtility.TrTextContent("Clear Alpha", "If enabled, the alpha channel will be cleared before rendering this layer. If enabled, post processing will affect only the objects of this layer");
|
|
static public readonly GUIContent k_ClearMode = EditorGUIUtility.TrTextContent("Clear Color", "To override the clear mode of this layer, activate the option by clicking on the check-box and then select the desired value. This can be changed only on the first sub layer of a stack (stacked sublayers do not clear the color).");
|
|
static public readonly GUIContent k_AAMode = EditorGUIUtility.TrTextContent("Post Anti-aliasing", "To override the postprocess Anti-aliasing mode, activate the option by clicking on the check-box and then select the desired value.");
|
|
static public readonly GUIContent k_CullingMask = EditorGUIUtility.TrTextContent("Culling Mask", "To override the culling mask, activate the option by clicking on the check-box and then select the desired value.");
|
|
static public readonly GUIContent k_VolumeMask = EditorGUIUtility.TrTextContent("Volume Mask", "To override the volume mask, activate the option by clicking on the check-box and then select the desired value.");
|
|
static public readonly GUIContent k_AlphaRange = EditorGUIUtility.TrTextContent("Alpha Range", "The range of alpha values used when transitioning from post-processed to plain image regions. A smaller range will result in a steeper transition.");
|
|
|
|
static public readonly string k_AlphaInfoPost = "The use of AOVs properties in a player requires to enable the Runtime AOV API support in the HDRP quality settings.";
|
|
|
|
static public readonly string k_ShaderCompilationWarning = "The Unity Editor is compiling the AOV shaders for the first time. The output might not be correct until the compilation is over.";
|
|
|
|
static public float infoBoxIconWidth = 100;
|
|
}
|
|
|
|
static bool s_AsyncCompileState = false;
|
|
static bool s_HasStartedCompiling = false;
|
|
|
|
public static void DrawItemInList(Rect rect, SerializedCompositionLayer serialized, RenderTexture thumbnail, float aspectRatio, bool isAlphaEnbaled)
|
|
{
|
|
bool isCameraStack = serialized.outTarget.intValue == (int)CompositorLayer.OutputTarget.CameraStack;
|
|
|
|
// Compute the desired indentation
|
|
{
|
|
const float listBorder = 2.0f;
|
|
rect.x = isCameraStack ? rect.x + CompositorStyle.k_ListItemStackPading + listBorder : rect.x + listBorder;
|
|
rect.width = isCameraStack ? rect.width - CompositorStyle.k_ListItemStackPading - listBorder : rect.width - listBorder;
|
|
rect.y += CompositorStyle.k_ListItemPading;
|
|
rect.height = EditorGUIUtility.singleLineHeight;
|
|
}
|
|
|
|
if (thumbnail)
|
|
{
|
|
Rect newRect = rect;
|
|
newRect.width = EditorGUIUtility.singleLineHeight;
|
|
EditorGUI.PropertyField(newRect, serialized.show, GUIContent.none);
|
|
rect.x += CompositorStyle.k_CheckboxSpacing;
|
|
Rect previewRect = rect;
|
|
previewRect.width = CompositorStyle.k_ThumbnailSize * aspectRatio;
|
|
previewRect.height = CompositorStyle.k_ThumbnailSize;
|
|
EditorGUI.DrawPreviewTexture(previewRect, thumbnail);
|
|
previewRect.x += previewRect.width + CompositorStyle.k_ThumbnailDivider;
|
|
rect.x += previewRect.width + CompositorStyle.k_ThumbnailSpacing;
|
|
rect.width -= previewRect.width + CompositorStyle.k_ThumbnailSpacing;
|
|
|
|
if (isAlphaEnbaled
|
|
&& (thumbnail.graphicsFormat == GraphicsFormat.R16G16B16A16_SFloat
|
|
|| thumbnail.graphicsFormat == GraphicsFormat.R32G32B32A32_SFloat
|
|
|| thumbnail.graphicsFormat == GraphicsFormat.R16G16B16A16_UNorm))
|
|
{
|
|
EditorGUI.DrawTextureAlpha(previewRect, thumbnail);
|
|
rect.x += previewRect.width + CompositorStyle.k_ThumbnailSpacing;
|
|
rect.width -= previewRect.width + CompositorStyle.k_ThumbnailSpacing;
|
|
}
|
|
|
|
rect.y += CompositorStyle.k_LabelVerticalOffset;
|
|
EditorGUI.LabelField(rect, serialized.layerName.stringValue);
|
|
}
|
|
else
|
|
{
|
|
Rect newRect = rect;
|
|
newRect.width = EditorGUIUtility.singleLineHeight;
|
|
EditorGUI.PropertyField(newRect, serialized.show, GUIContent.none);
|
|
newRect.x += CompositorStyle.k_CheckboxSpacing;
|
|
if (isCameraStack)
|
|
{
|
|
Rect iconRect = newRect;
|
|
iconRect.width = CompositorStyle.k_IconSize;
|
|
iconRect.height = CompositorStyle.k_IconSize;
|
|
iconRect.y -= CompositorStyle.k_IconVerticalOffset;
|
|
switch (serialized.inputLayerType.enumValueIndex)
|
|
{
|
|
case (int)CompositorLayer.LayerType.Camera:
|
|
GUI.DrawTexture(iconRect, EditorGUIUtility.ObjectContent(null, typeof(Camera)).image);
|
|
break;
|
|
case (int)CompositorLayer.LayerType.Video:
|
|
GUI.DrawTexture(iconRect, EditorGUIUtility.ObjectContent(null, typeof(UnityEngine.Video.VideoClip)).image);
|
|
break;
|
|
case (int)CompositorLayer.LayerType.Image:
|
|
GUI.DrawTexture(iconRect, EditorGUIUtility.ObjectContent(null, typeof(Texture)).image);
|
|
break;
|
|
default:
|
|
// This will happen if someone adds a new layer type and does not update this switch statement
|
|
Debug.Log("Unknown layer type: Please add code here to draw this type of layer.");
|
|
break;
|
|
}
|
|
newRect.x += CompositorStyle.k_IconSize + CompositorStyle.k_IconSpacing;
|
|
}
|
|
|
|
newRect.width = rect.width - newRect.x;
|
|
EditorGUI.LabelField(newRect, serialized.layerName.stringValue);
|
|
}
|
|
}
|
|
|
|
public static void DrawOutputLayerProperties(Rect rect, SerializedCompositionLayer serializedProperties, System.Action resetRenderTargetCallback)
|
|
{
|
|
rect.y += CompositorStyle.k_ListItemPading;
|
|
rect.height = CompositorStyle.k_SingleLineHeight;
|
|
|
|
EditorGUI.PropertyField(rect, serializedProperties.colorFormat, Styles.k_BufferFormat);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUI.PropertyField(rect, serializedProperties.resolutionScale, Styles.k_Resolution);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
// if the resolution changes, reset the RTs
|
|
resetRenderTargetCallback();
|
|
}
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
EditorGUI.PropertyField(rect, serializedProperties.outputRenderer, Styles.k_OutputRenderer);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
EditorGUI.PropertyField(rect, serializedProperties.aovBitmask, Styles.k_AOVs);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
if (serializedProperties.aovBitmask.intValue != 0)
|
|
{
|
|
// [case 1288744] Enable async compile for the debug shaders to avoid editor freeze when the user selects AOVs
|
|
s_AsyncCompileState = ShaderUtil.allowAsyncCompilation;
|
|
ShaderUtil.allowAsyncCompilation = true;
|
|
// Note: We cannot check immediately if "anythingCompiling", this has to be delayed for the next frame
|
|
if (s_HasStartedCompiling && ShaderUtil.anythingCompiling)
|
|
{
|
|
// Display a message while we are compiling the shaders
|
|
Rect infoRect = rect;
|
|
// Compute the height of the infobox based on the width of the window and the amount of text
|
|
GUIStyle.none.CalcMinMaxWidth(new GUIContent(Styles.k_ShaderCompilationWarning), out float minWidth, out float maxWidth);
|
|
float lines = Mathf.Max(2, Mathf.CeilToInt(maxWidth / (rect.width - Styles.infoBoxIconWidth)));
|
|
infoRect.height = lines * CompositorStyle.k_Spacing;
|
|
EditorGUI.HelpBox(infoRect, Styles.k_ShaderCompilationWarning, MessageType.Warning);
|
|
rect.y += infoRect.height + EditorGUIUtility.standardVerticalSpacing;
|
|
}
|
|
else
|
|
{
|
|
// If the shaders have finished compiling, set the async compilation to the previous state
|
|
if (s_HasStartedCompiling)
|
|
{
|
|
ShaderUtil.allowAsyncCompilation = s_AsyncCompileState;
|
|
s_HasStartedCompiling = false;
|
|
}
|
|
else
|
|
{
|
|
s_HasStartedCompiling = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if the user switched off the AOV before the shaders were compiled
|
|
if (s_HasStartedCompiling)
|
|
{
|
|
ShaderUtil.allowAsyncCompilation = s_AsyncCompileState;
|
|
s_HasStartedCompiling = false;
|
|
}
|
|
}
|
|
|
|
HDRenderPipelineAsset hdrp = HDRenderPipeline.currentAsset;
|
|
if (serializedProperties.aovBitmask.intValue != 0 && hdrp && !hdrp.currentPlatformRenderPipelineSettings.supportRuntimeAOVAPI)
|
|
{
|
|
Rect infoRect = rect;
|
|
// Compute the height of the infobox based on the width of the window and the amount of text
|
|
GUIStyle.none.CalcMinMaxWidth(new GUIContent(Styles.k_AlphaInfoPost), out float minWidth, out float maxWidth);
|
|
float lines = Mathf.Max(2, Mathf.CeilToInt(maxWidth / (rect.width - Styles.infoBoxIconWidth)));
|
|
infoRect.height = lines * CompositorStyle.k_Spacing;
|
|
EditorGUI.HelpBox(infoRect, Styles.k_AlphaInfoPost, MessageType.Info);
|
|
rect.y += infoRect.height + EditorGUIUtility.standardVerticalSpacing;
|
|
}
|
|
}
|
|
|
|
public static void DrawStackedLayerProperties(Rect rect, SerializedCompositionLayer serializedProperties, ReorderableList filterList)
|
|
{
|
|
rect.y += CompositorStyle.k_ListItemPading;
|
|
rect.height = CompositorStyle.k_SingleLineHeight;
|
|
|
|
EditorGUI.PropertyField(rect, serializedProperties.layerName, Styles.k_NameContent);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
switch (serializedProperties.inputLayerType.enumValueIndex)
|
|
{
|
|
case (int)CompositorLayer.LayerType.Camera:
|
|
EditorGUI.PropertyField(rect, serializedProperties.inputCamera, Styles.k_Camera);
|
|
break;
|
|
case (int)CompositorLayer.LayerType.Video:
|
|
EditorGUI.PropertyField(rect, serializedProperties.inputVideo, Styles.k_Video);
|
|
break;
|
|
case (int)CompositorLayer.LayerType.Image:
|
|
EditorGUI.PropertyField(rect, serializedProperties.inputTexture, Styles.k_Image);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
EditorGUI.PropertyField(rect, serializedProperties.fitType);
|
|
break;
|
|
default:
|
|
// This will happen if someone adds a new layer type and does not update this switch statement
|
|
Debug.Log("Unknown layer type: Please add code here to handle this type of layer.");
|
|
break;
|
|
}
|
|
rect.y += 1.5f * CompositorStyle.k_Spacing;
|
|
|
|
using (new EditorGUI.DisabledScope(serializedProperties.positionInStack.intValue == 0))
|
|
{
|
|
EditorGUI.PropertyField(rect, serializedProperties.clearDepth, Styles.k_ClearDepth);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
}
|
|
|
|
EditorGUI.PropertyField(rect, serializedProperties.clearAlpha, Styles.k_ClearAlpha);
|
|
rect.y += 1.0f * CompositorStyle.k_Spacing;
|
|
|
|
// Draw a min/max slider for tha alpha range
|
|
{
|
|
const float spacing = 5;
|
|
var labelRect = new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth, rect.height);
|
|
EditorGUI.PrefixLabel(labelRect, Styles.k_AlphaRange);
|
|
|
|
var minLabelRect = rect;
|
|
minLabelRect.x += EditorGUIUtility.labelWidth;
|
|
minLabelRect.width = EditorGUIUtility.fieldWidth / 2;
|
|
serializedProperties.alphaMin.floatValue = EditorGUI.FloatField(minLabelRect, serializedProperties.alphaMin.floatValue);
|
|
|
|
GUI.SetNextControlName("AlphaMinMaxSlider");
|
|
var sliderRect = rect;
|
|
sliderRect.x += EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth / 2 + spacing;
|
|
sliderRect.width -= (EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth + 2 * spacing);
|
|
float minVal = serializedProperties.alphaMin.floatValue;
|
|
float maxVal = serializedProperties.alphaMax.floatValue;
|
|
|
|
EditorGUI.MinMaxSlider(sliderRect, ref minVal, ref maxVal, 0, 1);
|
|
if (serializedProperties.alphaMin.floatValue != minVal || serializedProperties.alphaMax.floatValue != maxVal)
|
|
{
|
|
// Note: We need to move the focus when the slider changes, otherwise the textField will not update
|
|
GUI.FocusControl("AlphaMinMaxSlider");
|
|
serializedProperties.alphaMin.floatValue = minVal;
|
|
serializedProperties.alphaMax.floatValue = maxVal;
|
|
}
|
|
|
|
var maxLabelRect = rect;
|
|
maxLabelRect.x = sliderRect.x + sliderRect.width + spacing;
|
|
maxLabelRect.width = EditorGUIUtility.fieldWidth / 2;
|
|
serializedProperties.alphaMax.floatValue = EditorGUI.FloatField(maxLabelRect, serializedProperties.alphaMax.floatValue);
|
|
|
|
// sanity checks
|
|
if (serializedProperties.alphaMax.floatValue < serializedProperties.alphaMin.floatValue)
|
|
{
|
|
serializedProperties.alphaMax.floatValue = serializedProperties.alphaMin.floatValue;
|
|
}
|
|
if (serializedProperties.alphaMax.floatValue > 1)
|
|
{
|
|
serializedProperties.alphaMax.floatValue = 1;
|
|
}
|
|
if (serializedProperties.alphaMin.floatValue > serializedProperties.alphaMax.floatValue)
|
|
{
|
|
serializedProperties.alphaMin.floatValue = serializedProperties.alphaMax.floatValue;
|
|
}
|
|
if (serializedProperties.alphaMin.floatValue < 0)
|
|
{
|
|
serializedProperties.alphaMin.floatValue = 0;
|
|
}
|
|
}
|
|
rect.y += 1.5f * CompositorStyle.k_Spacing;
|
|
|
|
// The clear mode should be visible / configurable only for the first layer in the stack. For the other layers we set a camera-stacking specific clear-mode .
|
|
using (new EditorGUI.DisabledScope(serializedProperties.positionInStack.intValue != 0))
|
|
{
|
|
DrawPropertyHelper(rect, Styles.k_ClearMode, serializedProperties.overrideClearMode, serializedProperties.clearMode);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
}
|
|
|
|
DrawPropertyHelper(rect, Styles.k_AAMode, serializedProperties.overrideAA, serializedProperties.aaMode);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
DrawPropertyHelper(rect, Styles.k_CullingMask, serializedProperties.overrideCulling, serializedProperties.cullingMaskProperty);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
DrawPropertyHelper(rect, Styles.k_VolumeMask, serializedProperties.overrideVolume, serializedProperties.volumeMask);
|
|
rect.y += CompositorStyle.k_Spacing;
|
|
|
|
Rect filterRect = rect;
|
|
filterRect.y += 0.5f * CompositorStyle.k_Spacing;
|
|
filterList.DoList(filterRect);
|
|
}
|
|
|
|
static void DrawPropertyHelper(Rect rect, GUIContent label, SerializedProperty checkBox, SerializedProperty serializedProperty)
|
|
{
|
|
Rect rectCopy = rect;
|
|
EditorGUI.PropertyField(rectCopy, checkBox, GUIContent.none);
|
|
|
|
rectCopy.x += EditorGUIUtility.singleLineHeight;
|
|
rectCopy.width = EditorGUIUtility.labelWidth - EditorGUIUtility.singleLineHeight;
|
|
EditorGUI.LabelField(rectCopy, label);
|
|
|
|
using (new EditorGUI.DisabledScope(!checkBox.boolValue))
|
|
{
|
|
float pad = EditorGUIUtility.labelWidth;
|
|
rect.x += pad;
|
|
rect.width -= rect.x;
|
|
EditorGUI.PropertyField(rect, serializedProperty, GUIContent.none);
|
|
}
|
|
}
|
|
}
|
|
}
|