118 lines
4.6 KiB
C#
118 lines
4.6 KiB
C#
|
using UnityEngine;
|
||
|
using UnityEngine.Experimental.Rendering;
|
||
|
using UnityEngine.Rendering;
|
||
|
using UnityEngine.Rendering.RenderGraphModule;
|
||
|
using UnityEngine.Rendering.Universal;
|
||
|
|
||
|
// This Renderer Feature enqueues either the DepthBlitCopyDepthPass or the DepthBlitDepthOnlyPass depending on the current platform support.
|
||
|
// DepthBlitCopyPass is a simplified version of URP CopyDepthPass. The pass copies the depth texture to an RTHandle.
|
||
|
// DepthBlitDepthOnlyPass is a simplified version of the URP DepthOnlyPass. The pass renders depth values to an RTHandle.
|
||
|
// The Renderer Feature also enqueues the DepthBlitEdgePass which takes the RTHandle as input to create an effect to visualize depth, and output it to the screen.
|
||
|
public class DepthBlitFeature : ScriptableRendererFeature
|
||
|
{
|
||
|
public RenderPassEvent evt_Depth = RenderPassEvent.AfterRenderingOpaques;
|
||
|
public RenderPassEvent evt_Edge = RenderPassEvent.AfterRenderingOpaques;
|
||
|
public UniversalRendererData rendererDataAsset; // The field for accessing opaqueLayerMask on the renderer asset
|
||
|
|
||
|
public Shader copyDepthShader;
|
||
|
|
||
|
public Material m_DepthEdgeMaterial;
|
||
|
|
||
|
// The RTHandle for storing the depth texture
|
||
|
private RTHandle m_DepthRTHandle;
|
||
|
private const string k_DepthRTName = "_MyDepthTexture";
|
||
|
|
||
|
// This class is for keeping the TextureHandle reference in the frame data so that it can be shared with multiple passes in the render graph system.
|
||
|
public class TexRefData : ContextItem
|
||
|
{
|
||
|
public TextureHandle depthTextureHandle = TextureHandle.nullHandle;
|
||
|
|
||
|
public override void Reset()
|
||
|
{
|
||
|
depthTextureHandle = TextureHandle.nullHandle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The passes for the effect
|
||
|
private DepthBlitCopyDepthPass m_CopyDepthPass;
|
||
|
private DepthBlitDepthOnlyPass m_DepthOnlyPass; // DepthOnlyPass is for platforms that run OpenGL ES, which does not support CopyDepth.
|
||
|
private DepthBlitEdgePass m_DepthEdgePass;
|
||
|
|
||
|
// Check if the platform supports CopyDepthPass
|
||
|
private bool CanCopyDepth(ref CameraData cameraData)
|
||
|
{
|
||
|
bool msaaEnabledForCamera = cameraData.cameraTargetDescriptor.msaaSamples > 1;
|
||
|
bool supportsTextureCopy = SystemInfo.copyTextureSupport != CopyTextureSupport.None;
|
||
|
bool supportsDepthTarget = RenderingUtils.SupportsRenderTextureFormat(RenderTextureFormat.Depth);
|
||
|
bool supportsDepthCopy = !msaaEnabledForCamera && (supportsDepthTarget || supportsTextureCopy);
|
||
|
|
||
|
bool msaaDepthResolve = msaaEnabledForCamera && SystemInfo.supportsMultisampledTextures != 0;
|
||
|
|
||
|
// Avoid copying MSAA depth on GLES3 platform to avoid invalid results
|
||
|
if (IsGLESDevice() && msaaDepthResolve)
|
||
|
return false;
|
||
|
|
||
|
return supportsDepthCopy || msaaDepthResolve;
|
||
|
}
|
||
|
|
||
|
private bool IsGLESDevice()
|
||
|
{
|
||
|
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3;
|
||
|
}
|
||
|
|
||
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||
|
{
|
||
|
var cameraData = renderingData.cameraData;
|
||
|
if (renderingData.cameraData.cameraType != CameraType.Game)
|
||
|
return;
|
||
|
|
||
|
// Create an RTHandle for storing the depth
|
||
|
var desc = renderingData.cameraData.cameraTargetDescriptor;
|
||
|
if (CanCopyDepth(ref cameraData))
|
||
|
{
|
||
|
desc.depthBufferBits = 0;
|
||
|
desc.msaaSamples = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
desc.graphicsFormat = GraphicsFormat.None;
|
||
|
desc.msaaSamples = 1;
|
||
|
}
|
||
|
RenderingUtils.ReAllocateHandleIfNeeded(ref m_DepthRTHandle, desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: k_DepthRTName );
|
||
|
|
||
|
// Setup passes
|
||
|
if (CanCopyDepth(ref cameraData))
|
||
|
{
|
||
|
if (m_CopyDepthPass == null)
|
||
|
m_CopyDepthPass = new DepthBlitCopyDepthPass(evt_Depth, copyDepthShader, m_DepthRTHandle);
|
||
|
|
||
|
renderer.EnqueuePass(m_CopyDepthPass);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (m_DepthOnlyPass == null)
|
||
|
m_DepthOnlyPass = new DepthBlitDepthOnlyPass(evt_Depth, RenderQueueRange.opaque, rendererDataAsset.opaqueLayerMask, m_DepthRTHandle);
|
||
|
|
||
|
renderer.EnqueuePass(m_DepthOnlyPass);
|
||
|
}
|
||
|
|
||
|
// Pass the RTHandle for the DepthEdge effect
|
||
|
m_DepthEdgePass.SetRTHandle(ref m_DepthRTHandle);
|
||
|
renderer.EnqueuePass(m_DepthEdgePass);
|
||
|
}
|
||
|
|
||
|
public override void Create()
|
||
|
{
|
||
|
m_DepthEdgePass = new DepthBlitEdgePass(m_DepthEdgeMaterial, evt_Edge);
|
||
|
}
|
||
|
|
||
|
protected override void Dispose(bool disposing)
|
||
|
{
|
||
|
m_CopyDepthPass?.Dispose();
|
||
|
m_DepthRTHandle?.Release();
|
||
|
m_DepthEdgePass = null;
|
||
|
m_CopyDepthPass = null;
|
||
|
m_DepthOnlyPass = null;
|
||
|
}
|
||
|
}
|