using System;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.Universal.Internal
{
///
/// Render all objects that have a 'DepthOnly' pass into the given depth buffer.
///
/// You can use this pass to prime a depth buffer for subsequent rendering.
/// Use it as a z-prepass, or use it to generate a depth buffer.
///
public class DepthOnlyPass : ScriptableRenderPass
{
private static readonly ShaderTagId k_ShaderTagId = new ShaderTagId("DepthOnly");
private RTHandle destination { get; set; }
private GraphicsFormat depthStencilFormat;
internal ShaderTagId shaderTagId { get; set; } = k_ShaderTagId;
private PassData m_PassData;
FilteringSettings m_FilteringSettings;
///
/// Creates a new DepthOnlyPass 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 DepthOnlyPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask)
{
base.profilingSampler = new ProfilingSampler(nameof(DepthOnlyPass));
m_PassData = new PassData();
m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask);
renderPassEvent = evt;
useNativeRenderPass = false;
this.shaderTagId = k_ShaderTagId;
}
///
/// Configures the pass.
///
/// The RenderTextureDescriptor used for the depthStencilFormat.
/// The RTHandle used to render to.
///
///
///
public void Setup(
RenderTextureDescriptor baseDescriptor,
RTHandle depthAttachmentHandle)
{
this.destination = depthAttachmentHandle;
this.depthStencilFormat = baseDescriptor.depthStencilFormat;
}
///
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
// When depth priming is in use the camera target should not be overridden so the Camera's MSAA depth attachment is used.
if (renderingData.cameraData.renderer.useDepthPriming && (renderingData.cameraData.renderType == CameraRenderType.Base || renderingData.cameraData.clearDepth))
{
ConfigureTarget(renderingData.cameraData.renderer.cameraDepthTargetHandle);
// Only clear depth here so we don't clear any bound color target. It might be unused by this pass but that doesn't mean we can just clear it. (e.g. in case of overlay cameras + depth priming)
ConfigureClear(ClearFlag.Depth, Color.black);
}
// When not using depth priming the camera target should be set to our non MSAA depth target.
else
{
useNativeRenderPass = true;
ConfigureTarget(destination);
ConfigureClear(ClearFlag.All, Color.black);
}
}
private static void ExecutePass(ScriptableRenderContext context, PassData passData, ref RenderingData renderingData)
{
var cmd = renderingData.commandBuffer;
var shaderTagId = passData.shaderTagId;
var filteringSettings = passData.filteringSettings;
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.DepthPrepass)))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
var drawSettings = RenderingUtils.CreateDrawingSettings(shaderTagId, ref renderingData, sortFlags);
drawSettings.perObjectData = PerObjectData.None;
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings);
}
}
///
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
m_PassData.shaderTagId = this.shaderTagId;
m_PassData.filteringSettings = m_FilteringSettings;
ExecutePass(context, m_PassData, ref renderingData);
}
private class PassData
{
internal TextureHandle cameraDepthTexture;
internal RenderingData renderingData;
internal ShaderTagId shaderTagId;
internal FilteringSettings filteringSettings;
}
internal void Render(RenderGraph renderGraph, 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("DepthOnly 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);
passData.cameraDepthTexture = builder.UseDepthBuffer(cameraDepthTexture, DepthAccess.Write);
passData.renderingData = renderingData;
passData.shaderTagId = this.shaderTagId;
passData.filteringSettings = m_FilteringSettings;
// 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;
}
}
}
}