using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using Unity.Collections; using UnityEngine.Scripting.APIUpdating; using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.Universal { /// /// Input requirements for ScriptableRenderPass. /// /// [Flags] public enum ScriptableRenderPassInput { None = 0, Depth = 1 << 0, Normal = 1 << 1, Color = 1 << 2, Motion = 1 << 3 } // Note: Spaced built-in events so we can add events in between them // We need to leave room as we sort render passes based on event. // Users can also inject render pass events in a specific point by doing RenderPassEvent + offset /// /// Controls when the render pass executes. /// public enum RenderPassEvent { /// /// Executes a ScriptableRenderPass before rendering any other passes in the pipeline. /// Camera matrices and stereo rendering are not setup this point. /// You can use this to draw to custom input textures used later in the pipeline, f.ex LUT textures. /// BeforeRendering = 0, /// /// Executes a ScriptableRenderPass before rendering shadowmaps. /// Camera matrices and stereo rendering are not setup this point. /// BeforeRenderingShadows = 50, /// /// Executes a ScriptableRenderPass after rendering shadowmaps. /// Camera matrices and stereo rendering are not setup this point. /// AfterRenderingShadows = 100, /// /// Executes a ScriptableRenderPass before rendering prepasses, f.ex, depth prepass. /// Camera matrices and stereo rendering are already setup at this point. /// BeforeRenderingPrePasses = 150, [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Obsolete, to match the capital from 'Prepass' to 'PrePass' (UnityUpgradable) -> BeforeRenderingPrePasses")] BeforeRenderingPrepasses = 151, /// /// Executes a ScriptableRenderPass after rendering prepasses, f.ex, depth prepass. /// Camera matrices and stereo rendering are already setup at this point. /// AfterRenderingPrePasses = 200, /// /// Executes a ScriptableRenderPass before rendering gbuffer pass. /// BeforeRenderingGbuffer = 210, /// /// Executes a ScriptableRenderPass after rendering gbuffer pass. /// AfterRenderingGbuffer = 220, /// /// Executes a ScriptableRenderPass before rendering deferred shading pass. /// BeforeRenderingDeferredLights = 230, /// /// Executes a ScriptableRenderPass after rendering deferred shading pass. /// AfterRenderingDeferredLights = 240, /// /// Executes a ScriptableRenderPass before rendering opaque objects. /// BeforeRenderingOpaques = 250, /// /// Executes a ScriptableRenderPass after rendering opaque objects. /// AfterRenderingOpaques = 300, /// /// Executes a ScriptableRenderPass before rendering the sky. /// BeforeRenderingSkybox = 350, /// /// Executes a ScriptableRenderPass after rendering the sky. /// AfterRenderingSkybox = 400, /// /// Executes a ScriptableRenderPass before rendering transparent objects. /// BeforeRenderingTransparents = 450, /// /// Executes a ScriptableRenderPass after rendering transparent objects. /// AfterRenderingTransparents = 500, /// /// Executes a ScriptableRenderPass before rendering post-processing effects. /// BeforeRenderingPostProcessing = 550, /// /// Executes a ScriptableRenderPass after rendering post-processing effects but before final blit, post-processing AA effects and color grading. /// AfterRenderingPostProcessing = 600, /// /// Executes a ScriptableRenderPass after rendering all effects. /// AfterRendering = 1000, } /// /// ScriptableRenderPass implements a logical rendering pass that can be used to extend Universal RP renderer. /// public abstract partial class ScriptableRenderPass { public RenderPassEvent renderPassEvent { get; set; } public RenderTargetIdentifier[] colorAttachments { get => m_ColorAttachments; } public RenderTargetIdentifier colorAttachment { get => m_ColorAttachments[0]; } public RenderTargetIdentifier depthAttachment { get => m_DepthAttachment; } public RenderBufferStoreAction[] colorStoreActions { get => m_ColorStoreActions; } public RenderBufferStoreAction depthStoreAction { get => m_DepthStoreAction; } internal bool[] overriddenColorStoreActions { get => m_OverriddenColorStoreActions; } internal bool overriddenDepthStoreAction { get => m_OverriddenDepthStoreAction; } /// /// The input requirements for the ScriptableRenderPass, which has been set using ConfigureInput /// /// public ScriptableRenderPassInput input { get => m_Input; } public ClearFlag clearFlag { get => m_ClearFlag; } public Color clearColor { get => m_ClearColor; } RenderBufferStoreAction[] m_ColorStoreActions = new RenderBufferStoreAction[] { RenderBufferStoreAction.Store }; RenderBufferStoreAction m_DepthStoreAction = RenderBufferStoreAction.Store; // by default all store actions are Store. The overridden flags are used to keep track of explicitly requested store actions, to // help figuring out the correct final store action for merged render passes when using the RenderPass API. private bool[] m_OverriddenColorStoreActions = new bool[] { false }; private bool m_OverriddenDepthStoreAction = false; /// /// A ProfilingSampler for the entire render pass. Used as a profiling name by ScriptableRenderer when executing the pass. /// Default is Unnamed_ScriptableRenderPass. /// Set base.profilingSampler from the sub-class constructor to set a profiling name for a custom ScriptableRenderPass. /// protected internal ProfilingSampler profilingSampler { get; set; } internal bool overrideCameraTarget { get; set; } internal bool isBlitRenderPass { get; set; } internal bool useNativeRenderPass { get; set; } internal int renderTargetWidth { get; set; } internal int renderTargetHeight { get; set; } internal int renderTargetSampleCount { get; set; } internal bool depthOnly { get; set; } // this flag is updated each frame to keep track of which pass is the last for the current camera internal bool isLastPass { get; set; } // index to track the position in the current frame internal int renderPassQueueIndex { get; set; } internal NativeArray m_ColorAttachmentIndices; internal NativeArray m_InputAttachmentIndices; internal GraphicsFormat[] renderTargetFormat { get; set; } RenderTargetIdentifier[] m_ColorAttachments = new RenderTargetIdentifier[] { BuiltinRenderTextureType.CameraTarget }; internal RenderTargetIdentifier[] m_InputAttachments = new RenderTargetIdentifier[8]; internal bool[] m_InputAttachmentIsTransient = new bool[8]; RenderTargetIdentifier m_DepthAttachment = BuiltinRenderTextureType.CameraTarget; ScriptableRenderPassInput m_Input = ScriptableRenderPassInput.None; ClearFlag m_ClearFlag = ClearFlag.None; Color m_ClearColor = Color.black; internal DebugHandler GetActiveDebugHandler(RenderingData renderingData) { var debugHandler = renderingData.cameraData.renderer.DebugHandler; if ((debugHandler != null) && debugHandler.IsActiveForCamera(ref renderingData.cameraData)) return debugHandler; return null; } public ScriptableRenderPass() { renderPassEvent = RenderPassEvent.AfterRenderingOpaques; m_ColorAttachments = new RenderTargetIdentifier[] { BuiltinRenderTextureType.CameraTarget, 0, 0, 0, 0, 0, 0, 0 }; m_InputAttachments = new RenderTargetIdentifier[] { -1, -1, -1, -1, -1, -1, -1, -1 }; m_InputAttachmentIsTransient = new bool[] { false, false, false, false, false, false, false, false }; m_DepthAttachment = BuiltinRenderTextureType.CameraTarget; m_ColorStoreActions = new RenderBufferStoreAction[] { RenderBufferStoreAction.Store, 0, 0, 0, 0, 0, 0, 0 }; m_DepthStoreAction = RenderBufferStoreAction.Store; m_OverriddenColorStoreActions = new bool[] { false, false, false, false, false, false, false, false }; m_OverriddenDepthStoreAction = false; m_ClearFlag = ClearFlag.None; m_ClearColor = Color.black; overrideCameraTarget = false; isBlitRenderPass = false; profilingSampler = new ProfilingSampler($"Unnamed_{nameof(ScriptableRenderPass)}"); useNativeRenderPass = true; renderTargetWidth = -1; renderTargetHeight = -1; renderTargetSampleCount = -1; renderPassQueueIndex = -1; renderTargetFormat = new GraphicsFormat[] { GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None, GraphicsFormat.None }; depthOnly = false; } /// /// Configures Input Requirements for this render pass. /// This method should be called inside ScriptableRendererFeature.AddRenderPasses. /// /// ScriptableRenderPassInput containing information about what requirements the pass needs. /// public void ConfigureInput(ScriptableRenderPassInput passInput) { m_Input = passInput; } /// /// Configures the Store Action for a color attachment of this render pass. /// /// RenderBufferStoreAction to use /// Index of the color attachment public void ConfigureColorStoreAction(RenderBufferStoreAction storeAction, uint attachmentIndex = 0) { m_ColorStoreActions[attachmentIndex] = storeAction; m_OverriddenColorStoreActions[attachmentIndex] = true; } /// /// Configures the Store Actions for all the color attachments of this render pass. /// /// Array of RenderBufferStoreActions to use public void ConfigureColorStoreActions(RenderBufferStoreAction[] storeActions) { int count = Math.Min(storeActions.Length, m_ColorStoreActions.Length); for (uint i = 0; i < count; ++i) { m_ColorStoreActions[i] = storeActions[i]; m_OverriddenColorStoreActions[i] = true; } } /// /// Configures the Store Action for the depth attachment of this render pass. /// /// RenderBufferStoreAction to use public void ConfigureDepthStoreAction(RenderBufferStoreAction storeAction) { m_DepthStoreAction = storeAction; m_OverriddenDepthStoreAction = true; } internal void ConfigureInputAttachments(RenderTargetIdentifier input, bool isTransient = false) { m_InputAttachments[0] = input; m_InputAttachmentIsTransient[0] = isTransient; } internal void ConfigureInputAttachments(RenderTargetIdentifier[] inputs) { m_InputAttachments = inputs; } internal void ConfigureInputAttachments(RenderTargetIdentifier[] inputs, bool[] isTransient) { ConfigureInputAttachments(inputs); m_InputAttachmentIsTransient = isTransient; } internal void SetInputAttachmentTransient(int idx, bool isTransient) { m_InputAttachmentIsTransient[idx] = isTransient; } internal bool IsInputAttachmentTransient(int idx) { return m_InputAttachmentIsTransient[idx]; } /// /// Configures render targets for this render pass. Call this instead of CommandBuffer.SetRenderTarget. /// This method should be called inside Configure. /// /// Color attachment identifier. /// Depth attachment identifier. /// public void ConfigureTarget(RenderTargetIdentifier colorAttachment, RenderTargetIdentifier depthAttachment) { m_DepthAttachment = depthAttachment; ConfigureTarget(colorAttachment); } internal void ConfigureTarget(RenderTargetIdentifier colorAttachment, RenderTargetIdentifier depthAttachment, GraphicsFormat format) { m_DepthAttachment = depthAttachment; ConfigureTarget(colorAttachment, format); } /// /// Configures render targets for this render pass. Call this instead of CommandBuffer.SetRenderTarget. /// This method should be called inside Configure. /// /// Color attachment identifier. /// Depth attachment identifier. /// public void ConfigureTarget(RenderTargetIdentifier[] colorAttachments, RenderTargetIdentifier depthAttachment) { overrideCameraTarget = true; uint nonNullColorBuffers = RenderingUtils.GetValidColorBufferCount(colorAttachments); if (nonNullColorBuffers > SystemInfo.supportedRenderTargetCount) Debug.LogError("Trying to set " + nonNullColorBuffers + " renderTargets, which is more than the maximum supported:" + SystemInfo.supportedRenderTargetCount); m_ColorAttachments = colorAttachments; m_DepthAttachment = depthAttachment; } internal void ConfigureTarget(RenderTargetIdentifier[] colorAttachments, RenderTargetIdentifier depthAttachment, GraphicsFormat[] formats) { ConfigureTarget(colorAttachments, depthAttachment); for (int i = 0; i < formats.Length; ++i) renderTargetFormat[i] = formats[i]; } /// /// Configures render targets for this render pass. Call this instead of CommandBuffer.SetRenderTarget. /// This method should be called inside Configure. /// /// Color attachment identifier. /// public void ConfigureTarget(RenderTargetIdentifier colorAttachment) { overrideCameraTarget = true; m_ColorAttachments[0] = colorAttachment; for (int i = 1; i < m_ColorAttachments.Length; ++i) m_ColorAttachments[i] = 0; } internal void ConfigureTarget(RenderTargetIdentifier colorAttachment, GraphicsFormat format, int width = -1, int height = -1, int sampleCount = -1, bool depth = false) { ConfigureTarget(colorAttachment); for (int i = 1; i < m_ColorAttachments.Length; ++i) renderTargetFormat[i] = GraphicsFormat.None; if (depth == true && !GraphicsFormatUtility.IsDepthFormat(format)) { throw new ArgumentException("When configuring a depth only target the passed in format must be a depth format."); } renderTargetWidth = width; renderTargetHeight = height; renderTargetSampleCount = sampleCount; depthOnly = depth; renderTargetFormat[0] = format; } /// /// Configures render targets for this render pass. Call this instead of CommandBuffer.SetRenderTarget. /// This method should be called inside Configure. /// /// Color attachment identifier. /// public void ConfigureTarget(RenderTargetIdentifier[] colorAttachments) { ConfigureTarget(colorAttachments, BuiltinRenderTextureType.CameraTarget); } /// /// Configures clearing for the render targets for this render pass. Call this inside Configure. /// /// ClearFlag containing information about what targets to clear. /// Clear color. /// public void ConfigureClear(ClearFlag clearFlag, Color clearColor) { m_ClearFlag = clearFlag; m_ClearColor = clearColor; } /// /// This method is called by the renderer before rendering a camera /// Override this method if you need to to configure render targets and their clear state, and to create temporary render target textures. /// If a render pass doesn't override this method, this render pass renders to the active Camera's render target. /// You should never call CommandBuffer.SetRenderTarget. Instead call ConfigureTarget and ConfigureClear. /// /// CommandBuffer to enqueue rendering commands. This will be executed by the pipeline. /// Current rendering state information /// /// public virtual void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { } /// /// This method is called by the renderer before executing the render pass. /// Override this method if you need to to configure render targets and their clear state, and to create temporary render target textures. /// If a render pass doesn't override this method, this render pass renders to the active Camera's render target. /// You should never call CommandBuffer.SetRenderTarget. Instead call ConfigureTarget and ConfigureClear. /// /// CommandBuffer to enqueue rendering commands. This will be executed by the pipeline. /// Render texture descriptor of the camera render target. /// /// public virtual void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) { } /// /// Called upon finish rendering a camera. You can use this callback to release any resources created /// by this render /// pass that need to be cleanup once camera has finished rendering. /// This method be called for all cameras in a camera stack. /// /// Use this CommandBuffer to cleanup any generated data public virtual void OnCameraCleanup(CommandBuffer cmd) { } /// /// Called upon finish rendering a camera stack. You can use this callback to release any resources created /// by this render pass that need to be cleanup once all cameras in the stack have finished rendering. /// This method will be called once after rendering the last camera in the camera stack. /// Cameras that don't have an explicit camera stack are also considered stacked rendering. /// In that case the Base camera is the first and last camera in the stack. /// /// Use this CommandBuffer to cleanup any generated data public virtual void OnFinishCameraStackRendering(CommandBuffer cmd) { } /// /// Execute the pass. This is where custom rendering occurs. Specific details are left to the implementation /// /// Use this render context to issue any draw commands during execution /// Current rendering state information public abstract void Execute(ScriptableRenderContext context, ref RenderingData renderingData); /// /// Add a blit command to the context for execution. This changes the active render target in the ScriptableRenderer to /// destination. /// /// Command buffer to record command for execution. /// Source texture or target identifier to blit from. /// Destination texture or target identifier to blit into. This becomes the renderer active render target. /// Material to use. /// Shader pass to use. Default is 0. /// public void Blit(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material = null, int passIndex = 0) { ScriptableRenderer.SetRenderTarget(cmd, destination, BuiltinRenderTextureType.CameraTarget, clearFlag, clearColor); cmd.Blit(source, destination, material, passIndex); } /// /// Add a blit command to the context for execution. This applies the material to the color target. /// /// Command buffer to record command for execution. /// RenderingData to access the active renderer. /// Material to use. /// Shader pass to use. Default is 0. public void Blit(CommandBuffer cmd, ref RenderingData data, Material material, int passIndex = 0) { var renderer = data.cameraData.renderer; Blit(cmd, renderer.cameraColorTarget, renderer.GetCameraColorFrontBuffer(cmd), material, passIndex); renderer.SwapColorBuffer(cmd); } /// /// Creates DrawingSettings based on current the rendering state. /// /// Shader pass tag to render. /// Current rendering state. /// Criteria to sort objects being rendered. /// /// public DrawingSettings CreateDrawingSettings(ShaderTagId shaderTagId, ref RenderingData renderingData, SortingCriteria sortingCriteria) { Camera camera = renderingData.cameraData.camera; SortingSettings sortingSettings = new SortingSettings(camera) { criteria = sortingCriteria }; DrawingSettings settings = new DrawingSettings(shaderTagId, sortingSettings) { perObjectData = renderingData.perObjectData, mainLightIndex = renderingData.lightData.mainLightIndex, enableDynamicBatching = renderingData.supportsDynamicBatching, // Disable instancing for preview cameras. This is consistent with the built-in forward renderer. Also fixes case 1127324. enableInstancing = camera.cameraType == CameraType.Preview ? false : true, }; return settings; } /// /// Creates DrawingSettings based on current rendering state. /// /// /// List of shader pass tag to render. /// Current rendering state. /// Criteria to sort objects being rendered. /// /// public DrawingSettings CreateDrawingSettings(List shaderTagIdList, ref RenderingData renderingData, SortingCriteria sortingCriteria) { if (shaderTagIdList == null || shaderTagIdList.Count == 0) { Debug.LogWarning("ShaderTagId list is invalid. DrawingSettings is created with default pipeline ShaderTagId"); return CreateDrawingSettings(new ShaderTagId("UniversalPipeline"), ref renderingData, sortingCriteria); } DrawingSettings settings = CreateDrawingSettings(shaderTagIdList[0], ref renderingData, sortingCriteria); for (int i = 1; i < shaderTagIdList.Count; ++i) settings.SetShaderPassName(i, shaderTagIdList[i]); return settings; } public static bool operator <(ScriptableRenderPass lhs, ScriptableRenderPass rhs) { return lhs.renderPassEvent < rhs.renderPassEvent; } public static bool operator >(ScriptableRenderPass lhs, ScriptableRenderPass rhs) { return lhs.renderPassEvent > rhs.renderPassEvent; } } }