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 } } }