using System; using System.Collections.Generic; using UnityEngine.Experimental.Rendering; using UnityEngine.Experimental.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal.Internal { /// /// Render all objects that have a 'DepthNormals' and/or 'DepthNormalsOnly' pass into the given depth and normal buffers. /// public class DepthNormalOnlyPass : ScriptableRenderPass { internal List shaderTagIds { get; set; } private RTHandle depthHandle { get; set; } private RTHandle normalHandle { get; set; } private RTHandle renderingLayersHandle { get; set; } internal bool enableRenderingLayers { get; set; } = false; private FilteringSettings m_FilteringSettings; private PassData m_PassData; // Constants private static readonly List k_DepthNormals = new List { new ShaderTagId("DepthNormals"), new ShaderTagId("DepthNormalsOnly") }; private static readonly RTHandle[] k_ColorAttachment1 = new RTHandle[1]; private static readonly RTHandle[] k_ColorAttachment2 = new RTHandle[2]; /// /// Creates a new DepthNormalOnlyPass instance. /// /// The RenderPassEvent to use. /// The RenderQueueRange to use for creating filtering settings that control what objects get rendered. /// The layer mask to use for creating filtering settings that control what objects get rendered. /// /// /// public DepthNormalOnlyPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask) { base.profilingSampler = new ProfilingSampler(nameof(DepthNormalOnlyPass)); m_PassData = new PassData(); m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask); renderPassEvent = evt; useNativeRenderPass = false; this.shaderTagIds = k_DepthNormals; } /// /// Finds the format to use for the normals texture. /// /// The GraphicsFormat to use with the Normals texture. public static GraphicsFormat GetGraphicsFormat() { if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R8G8B8A8_SNorm, FormatUsage.Render)) return GraphicsFormat.R8G8B8A8_SNorm; // Preferred format else if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.Render)) return GraphicsFormat.R16G16B16A16_SFloat; // fallback else return GraphicsFormat.R32G32B32A32_SFloat; // fallback } /// /// Configures the pass. /// /// The RTHandle used to render depth to. /// The RTHandle used to render normals. /// public void Setup(RTHandle depthHandle, RTHandle normalHandle) { this.depthHandle = depthHandle; this.normalHandle = normalHandle; this.enableRenderingLayers = false; } /// /// Configures the pass. /// /// The RTHandle used to render depth to. /// The RTHandle used to render normals. /// The RTHandle used to render decals. /// public void Setup(RTHandle depthHandle, RTHandle normalHandle, RTHandle decalLayerHandle) { Setup(depthHandle, normalHandle); this.renderingLayersHandle = decalLayerHandle; this.enableRenderingLayers = true; } /// public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { RTHandle[] colorHandles; if (this.enableRenderingLayers) { k_ColorAttachment2[0] = normalHandle; k_ColorAttachment2[1] = renderingLayersHandle; colorHandles = k_ColorAttachment2; } else { k_ColorAttachment1[0] = normalHandle; colorHandles = k_ColorAttachment1; } if (renderingData.cameraData.renderer.useDepthPriming && (renderingData.cameraData.renderType == CameraRenderType.Base || renderingData.cameraData.clearDepth)) ConfigureTarget(colorHandles, renderingData.cameraData.renderer.cameraDepthTargetHandle); else ConfigureTarget(colorHandles, depthHandle); ConfigureClear(ClearFlag.All, Color.black); } private static void ExecutePass(ScriptableRenderContext context, PassData passData, ref RenderingData renderingData) { var cmd = renderingData.commandBuffer; var shaderTagIds = passData.shaderTagIds; var filteringSettings = passData.filteringSettings; using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.DepthNormalPrepass))) { context.ExecuteCommandBuffer(cmd); cmd.Clear(); // Enable Rendering Layers if (passData.enableRenderingLayers) { CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.WriteRenderingLayers, true); context.ExecuteCommandBuffer(cmd); cmd.Clear(); } // Draw var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags; var drawSettings = RenderingUtils.CreateDrawingSettings(shaderTagIds, ref renderingData, sortFlags); drawSettings.perObjectData = PerObjectData.None; context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings); // Clean up if (passData.enableRenderingLayers) { CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.WriteRenderingLayers, false); context.ExecuteCommandBuffer(cmd); cmd.Clear(); } } } /// public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { m_PassData.shaderTagIds = this.shaderTagIds; m_PassData.filteringSettings = m_FilteringSettings; m_PassData.enableRenderingLayers = enableRenderingLayers; ExecutePass(context, m_PassData, ref renderingData); } /// public override void OnCameraCleanup(CommandBuffer cmd) { if (cmd == null) { throw new ArgumentNullException("cmd"); } normalHandle = null; depthHandle = null; renderingLayersHandle = null; } private class PassData { internal TextureHandle cameraDepthTexture; internal TextureHandle cameraNormalsTexture; internal RenderingData renderingData; internal List shaderTagIds; internal FilteringSettings filteringSettings; internal bool enableRenderingLayers; } internal void Render(RenderGraph renderGraph, out TextureHandle cameraNormalsTexture, out TextureHandle cameraDepthTexture, ref RenderingData renderingData) { const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D32_SFloat_S8_UInt; const int k_DepthBufferBits = 32; using (var builder = renderGraph.AddRenderPass("DepthNormals Prepass", out var passData, base.profilingSampler)) { var depthDescriptor = renderingData.cameraData.cameraTargetDescriptor; depthDescriptor.graphicsFormat = GraphicsFormat.None; depthDescriptor.depthStencilFormat = k_DepthStencilFormat; depthDescriptor.depthBufferBits = k_DepthBufferBits; depthDescriptor.msaaSamples = 1;// Depth-Only pass don't use MSAA cameraDepthTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDescriptor, "_CameraDepthTexture", true); // TODO RENDERGRAPH: Handle Deferred case, see _CameraNormalsTexture logic in UniversalRenderer.cs var normalDescriptor = renderingData.cameraData.cameraTargetDescriptor; normalDescriptor.depthBufferBits = 0; // Never have MSAA on this depth texture. When doing MSAA depth priming this is the texture that is resolved to and used for post-processing. normalDescriptor.msaaSamples = 1;// Depth-Only pass don't use MSAA // Find compatible render-target format for storing normals. // Shader code outputs normals in signed format to be compatible with deferred gbuffer layout. // Deferred gbuffer format is signed so that normals can be blended for terrain geometry. // TODO: deferred normalDescriptor.graphicsFormat = GetGraphicsFormat(); cameraNormalsTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, normalDescriptor, "_CameraNormalsTexture", true); passData.cameraNormalsTexture = builder.UseColorBuffer(cameraNormalsTexture, 0); passData.cameraDepthTexture = builder.UseDepthBuffer(cameraDepthTexture, DepthAccess.Write); passData.renderingData = renderingData; passData.shaderTagIds = this.shaderTagIds; passData.filteringSettings = m_FilteringSettings; passData.enableRenderingLayers = enableRenderingLayers; // TODO RENDERGRAPH: culling? force culling off for testing builder.AllowPassCulling(false); builder.SetRenderFunc((PassData data, RenderGraphContext context) => { ExecutePass(context.renderContext, data, ref data.renderingData); }); return; } } } }