GameTech/URP 渲染实战
源码 / Ch30/FullscreenDebugFeature.cs
Ch30/FullscreenDebugFeature.cs
// 第 30 章的全屏调试 Feature:把相机颜色拷贝一份,再用调试材质(像素校验等)画回去。
// 结构与第 28 章的 ScreenEffectFeature 相同,单独放一份让本章代码自成一体。
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace Cookbook.Ch30
{
    public class FullscreenDebugFeature : ScriptableRendererFeature
    {
        [System.Serializable]
        public class Settings
        {
            public Material material;
            public int passIndex = 0;
            // 校验 HDR 场景颜色:放在后处理之前;想检查最终画面就改成 AfterRenderingPostProcessing
            public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
            public ScriptableRenderPassInput requirements = ScriptableRenderPassInput.None;
        }
        public Settings settings = new Settings();

        FullscreenDebugPass m_Pass;

        public override void Create()
        {
            m_Pass = new FullscreenDebugPass(name);
        }

        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            var camType = renderingData.cameraData.cameraType;
            if (settings.material == null || camType == CameraType.Preview || camType == CameraType.Reflection)
                return;
            m_Pass.renderPassEvent = settings.renderPassEvent;
            m_Pass.ConfigureInput(settings.requirements);
            m_Pass.Setup(settings.material, settings.passIndex);
            renderer.EnqueuePass(m_Pass);
        }

        public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
        {
            // cameraColorTargetHandle 只有在这里(以及之后)才是本帧有效的句柄
            m_Pass.SetTarget(renderer.cameraColorTargetHandle);
        }

        protected override void Dispose(bool disposing)
        {
            m_Pass?.Dispose();
        }

        class FullscreenDebugPass : ScriptableRenderPass
        {
            Material m_Material;
            int m_PassIndex;
            RTHandle m_CameraColor;
            RTHandle m_Copy;

            public FullscreenDebugPass(string name)
            {
                profilingSampler = new ProfilingSampler(name);
            }

            public void Setup(Material material, int passIndex) { m_Material = material; m_PassIndex = passIndex; }
            public void SetTarget(RTHandle cameraColor) { m_CameraColor = cameraColor; }

            public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
            {
                // 临时 RT 与相机目标同尺寸、同格式,但不要 MSAA、不要深度
                var desc = renderingData.cameraData.cameraTargetDescriptor;
                desc.msaaSamples = 1;
                desc.depthBufferBits = 0;
                RenderingUtils.ReAllocateIfNeeded(ref m_Copy, desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_FullscreenDebugCopy");
                ConfigureTarget(m_CameraColor);
            }

            public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
            {
                var cmd = CommandBufferPool.Get();
                using (new ProfilingScope(cmd, profilingSampler))
                {
                    // 不能边读边写同一张 RT:先拷贝,再以拷贝为 _BlitTexture 画回去
                    Blitter.BlitCameraTexture(cmd, m_CameraColor, m_Copy);
                    Blitter.BlitCameraTexture(cmd, m_Copy, m_CameraColor, m_Material, m_PassIndex);
                }
                context.ExecuteCommandBuffer(cmd);
                CommandBufferPool.Release(cmd);
            }

            public void Dispose() { m_Copy?.Release(); }
        }
    }
}