2025-10-02 22:19:52 +08:00
using UnityEngine ;
using UnityEngine.Experimental.Rendering ;
using UnityEngine.Rendering ;
using UnityEngine.Rendering.Universal ;
using UnityEngine.Rendering.Universal.Internal ;
// This Renderer Feature enqueues either the CopyDepthPass or the DepthOnlyPass depending on the current platform support.
// CopyDepthPass copies the depth texture to an RTHandle. DepthOnlyPass 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 ;
private Material m_CopyDepthMaterial ;
public Material m_DepthEdgeMaterial ;
// The RTHandle for storing the depth texture
private RTHandle m_DepthRTHandle ;
private const string k_DepthRTName = "_MyDepthTexture" ;
// The passes for the effect
private CopyDepthPass m_CopyDepthPass ;
private DepthOnlyPass 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 | | SystemInfo . graphicsDeviceType = = GraphicsDeviceType . OpenGLES2 ;
}
public override void AddRenderPasses ( ScriptableRenderer renderer , ref RenderingData renderingData )
{
var cameraData = renderingData . cameraData ;
if ( renderingData . cameraData . cameraType ! = CameraType . Game )
return ;
if ( CanCopyDepth ( ref cameraData ) )
{
if ( m_CopyDepthMaterial = = null )
m_CopyDepthMaterial = CoreUtils . CreateEngineMaterial ( copyDepthShader ) ;
if ( m_CopyDepthPass = = null )
2025-11-25 10:52:39 +08:00
m_CopyDepthPass = new CopyDepthPass ( evt_Depth , m_CopyDepthMaterial . shader ) ;
2025-10-02 22:19:52 +08:00
renderer . EnqueuePass ( m_CopyDepthPass ) ;
}
else
{
if ( m_DepthOnlyPass = = null )
m_DepthOnlyPass = new DepthOnlyPass ( evt_Depth , RenderQueueRange . opaque , rendererDataAsset . opaqueLayerMask ) ;
renderer . EnqueuePass ( m_DepthOnlyPass ) ;
}
renderer . EnqueuePass ( m_DepthEdgePass ) ;
}
public override void SetupRenderPasses ( ScriptableRenderer renderer , in 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 ;
desc . graphicsFormat = GraphicsFormat . None ;
desc . msaaSamples = 1 ;
RenderingUtils . ReAllocateIfNeeded ( ref m_DepthRTHandle , desc , FilterMode . Bilinear , TextureWrapMode . Clamp , name : k_DepthRTName ) ;
// Setup source and destination RTHandles for the CopyDepthPass
if ( CanCopyDepth ( ref cameraData ) )
m_CopyDepthPass . Setup ( renderer . cameraDepthTargetHandle , m_DepthRTHandle ) ;
else
m_DepthOnlyPass . Setup ( desc , m_DepthRTHandle ) ;
// Pass the RTHandle for the DepthEdge effect
m_DepthEdgePass . SetRTHandle ( ref m_DepthRTHandle , renderer . cameraColorTargetHandle ) ;
}
public override void Create ( )
{
m_DepthEdgePass = new DepthBlitEdgePass ( m_DepthEdgeMaterial , evt_Edge ) ;
}
protected override void Dispose ( bool disposing )
{
m_DepthRTHandle ? . Release ( ) ;
CoreUtils . Destroy ( m_CopyDepthMaterial ) ;
m_DepthEdgePass = null ;
m_CopyDepthPass = null ;
m_DepthOnlyPass = null ;
}
}