VR4Medical/ICI/Library/PackageCache/com.unity.render-pipelines.universal@2b88762731f8/Samples~/URPPackageSamples/RendererFeatures/DepthBlit/DepthBlitFeature.cs
2025-07-29 13:45:50 +03:00

136 lines
5.9 KiB
C#

using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
// Create a Scriptable Renderer Feature that either copies the depth texture to a render texture (RTHandle), or renders depth values to a render texture.
// The Scriptable Renderer Feature then outputs the render texture to the screen, using a material that renders an edge effect.
// For more information about creating scriptable renderer features, refer to https://docs.unity3d.com/Manual/urp/customizing-urp.html
public class DepthBlitFeature : ScriptableRendererFeature
{
// Set the injection points for the render passes
public RenderPassEvent evt_Depth = RenderPassEvent.AfterRenderingOpaques;
public RenderPassEvent evt_Edge = RenderPassEvent.AfterRenderingOpaques;
// Create a property for a Universal Renderer asset that sets the opaque layers to draw.
public UniversalRendererData rendererDataAsset;
// Create a property for the shader that copies the depth texture.
public Shader copyDepthShader;
// Create a property for the material that renders the edge effect.
public Material m_DepthEdgeMaterial;
// Set the properties of the destination depth texture.
private const string k_DepthRTName = "_MyDepthTexture";
private FilterMode m_DepthRTFilterMode = FilterMode.Bilinear;
private TextureWrapMode m_DepthRTWrapMode = TextureWrapMode.Clamp;
// Create a class that keeps the reference to the depth texture in the frame data, so multiple passes in the render graph system can share the texture.
public class TexRefData : ContextItem
{
public TextureHandle depthTextureHandle = TextureHandle.nullHandle;
public override void Reset()
{
depthTextureHandle = TextureHandle.nullHandle;
}
}
// Declare the render passes.
// The script uses DepthOnlyPass for platforms that run OpenGL ES, which doesn't support copying from a depth texture.
private DepthBlitCopyDepthPass m_CopyDepthPass;
private DepthBlitDepthOnlyPass m_DepthOnlyPass;
private DepthBlitEdgePass m_DepthEdgePass;
// Check if the platform supports copying from a depth texture.
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 platforms to avoid invalid results
if (IsGLESDevice() && msaaDepthResolve)
return false;
return supportsDepthCopy || msaaDepthResolve;
}
private bool IsGLESDevice()
{
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3;
}
// Override the AddRenderPasses method to inject passes into the renderer. Unity calls AddRenderPasses once per camera.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// Skip rendering if the camera is not a game camera.
var cameraData = renderingData.cameraData;
if (renderingData.cameraData.cameraType != CameraType.Game)
return;
// Set up a RenderTextureDescriptor with the properties of the depth texture.
var desc = renderingData.cameraData.cameraTargetDescriptor;
if (CanCopyDepth(ref cameraData))
{
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
}
else
{
desc.graphicsFormat = GraphicsFormat.None;
desc.msaaSamples = 1;
}
// Create the DepthBlitCopyDepthPass or DepthBlitDepthOnlyPass render pass, and inject it into the renderer.
RTHandle depthRTHandle;
if (CanCopyDepth(ref cameraData))
{
if (m_CopyDepthPass == null)
// Create a new instance of a render pass that copies the depth texture to the new render texture.
// This render pass is a simplified version of CopyDepthPass in URP.
m_CopyDepthPass = new DepthBlitCopyDepthPass(evt_Depth, copyDepthShader,
desc, m_DepthRTFilterMode, m_DepthRTWrapMode, name: k_DepthRTName);
renderer.EnqueuePass(m_CopyDepthPass);
depthRTHandle = m_CopyDepthPass.depthRT;
}
else
{
if (m_DepthOnlyPass == null)
// Create a new instance of a render pass that renders depth values to the new render texture.
// This render pass is a simplified version of DepthOnlyPass in URP.
m_DepthOnlyPass = new DepthBlitDepthOnlyPass(evt_Depth, RenderQueueRange.opaque, rendererDataAsset.opaqueLayerMask,
desc, m_DepthRTFilterMode, m_DepthRTWrapMode, name: k_DepthRTName);
renderer.EnqueuePass(m_DepthOnlyPass);
depthRTHandle = m_DepthOnlyPass.depthRT;
}
// Pass the render texture to the edge effect render pass, and inject the render pass into the renderer.
m_DepthEdgePass.SetRTHandle(ref depthRTHandle);
renderer.EnqueuePass(m_DepthEdgePass);
}
public override void Create()
{
// Create a new instance of the render pass that renders the edge effect.
m_DepthEdgePass = new DepthBlitEdgePass(m_DepthEdgeMaterial, evt_Edge);
}
// Free the resources the render passes use.
protected override void Dispose(bool disposing)
{
m_CopyDepthPass?.Dispose();
m_DepthOnlyPass?.Dispose();
m_DepthEdgePass = null;
m_CopyDepthPass = null;
m_DepthOnlyPass = null;
}
}