using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using Unity.Collections; using UnityEngine.Scripting.APIUpdating; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal { /// /// Input requirements for ScriptableRenderPass. /// /// URP adds render passes to generate the inputs, or reuses inputs that are already available from earlier in the frame. /// /// URP binds the inputs as global shader texture properties. /// /// [Flags] public enum ScriptableRenderPassInput { /// /// Used when a ScriptableRenderPass does not require any texture. /// None = 0, /// /// Used when a ScriptableRenderPass requires a depth texture. /// /// To sample the depth texture in a shader, include `Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl`, then use the `SampleSceneDepth` method. /// Depth = 1 << 0, /// /// Used when a ScriptableRenderPass requires a normal texture. /// /// To sample the normals texture in a shader, include `Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl`, then use the `SampleSceneNormals` method. /// Normal = 1 << 1, /// /// Used when a ScriptableRenderPass requires a color texture. /// /// To sample the color texture in a shader, include `Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl`, then use the `SampleSceneColor` method. /// /// **Note:** The opaque texture might be a downscaled copy of the framebuffer from before rendering transparent objects. /// Color = 1 << 2, /// /// Used when a ScriptableRenderPass requires a motion vectors texture. /// /// To sample the motion vectors texture in a shader, use `TEXTURE2D_X(_MotionVectorTexture)`, then `LOAD_TEXTURE2D_X_LOD(_MotionVectorTexture, pixelCoords, 0).xy`. /// 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, /// /// 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, } /// /// Framebuffer fetch events in Universal RP /// internal enum FramebufferFetchEvent { None = 0, FetchGbufferInDeferred = 1 } internal static class RenderPassEventsEnumValues { // we cache the values in this array at construction time to avoid runtime allocations, which we would cause if we accessed valuesInternal directly public static int[] values; static RenderPassEventsEnumValues() { System.Array valuesInternal = Enum.GetValues(typeof(RenderPassEvent)); values = new int[valuesInternal.Length]; int index = 0; foreach (int value in valuesInternal) { values[index] = value; index++; } } } /// /// ScriptableRenderPass implements a logical rendering pass that can be used to extend Universal RP renderer. /// /// /// To implement your own rendering pass you need to take the following steps: /// 1. Create a new Subclass from ScriptableRenderPass that implements the rendering logic. /// 2. Create an instance of your subclass and set up the relevant parameters such as ScriptableRenderPass.renderPassEvent in the constructor or initialization code. /// 3. Ensure your pass instance gets picked up by URP, this can be done through a ScriptableRendererFeature or by calling ScriptableRenderer.EnqueuePass from an event callback like RenderPipelineManager.beginCameraRendering /// /// See [link] for more info on working with a ScriptableRendererFeature or [link] for more info on working with ScriptableRenderer.EnqueuePass. /// public abstract partial class ScriptableRenderPass : IRenderGraphRecorder { /// /// The event when the render pass executes. /// public RenderPassEvent renderPassEvent { get; set; } /// /// The input requirements for the ScriptableRenderPass, which has been set using ConfigureInput /// /// public ScriptableRenderPassInput input => m_Input; /// /// Setting this property to true forces rendering of all passes in the URP frame via an intermediate texture. Use this option for passes that do not support rendering directly to the backbuffer or that require sampling the active color target. Using this option might have a significant performance impact on untethered VR platforms. /// public bool requiresIntermediateTexture { get; set; } private ProfilingSampler m_ProfingSampler; private string m_PassName; /// /// A ProfilingSampler for the entire render pass. Used as a profiling name by ScriptableRenderer when executing the pass. /// The default is named as the class type of the sub-class. /// Set base.profilingSampler from the sub-class constructor to set a different profiling name for a custom ScriptableRenderPass /// This returns null in release build (non-development).. /// protected internal ProfilingSampler profilingSampler { get { #if (DEVELOPMENT_BUILD || UNITY_EDITOR) return m_ProfingSampler; #else return null; #endif } set { m_ProfingSampler = value; m_PassName = (value != null) ? value.name : this.GetType().Name; } } /// /// The name of the pass that will show up in profiler and other tools. This will be indentical to the /// name of profilingSampler. profilingSampler is set to null in the release build (non-development) /// so this passName property is the safe way to access the name and use it consistently. This will always return a valid string. /// protected internal string passName{ get { return m_PassName; } } internal bool isBlitRenderPass { 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; } ScriptableRenderPassInput m_Input = ScriptableRenderPassInput.None; static internal DebugHandler GetActiveDebugHandler(UniversalCameraData cameraData) { var debugHandler = cameraData.renderer.DebugHandler; if ((debugHandler != null) && debugHandler.IsActiveForCamera(cameraData.isPreviewCamera)) return debugHandler; return null; } /// /// Creates a new ScriptableRenderPass" instance. /// public ScriptableRenderPass() { renderPassEvent = RenderPassEvent.AfterRenderingOpaques; profilingSampler = new ProfilingSampler(this.GetType().Name); } /// /// 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; } /// /// 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 should be called for all cameras in a camera stack. /// /// Use this CommandBuffer to cleanup any generated data public virtual void OnCameraCleanup(CommandBuffer cmd) { } /// public virtual void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { Debug.LogWarning("The render pass " + this.ToString() + " does not have an implementation of the RecordRenderGraph method. Please implement this method, or consider turning on Compatibility Mode (RenderGraph disabled) in the menu Edit > Project Settings > Graphics > URP. Otherwise the render pass will have no effect. For more information, refer to https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest/index.html?subfolder=/manual/customizing-urp.html."); } /// /// Creates DrawingSettings based on current the rendering state. /// /// Shader pass tag to render. /// Current rendering state. /// Criteria to sort objects being rendered. /// Returns the draw settings created. /// public DrawingSettings CreateDrawingSettings(ShaderTagId shaderTagId, ref RenderingData renderingData, SortingCriteria sortingCriteria) { ContextContainer frameData = renderingData.frameData; UniversalRenderingData universalRenderingData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); UniversalLightData lightData = frameData.Get(); return RenderingUtils.CreateDrawingSettings(shaderTagId, universalRenderingData, cameraData, lightData, sortingCriteria); } /// /// Creates DrawingSettings based on current the rendering state. /// /// Shader pass tag to render. /// Current rendering state. /// Current camera state. /// Current light state. /// Criteria to sort objects being rendered. /// Returns the draw settings created. /// public DrawingSettings CreateDrawingSettings(ShaderTagId shaderTagId, UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData, SortingCriteria sortingCriteria) { return RenderingUtils.CreateDrawingSettings(shaderTagId, renderingData, cameraData, lightData, sortingCriteria); } /// /// Creates DrawingSettings based on current rendering state. /// /// List of shader pass tag to render. /// Current rendering state. /// Criteria to sort objects being rendered. /// Returns the draw settings created. /// public DrawingSettings CreateDrawingSettings(List shaderTagIdList, ref RenderingData renderingData, SortingCriteria sortingCriteria) { ContextContainer frameData = renderingData.frameData; UniversalRenderingData universalRenderingData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); UniversalLightData lightData = frameData.Get(); return RenderingUtils.CreateDrawingSettings(shaderTagIdList, universalRenderingData, cameraData, lightData, sortingCriteria); } /// /// Creates DrawingSettings based on current rendering state. /// /// List of shader pass tag to render. /// Current rendering state. /// Current camera state. /// Current light state. /// Criteria to sort objects being rendered. /// Returns the draw settings created. /// public DrawingSettings CreateDrawingSettings(List shaderTagIdList, UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData, SortingCriteria sortingCriteria) { return RenderingUtils.CreateDrawingSettings(shaderTagIdList, renderingData, cameraData, lightData, sortingCriteria); } /// /// Compares two instances of ScriptableRenderPass by their RenderPassEvent and returns if is executed before . /// /// /// /// public static bool operator <(ScriptableRenderPass lhs, ScriptableRenderPass rhs) { return lhs.renderPassEvent < rhs.renderPassEvent; } /// /// Compares two instances of ScriptableRenderPass by their RenderPassEvent and returns if is executed after . /// /// /// /// public static bool operator >(ScriptableRenderPass lhs, ScriptableRenderPass rhs) { return lhs.renderPassEvent > rhs.renderPassEvent; } internal static int GetRenderPassEventRange(RenderPassEvent renderPassEvent) { int numEvents = RenderPassEventsEnumValues.values.Length; int currentIndex = 0; // find the index of the renderPassEvent in the values array for(int i = 0; i < numEvents; ++i) { if (RenderPassEventsEnumValues.values[currentIndex] == (int)renderPassEvent) break; currentIndex++; } if (currentIndex >= numEvents) { Debug.LogError("GetRenderPassEventRange: invalid renderPassEvent value cannot be found in the RenderPassEvent enumeration"); return 0; } if (currentIndex + 1 >= numEvents) return 50; // if this was the last event in the enum, then add 50 as the range int nextValue = RenderPassEventsEnumValues.values[currentIndex + 1]; return nextValue - (int) renderPassEvent; } } }