437 lines
17 KiB
C#
437 lines
17 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace UnityEngine.Rendering.PostProcessing
|
|
{
|
|
#if (ENABLE_VR_MODULE && ENABLE_VR)
|
|
using XRSettings = UnityEngine.XR.XRSettings;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// A context object passed around all post-processing effects in a frame.
|
|
/// </summary>
|
|
public sealed class PostProcessRenderContext
|
|
{
|
|
// -----------------------------------------------------------------------------------------
|
|
// The following should be filled by the render pipeline
|
|
|
|
Camera m_Camera;
|
|
|
|
/// <summary>
|
|
/// The camera currently being rendered.
|
|
/// </summary>
|
|
public Camera camera
|
|
{
|
|
get { return m_Camera; }
|
|
set
|
|
{
|
|
m_Camera = value;
|
|
|
|
#if !UNITY_SWITCH && (ENABLE_VR_MODULE && ENABLE_VR)
|
|
if (m_Camera.stereoEnabled)
|
|
{
|
|
var xrDesc = XRSettings.eyeTextureDesc;
|
|
stereoRenderingMode = StereoRenderingMode.SinglePass;
|
|
numberOfEyes = 1;
|
|
|
|
#if UNITY_2018_3_OR_NEWER
|
|
if (XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.MultiPass)
|
|
stereoRenderingMode = StereoRenderingMode.MultiPass;
|
|
#endif
|
|
|
|
#if UNITY_STANDALONE || UNITY_EDITOR || UNITY_PS4 || UNITY_PS5
|
|
if (xrDesc.dimension == TextureDimension.Tex2DArray)
|
|
stereoRenderingMode = StereoRenderingMode.SinglePassInstanced;
|
|
#endif
|
|
if (stereoRenderingMode == StereoRenderingMode.SinglePassInstanced)
|
|
numberOfEyes = 2;
|
|
|
|
width = xrDesc.width;
|
|
height = xrDesc.height;
|
|
m_sourceDescriptor = xrDesc;
|
|
|
|
if (m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
|
|
xrActiveEye = (int)Camera.StereoscopicEye.Right;
|
|
|
|
screenWidth = XRSettings.eyeTextureWidth;
|
|
screenHeight = XRSettings.eyeTextureHeight;
|
|
stereoActive = true;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
width = m_Camera.pixelWidth;
|
|
height = m_Camera.pixelHeight;
|
|
m_sourceDescriptor.width = width;
|
|
m_sourceDescriptor.height = height;
|
|
screenWidth = width;
|
|
screenHeight = height;
|
|
stereoActive = false;
|
|
numberOfEyes = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The command buffer to fill render commands in.
|
|
/// </summary>
|
|
public CommandBuffer command { get; set; }
|
|
|
|
/// <summary>
|
|
/// The source target for this pass (can't be the same as <see cref="destination"/>).
|
|
/// </summary>
|
|
public RenderTargetIdentifier source { get; set; }
|
|
|
|
/// <summary>
|
|
/// The destination target for this pass (can't be the same as <see cref="source"/>).
|
|
/// </summary>
|
|
public RenderTargetIdentifier destination { get; set; }
|
|
|
|
/// <summary>
|
|
/// The texture format used for the source target.
|
|
/// </summary>
|
|
// We need this to be set explictely as we don't have any way of knowing if we're rendering
|
|
// using HDR or not as scriptable render pipelines may ignore the HDR toggle on camera
|
|
// completely
|
|
public RenderTextureFormat sourceFormat { get; set; }
|
|
|
|
/// <summary>
|
|
/// Should we flip the last pass?
|
|
/// </summary>
|
|
public bool flip { get; set; }
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// The following is auto-populated by the post-processing stack
|
|
|
|
/// <summary>
|
|
/// The resource asset contains reference to external resources (shaders, textures...).
|
|
/// </summary>
|
|
public PostProcessResources resources { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The property sheet factory handled by the currently active <see cref="PostProcessLayer"/>.
|
|
/// </summary>
|
|
public PropertySheetFactory propertySheets { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// A dictionary to store custom user data objects. This is handy to share data between
|
|
/// custom effects.
|
|
/// </summary>
|
|
public Dictionary<string, object> userData { get; private set; }
|
|
|
|
/// <summary>
|
|
/// A reference to the internal debug layer.
|
|
/// </summary>
|
|
public PostProcessDebugLayer debugLayer { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The current camera width (in pixels).
|
|
/// </summary>
|
|
public int width { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The current camera height (in pixels).
|
|
/// </summary>
|
|
public int height { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Is stereo rendering active?
|
|
/// </summary>
|
|
public bool stereoActive { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The current active rendering eye (for XR).
|
|
/// </summary>
|
|
public int xrActiveEye { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The number of eyes for XR outputs.
|
|
/// </summary>
|
|
public int numberOfEyes { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Available XR rendering modes.
|
|
/// </summary>
|
|
public enum StereoRenderingMode
|
|
{
|
|
/// <summary>
|
|
/// Multi-pass.
|
|
/// </summary>
|
|
MultiPass = 0,
|
|
|
|
/// <summary>
|
|
/// Single-pass.
|
|
/// </summary>
|
|
SinglePass,
|
|
|
|
/// <summary>
|
|
/// Single-pass instanced.
|
|
/// </summary>
|
|
SinglePassInstanced,
|
|
|
|
/// <summary>
|
|
/// Single-pass multi-view.
|
|
/// </summary>
|
|
SinglePassMultiview
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current rendering mode for XR.
|
|
/// </summary>
|
|
public StereoRenderingMode stereoRenderingMode { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The width of the logical screen size.
|
|
/// </summary>
|
|
public int screenWidth { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The height of the logical screen size.
|
|
/// </summary>
|
|
public int screenHeight { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Are we currently rendering in the scene view?
|
|
/// </summary>
|
|
public bool isSceneView { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The current anti-aliasing method used by the camera.
|
|
/// </summary>
|
|
public PostProcessLayer.Antialiasing antialiasing { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// A reference to the temporal anti-aliasing settings for the rendering layer. This is
|
|
/// mostly used to grab the jitter vector and other TAA-related values when an effect needs
|
|
/// to do temporal reprojection.
|
|
/// </summary>
|
|
public TemporalAntialiasing temporalAntialiasing { get; internal set; }
|
|
|
|
// Internal values used for builtin effects
|
|
// Beware, these may not have been set before a specific builtin effect has been executed
|
|
internal PropertySheet uberSheet;
|
|
internal Texture autoExposureTexture;
|
|
internal LogHistogram logHistogram;
|
|
internal Texture logLut;
|
|
internal AutoExposure autoExposure;
|
|
internal int bloomBufferNameID;
|
|
#if UNITY_2018_2_OR_NEWER
|
|
internal bool physicalCamera;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Resets the state of this context object. This is called by the render pipeline on every
|
|
/// frame and allows re-using the same context object between frames without having to
|
|
/// recreate a new one.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
m_Camera = null;
|
|
width = 0;
|
|
height = 0;
|
|
m_sourceDescriptor = new RenderTextureDescriptor(0, 0);
|
|
#if UNITY_2018_2_OR_NEWER
|
|
physicalCamera = false;
|
|
#endif
|
|
stereoActive = false;
|
|
xrActiveEye = (int)Camera.StereoscopicEye.Left;
|
|
screenWidth = 0;
|
|
screenHeight = 0;
|
|
|
|
command = null;
|
|
source = 0;
|
|
destination = 0;
|
|
sourceFormat = RenderTextureFormat.ARGB32;
|
|
flip = false;
|
|
|
|
resources = null;
|
|
propertySheets = null;
|
|
debugLayer = null;
|
|
isSceneView = false;
|
|
antialiasing = PostProcessLayer.Antialiasing.None;
|
|
temporalAntialiasing = null;
|
|
|
|
uberSheet = null;
|
|
autoExposureTexture = null;
|
|
logLut = null;
|
|
autoExposure = null;
|
|
bloomBufferNameID = -1;
|
|
|
|
if (userData == null)
|
|
userData = new Dictionary<string, object>();
|
|
|
|
userData.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if temporal anti-aliasing is supported and enabled.
|
|
/// </summary>
|
|
/// <returns><c>true</c> if temporal anti-aliasing is supported and enabled, <c>false</c>
|
|
/// otherwise</returns>
|
|
public bool IsTemporalAntialiasingActive()
|
|
{
|
|
return antialiasing == PostProcessLayer.Antialiasing.TemporalAntialiasing
|
|
&& !isSceneView
|
|
&& temporalAntialiasing.IsSupported();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a specific debug overlay is enabled.
|
|
/// </summary>
|
|
/// <param name="overlay">The debug overlay to look for</param>
|
|
/// <returns><c>true</c> if the specified debug overlay is enable, <c>false</c>
|
|
/// otherwise</returns>
|
|
public bool IsDebugOverlayEnabled(DebugOverlay overlay)
|
|
{
|
|
return debugLayer.debugOverlay == overlay;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Blit a source render target to the debug overlay target. This is a direct shortcut to
|
|
/// <see cref="PostProcessDebugLayer.PushDebugOverlay"/>.
|
|
/// </summary>
|
|
/// <param name="cmd">The command buffer to send render commands to</param>
|
|
/// <param name="source">The source target</param>
|
|
/// <param name="sheet">The property sheet to use for the blit</param>
|
|
/// <param name="pass">The pass to use for the property sheet</param>
|
|
/// <seealso cref="PostProcessDebugLayer.PushDebugOverlay"/>
|
|
public void PushDebugOverlay(CommandBuffer cmd, RenderTargetIdentifier source, PropertySheet sheet, int pass)
|
|
{
|
|
debugLayer.PushDebugOverlay(cmd, source, sheet, pass);
|
|
}
|
|
|
|
// TODO: Change w/h name to texture w/h in order to make
|
|
// size usages explicit
|
|
RenderTextureDescriptor m_sourceDescriptor;
|
|
internal RenderTextureDescriptor GetDescriptor(int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default, RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default)
|
|
{
|
|
var modifiedDesc = new RenderTextureDescriptor(m_sourceDescriptor.width, m_sourceDescriptor.height,
|
|
m_sourceDescriptor.colorFormat, depthBufferBits);
|
|
modifiedDesc.dimension = m_sourceDescriptor.dimension;
|
|
modifiedDesc.volumeDepth = m_sourceDescriptor.volumeDepth;
|
|
modifiedDesc.vrUsage = m_sourceDescriptor.vrUsage;
|
|
modifiedDesc.msaaSamples = m_sourceDescriptor.msaaSamples;
|
|
modifiedDesc.memoryless = m_sourceDescriptor.memoryless;
|
|
|
|
modifiedDesc.useMipMap = m_sourceDescriptor.useMipMap;
|
|
modifiedDesc.autoGenerateMips = m_sourceDescriptor.autoGenerateMips;
|
|
modifiedDesc.enableRandomWrite = m_sourceDescriptor.enableRandomWrite;
|
|
modifiedDesc.shadowSamplingMode = m_sourceDescriptor.shadowSamplingMode;
|
|
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (m_Camera.allowDynamicResolution)
|
|
modifiedDesc.useDynamicScale = true;
|
|
#endif
|
|
|
|
if (colorFormat != RenderTextureFormat.Default)
|
|
modifiedDesc.colorFormat = colorFormat;
|
|
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (readWrite == RenderTextureReadWrite.sRGB)
|
|
modifiedDesc.sRGB = true;
|
|
else if (readWrite == RenderTextureReadWrite.Linear)
|
|
modifiedDesc.sRGB = false;
|
|
else if (readWrite == RenderTextureReadWrite.Default)
|
|
modifiedDesc.sRGB = QualitySettings.activeColorSpace != ColorSpace.Gamma;
|
|
#else
|
|
modifiedDesc.sRGB = readWrite != RenderTextureReadWrite.Linear;
|
|
#endif
|
|
|
|
return modifiedDesc;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Grabs a temporary render target with the current display size.
|
|
/// </summary>
|
|
/// <param name="cmd">The command buffer to grab a render target from</param>
|
|
/// <param name="nameID">The shader property name for this texture</param>
|
|
/// <param name="depthBufferBits">The number of bits to use for the depth buffer</param>
|
|
/// <param name="colorFormat">The render texture format</param>
|
|
/// <param name="readWrite">The color space conversion mode</param>
|
|
/// <param name="filter">The texture filtering mode</param>
|
|
/// <param name="widthOverride">Override the display width; use <c>0</c> to disable the override</param>
|
|
/// <param name="heightOverride">Override the display height; use <c>0</c> to disable the override</param>
|
|
public void GetScreenSpaceTemporaryRT(CommandBuffer cmd, int nameID,
|
|
int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default, RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default,
|
|
FilterMode filter = FilterMode.Bilinear, int widthOverride = 0, int heightOverride = 0)
|
|
{
|
|
var desc = GetDescriptor(depthBufferBits, colorFormat, readWrite);
|
|
if (widthOverride > 0)
|
|
desc.width = widthOverride;
|
|
if (heightOverride > 0)
|
|
desc.height = heightOverride;
|
|
|
|
//intermediates in VR are unchanged
|
|
if (stereoActive && desc.dimension == Rendering.TextureDimension.Tex2DArray)
|
|
desc.dimension = Rendering.TextureDimension.Tex2D;
|
|
|
|
#if UNITY_2019_1_OR_NEWER
|
|
cmd.GetTemporaryRT(nameID, desc, filter);
|
|
#elif UNITY_2017_3_OR_NEWER
|
|
cmd.GetTemporaryRT(nameID, desc.width, desc.height, desc.depthBufferBits, filter, desc.colorFormat, readWrite, desc.msaaSamples, desc.enableRandomWrite, desc.memoryless, m_Camera.allowDynamicResolution);
|
|
#else
|
|
cmd.GetTemporaryRT(nameID, desc.width, desc.height, desc.depthBufferBits, filter, desc.colorFormat, readWrite, desc.msaaSamples, desc.enableRandomWrite, desc.memoryless);
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Grabs a temporary render target with the current display size.
|
|
/// </summary>
|
|
/// <param name="depthBufferBits">The number of bits to use for the depth buffer</param>
|
|
/// <param name="colorFormat">The render texture format</param>
|
|
/// <param name="readWrite">The color space conversion mode</param>
|
|
/// <param name="widthOverride">Override the display width; use <c>0</c> to disable the override</param>
|
|
/// <param name="heightOverride">Override the display height; use <c>0</c> to disable the override</param>
|
|
/// <returns>A temporary render target</returns>
|
|
public RenderTexture GetScreenSpaceTemporaryRT(int depthBufferBits = 0, RenderTextureFormat colorFormat = RenderTextureFormat.Default,
|
|
RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default, int widthOverride = 0, int heightOverride = 0)
|
|
{
|
|
var desc = GetDescriptor(depthBufferBits, colorFormat, readWrite);
|
|
if (widthOverride > 0)
|
|
desc.width = widthOverride;
|
|
if (heightOverride > 0)
|
|
desc.height = heightOverride;
|
|
|
|
return RenderTexture.GetTemporary(desc);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update current single-pass stereo state for TAA, AO, etc.
|
|
/// </summary>
|
|
/// <param name="isTAAEnabled">The enabled state of Temporal Anti-aliasing</param>
|
|
/// <param name="isAOEnabled">The enabled state of Ambient Occlusion</param>
|
|
/// <param name="isSSREnabled">The enabled state of Screen-space Reflections</param>
|
|
public void UpdateSinglePassStereoState(bool isTAAEnabled, bool isAOEnabled, bool isSSREnabled)
|
|
{
|
|
#if UNITY_2019_1_OR_NEWER && ENABLE_VR_MODULE && ENABLE_VR
|
|
var xrDesc = XRSettings.eyeTextureDesc;
|
|
screenWidth = XRSettings.eyeTextureWidth;
|
|
|
|
if (stereoRenderingMode == StereoRenderingMode.SinglePass)
|
|
{
|
|
//For complex effects, it's more efficient to disable XR single-pass interface
|
|
if (isTAAEnabled || isAOEnabled || isSSREnabled)
|
|
{
|
|
numberOfEyes = 1;
|
|
}
|
|
else
|
|
{
|
|
//Use XR-interface method:
|
|
//We take care of providing stereoized camera render texture to postprocessing framework and rendering out the final postprocessed results to the each of the eye textures
|
|
// https://docs.google.com/document/d/1hANbhKCRIJs6ww7XoAIXbX3ArdAs7OBOTfZL1MqgtPI
|
|
|
|
numberOfEyes = 2;
|
|
xrDesc.width /= 2;
|
|
xrDesc.vrUsage = VRTextureUsage.None;
|
|
screenWidth /= 2;
|
|
}
|
|
|
|
width = xrDesc.width;
|
|
height = xrDesc.height;
|
|
m_sourceDescriptor = xrDesc;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|