Rasagar/Library/PackageCache/com.unity.render-pipelines.high-definition/Editor/Compositor/CompositionManagerEditor.cs
2024-08-26 23:07:20 +03:00

412 lines
18 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering.HighDefinition.Attributes;
using UnityEngine.Rendering.HighDefinition.Compositor;
using UnityEngine.Video;
using UnityEditor;
using UnityEditorInternal;
namespace UnityEditor.Rendering.HighDefinition.Compositor
{
// Responsible for drawing the inspector UI of the composition manager
[CustomEditor(typeof(CompositionManager))]
internal class CompositionManagerEditor : Editor
{
static partial class Styles
{
static public readonly GUIContent k_CompositionGraph = EditorGUIUtility.TrTextContent("Composition Graph", "Specifies the Shader Graph that will be used to produce the final composited output.");
static public readonly GUIContent k_OutputCamera = EditorGUIUtility.TrTextContent("Output Camera", "Specifies the camera that will output the final composited image.");
static public readonly GUIContent k_EnablePreview = EditorGUIUtility.TrTextContent("Enable Preview", "When enabled, the compositor will generate the final composed frame even in edit mode.");
static public readonly GUIContent k_InputFilters = EditorGUIUtility.TrTextContent("Input Filters", "A list of color filters that will be executed before composing the frame.");
static public readonly GUIContent k_Properties = EditorGUIUtility.TrTextContent("Properties", "The properties of a layer or sub-layer.");
static public readonly GUIContent k_RenderSchedule = EditorGUIUtility.TrTextContent("Render Schedule", "A list of layers and sub-layers in the scene. Layers are drawn from top to bottom.");
static public readonly string k_AlphaWarningPipeline = "The rendering pipeline was not configured to output an alpha channel. You can select a color buffer format that supports alpha in the HDRP quality settings.";
static public readonly string k_AlphaWarningPost = "The post processing system was not configured to process the alpha channel. You can select a buffer format that supports alpha in the HDRP quality settings.";
static public readonly string k_ShaderWarning = "You must specify a composition graph to see an output from the compositor.";
static public readonly GUIStyle k_HeaderStyle = new GUIStyle(EditorStyles.helpBox) { fontSize = CompositorStyle.k_HeaderFontSize };
}
ReorderableList m_layerList;
ReorderableList m_filterList;
// Cached serialized properties
SerializedCompositionManager m_SerializedProperties;
List<SerializedCompositionLayer> m_SerializedLayerProperties;
List<SerializedShaderProperty> m_SerializedShaderProperties;
bool m_IsEditorDirty = true;
bool m_EnablePreview;
bool layerListChange;
CompositionManager m_compositionManager;
public bool isDirty => m_IsEditorDirty;
public int defaultSelection = -1;
public int selectionIndex
{
get => m_layerList != null ? m_layerList.index : -1;
set
{
if (m_layerList != null) m_layerList.index = Math.Min(value, m_layerList.count - 1);
}
}
void AddLayerOfTypeCallback(object type)
{
Undo.RecordObject(m_compositionManager, "Add compositor sublayer");
m_compositionManager.AddNewLayer(m_layerList.index + 1, (CompositorLayer.LayerType)type);
m_SerializedProperties.layerList.serializedObject.Update();
m_compositionManager.DeleteLayerRTs();
m_compositionManager.UpdateLayerSetup();
}
void AddFilterOfTypeCallback(object type)
{
Undo.RecordObject(m_compositionManager, "Add input filter");
m_compositionManager.AddInputFilterAtLayer(CompositionFilter.Create((CompositionFilter.FilterType)type), m_layerList.index);
m_SerializedProperties.layerList.serializedObject.Update();
CacheSerializedObjects();
}
void DrawCompositionParameters()
{
ShaderPropertyUI.Draw(m_SerializedShaderProperties);
}
public bool CacheSerializedObjects()
{
try
{
m_SerializedProperties = new SerializedCompositionManager(serializedObject);
}
catch (Exception)
{
return false;
}
m_SerializedLayerProperties = new List<SerializedCompositionLayer>();
m_SerializedShaderProperties = new List<SerializedShaderProperty>();
var serializedLayerList = m_SerializedProperties.layerList;
for (int layerIndex = 0; layerIndex < serializedLayerList.arraySize; layerIndex++)
{
var serializedLayer = serializedLayerList.GetArrayElementAtIndex(layerIndex);
m_SerializedLayerProperties.Add(new SerializedCompositionLayer(serializedLayer));
}
var serializedPropertyList = m_SerializedProperties.shaderProperties;
if (m_SerializedProperties.shaderProperties == null)
{
return false;
}
for (int pIndex = 0; pIndex < serializedPropertyList.arraySize; pIndex++)
{
var serializedProperty = serializedPropertyList.GetArrayElementAtIndex(pIndex);
m_SerializedShaderProperties.Add(new SerializedShaderProperty(serializedProperty));
}
return true;
}
void OnEnable()
{
CacheSerializedObjects();
m_IsEditorDirty = false;
}
public override void OnInspectorGUI()
{
m_compositionManager = (CompositionManager)target;
if (m_compositionManager == null)
{
Debug.LogError("Compositor target was null");
return;
}
// Cache the serialized property fields
if (m_IsEditorDirty || m_SerializedProperties == null)
{
if (CacheSerializedObjects())
{
m_IsEditorDirty = false;
}
else
{
return;
}
}
m_SerializedProperties.Update();
m_EnablePreview = EditorGUILayout.Toggle(Styles.k_EnablePreview, m_compositionManager.enableOutput);
{
m_compositionManager.enableOutput = m_EnablePreview;
}
bool cameraChange = false;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_SerializedProperties.outputCamera, Styles.k_OutputCamera);
if (EditorGUI.EndChangeCheck())
{
cameraChange = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_SerializedProperties.compositionShader, Styles.k_CompositionGraph);
bool shaderChange = false;
if (EditorGUI.EndChangeCheck())
{
// Clear the existing shader (the new shader will be loaded in the next Update)
m_IsEditorDirty = true;
shaderChange = true;
}
if (m_compositionManager.shader == null)
{
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox(Styles.k_ShaderWarning, MessageType.Error);
}
EditorGUILayout.PropertyField(m_SerializedProperties.displayNumber);
// Draw some warnings in case alpha is not fully supported
if (m_compositionManager.alphaSupport == CompositionManager.AlphaChannelSupport.None)
{
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox(Styles.k_AlphaWarningPipeline, MessageType.Warning);
}
else if (m_compositionManager.alphaSupport == CompositionManager.AlphaChannelSupport.Rendering)
{
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox(Styles.k_AlphaWarningPost, MessageType.Warning);
}
// Now draw the composition shader properties
DrawCompositionParameters();
// Now draw the list of layers
EditorGUILayout.Separator();
layerListChange = false;
if (m_layerList == null)
{
var serializedLayerList = m_SerializedProperties.layerList;
m_layerList = new ReorderableList(m_SerializedProperties.compositorSO, serializedLayerList, true, false, true, true);
// Pre-select the "default" item in the list (used to remember the last selected item when re-creating the Editor)
if (defaultSelection >= 0)
{
m_layerList.index = Math.Min(defaultSelection, m_layerList.count - 1);
}
m_layerList.drawHeaderCallback = (Rect rect) =>
{
};
m_layerList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
if (index < m_SerializedLayerProperties.Count)
{
var serializedProperties = m_SerializedLayerProperties[index];
CompositionLayerUI.DrawItemInList(rect, serializedProperties, m_compositionManager.GetRenderTarget(index), m_compositionManager.aspectRatio, m_compositionManager.alphaSupport != CompositionManager.AlphaChannelSupport.None);
}
};
m_layerList.onReorderCallbackWithDetails += (list, oldIndex, newIndex) =>
{
layerListChange = true;
m_IsEditorDirty = true;
m_compositionManager.ReorderChildren(oldIndex, newIndex);
if (!m_compositionManager.ValidateLayerListOrder(oldIndex, newIndex))
{
// The new position is invalid, so set the currently selected layer to the old/starting position s
m_layerList.index = oldIndex;
}
};
m_layerList.elementHeightCallback = (index) =>
{
if (index < m_SerializedLayerProperties.Count)
{
return m_SerializedLayerProperties[index].GetListItemHeight();
}
return 0;
};
m_layerList.onAddCallback = (list) =>
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Image"), false, AddLayerOfTypeCallback, CompositorLayer.LayerType.Image);
menu.AddItem(new GUIContent("Video"), false, AddLayerOfTypeCallback, CompositorLayer.LayerType.Video);
menu.AddItem(new GUIContent("Camera"), false, AddLayerOfTypeCallback, CompositorLayer.LayerType.Camera);
menu.ShowAsContext();
m_IsEditorDirty = true;
m_SerializedProperties.layerList.serializedObject.Update();
EditorUtility.SetDirty(m_compositionManager.profile);
};
m_layerList.onRemoveCallback = (list) =>
{
Undo.RecordObject(m_compositionManager, "Remove compositor sublayer");
m_compositionManager.RemoveLayerAtIndex(list.index);
m_IsEditorDirty = true;
EditorUtility.SetDirty(m_compositionManager.profile);
};
m_layerList.onSelectCallback = (index) =>
{
m_filterList = null;
};
m_layerList.onCanRemoveCallback = (list) =>
{
return !m_compositionManager.IsOutputLayer(list.index);
};
m_layerList.onCanAddCallback = (list) =>
{
return list.index >= 0;
};
m_layerList.headerHeight = 0;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField(Styles.k_RenderSchedule, Styles.k_HeaderStyle);
m_layerList.DoLayoutList();
EditorGUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
{
layerListChange = true;
}
float height = EditorGUIUtility.singleLineHeight;
if (m_layerList.index >= 0)
{
height += m_SerializedLayerProperties[m_layerList.index].GetPropertiesHeight();
}
var rectangle = EditorGUILayout.BeginVertical(GUILayout.Height(height));
EditorGUI.BeginChangeCheck();
if (m_layerList.index >= 0)
{
EditorGUILayout.LabelField(Styles.k_Properties, Styles.k_HeaderStyle);
rectangle.y += EditorGUIUtility.singleLineHeight * 1.5f;
rectangle.x += 5;
rectangle.width -= 10;
var serializedProperties = m_SerializedLayerProperties[m_layerList.index];
DrawLayerProperties(rectangle, serializedProperties, m_layerList.index, null);
}
EditorGUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
{
// Also the layers might need to be re-initialized
layerListChange = true;
}
if (m_SerializedProperties != null)
{
m_SerializedProperties.ApplyModifiedProperties();
}
if (shaderChange)
{
// This needs to run after m_SerializedProperties.ApplyModifiedProperties
CompositionUtils.LoadOrCreateCompositionProfileAsset(m_compositionManager);
m_compositionManager.SetupCompositionMaterial();
CompositionUtils.SetDefaultLayers(m_compositionManager);
}
if (cameraChange)
{
m_compositionManager.DropCompositorCamera();
m_compositionManager.Init();
}
if (layerListChange)
{
// Some properties were changed, mark the profile as dirty so it can be saved if the user saves the scene
EditorUtility.SetDirty(m_compositionManager);
EditorUtility.SetDirty(m_compositionManager.profile);
m_compositionManager.DeleteLayerRTs();
m_compositionManager.UpdateLayerSetup();
}
}
void DrawLayerProperties(Rect rect, SerializedCompositionLayer serializedProperties, int layerIndex, RenderTexture preview = null)
{
if (serializedProperties == null)
{
return;
}
if (serializedProperties.outTarget.intValue != (int)CompositorLayer.OutputTarget.CameraStack)
{
CompositionLayerUI.DrawOutputLayerProperties(rect, serializedProperties, m_compositionManager.DeleteLayerRTs);
}
else
{
if (m_filterList == null)
{
m_filterList = new ReorderableList(serializedProperties.inputFilters.serializedObject, serializedProperties.inputFilters, true, true, true, true);
m_filterList.onAddCallback = (list) =>
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Chroma Keying"), false, AddFilterOfTypeCallback, 0);
menu.AddItem(new GUIContent("Alpha Mask"), false, AddFilterOfTypeCallback, 1);
menu.ShowAsContext();
EditorUtility.SetDirty(m_compositionManager.profile);
EditorUtility.SetDirty(m_compositionManager);
};
m_filterList.drawElementCallback = (Rect r, int index, bool isActive, bool isFocused) =>
{
if (index < m_SerializedLayerProperties[m_layerList.index].filterList.Count)
{
var serializedFilter = m_SerializedLayerProperties[m_layerList.index].filterList[index];
CompositionFilterUI.Draw(r, serializedFilter);
}
};
m_filterList.drawNoneElementCallback = (Rect r) =>
{
using (new EditorGUI.DisabledScope(true))
{
EditorGUI.LabelField(r, "List Is Empty", EditorStyles.label);
}
};
m_filterList.drawHeaderCallback = (Rect r) =>
{
EditorGUI.LabelField(r, Styles.k_InputFilters, EditorStyles.largeLabel);
};
m_filterList.elementHeightCallback = (index) =>
{
if (index < m_SerializedLayerProperties[m_layerList.index].filterList.Count)
{
var filter = m_SerializedLayerProperties[m_layerList.index].filterList[index];
return filter.GetHeight();
}
return CompositorStyle.k_Spacing;
};
}
CompositionLayerUI.DrawStackedLayerProperties(rect, serializedProperties, m_filterList);
}
}
}
}