using System; using System.Collections.Generic; using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.Universal.Internal { public class DepthNormalOnlyPass : ScriptableRenderPass { internal RenderTextureDescriptor normalDescriptor { get; set; } internal RenderTextureDescriptor depthDescriptor { get; set; } internal bool allocateDepth { get; set; } = true; internal bool allocateNormal { get; set; } = true; internal List shaderTagIds { get; set; } private RenderTargetHandle depthHandle { get; set; } private RenderTargetHandle normalHandle { get; set; } private FilteringSettings m_FilteringSettings; private int m_RendererMSAASamples = 1; // Constants private static readonly List k_DepthNormals = new List { new ShaderTagId("DepthNormals"), new ShaderTagId("DepthNormalsOnly") }; /// /// Create the DepthNormalOnlyPass /// public DepthNormalOnlyPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask) { base.profilingSampler = new ProfilingSampler(nameof(DepthNormalOnlyPass)); m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask); renderPassEvent = evt; useNativeRenderPass = false; } /// /// Configure the pass /// public void Setup(RenderTextureDescriptor baseDescriptor, RenderTargetHandle depthHandle, RenderTargetHandle normalHandle) { // 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. GraphicsFormat normalsFormat; if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R8G8B8A8_SNorm, FormatUsage.Render)) normalsFormat = GraphicsFormat.R8G8B8A8_SNorm; // Preferred format else if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.Render)) normalsFormat = GraphicsFormat.R16G16B16A16_SFloat; // fallback else normalsFormat = GraphicsFormat.R32G32B32A32_SFloat; // fallback this.depthHandle = depthHandle; m_RendererMSAASamples = baseDescriptor.msaaSamples; baseDescriptor.colorFormat = RenderTextureFormat.Depth; baseDescriptor.depthBufferBits = UniversalRenderer.k_DepthStencilBufferBits; // 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. baseDescriptor.msaaSamples = 1;// Depth-Only pass don't use MSAA depthDescriptor = baseDescriptor; this.normalHandle = normalHandle; baseDescriptor.graphicsFormat = normalsFormat; baseDescriptor.depthBufferBits = 0; normalDescriptor = baseDescriptor; this.allocateDepth = true; this.allocateNormal = true; this.shaderTagIds = k_DepthNormals; } /// public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { if (this.allocateNormal) { RenderTextureDescriptor desc = normalDescriptor; desc.msaaSamples = renderingData.cameraData.renderer.useDepthPriming ? m_RendererMSAASamples : 1; cmd.GetTemporaryRT(normalHandle.id, desc, FilterMode.Point); } if (this.allocateDepth) cmd.GetTemporaryRT(depthHandle.id, depthDescriptor, FilterMode.Point); if (renderingData.cameraData.renderer.useDepthPriming && (renderingData.cameraData.renderType == CameraRenderType.Base || renderingData.cameraData.clearDepth)) { ConfigureTarget( new RenderTargetIdentifier(normalHandle.Identifier(), 0, CubemapFace.Unknown, -1), new RenderTargetIdentifier(renderingData.cameraData.renderer.cameraDepthTarget, 0, CubemapFace.Unknown, -1) ); } else { ConfigureTarget( new RenderTargetIdentifier(normalHandle.Identifier(), 0, CubemapFace.Unknown, -1), new RenderTargetIdentifier(depthHandle.Identifier(), 0, CubemapFace.Unknown, -1) ); } ConfigureClear(ClearFlag.All, Color.black); } /// public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { // NOTE: Do NOT mix ProfilingScope with named CommandBuffers i.e. CommandBufferPool.Get("name"). // Currently there's an issue which results in mismatched markers. CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.DepthNormalPrepass))) { context.ExecuteCommandBuffer(cmd); cmd.Clear(); var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags; var drawSettings = CreateDrawingSettings(this.shaderTagIds, ref renderingData, sortFlags); drawSettings.perObjectData = PerObjectData.None; ref CameraData cameraData = ref renderingData.cameraData; Camera camera = cameraData.camera; context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref m_FilteringSettings); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } /// public override void OnCameraCleanup(CommandBuffer cmd) { if (cmd == null) { throw new ArgumentNullException("cmd"); } if (depthHandle != RenderTargetHandle.CameraTarget) { if (this.allocateNormal) cmd.ReleaseTemporaryRT(normalHandle.id); if (this.allocateDepth) cmd.ReleaseTemporaryRT(depthHandle.id); normalHandle = RenderTargetHandle.CameraTarget; depthHandle = RenderTargetHandle.CameraTarget; } } } }