136 lines
5.9 KiB
C#
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;
|
|
}
|
|
}
|