unity/Assets/PostProcessingV2/Runtime/PostProcessDebugLayer.cs (191 lines of code) (raw):

using System; using System.Collections.Generic; namespace UnityEngine.Rendering.PostProcessing { public enum DebugOverlay { None, Depth, Normals, MotionVectors, NANTracker, ColorBlindnessSimulation, _, AmbientOcclusion, BloomBuffer, BloomThreshold, DepthOfField } public enum ColorBlindnessType { Deuteranopia, Protanopia, Tritanopia } [Serializable] public sealed class PostProcessDebugLayer { // Monitors public LightMeterMonitor lightMeter; public HistogramMonitor histogram; public WaveformMonitor waveform; public VectorscopeMonitor vectorscope; Dictionary<MonitorType, Monitor> m_Monitors; // Current frame size int frameWidth; int frameHeight; public RenderTexture debugOverlayTarget { get; private set; } // Set to true if the frame that was just drawn as a debug overlay enabled and rendered public bool debugOverlayActive { get; private set; } // This is reset to None after rendering of post-processing has finished public DebugOverlay debugOverlay { get; private set; } // Overlay settings in a separate class to keep things separated [Serializable] public class OverlaySettings { [Range(0f, 16f)] public float motionColorIntensity = 4f; [Range(4, 128)] public int motionGridSize = 64; public ColorBlindnessType colorBlindnessType = ColorBlindnessType.Deuteranopia; [Range(0f, 1f)] public float colorBlindnessStrength = 1f; } public OverlaySettings overlaySettings; internal void OnEnable() { RuntimeUtilities.CreateIfNull(ref lightMeter); RuntimeUtilities.CreateIfNull(ref histogram); RuntimeUtilities.CreateIfNull(ref waveform); RuntimeUtilities.CreateIfNull(ref vectorscope); RuntimeUtilities.CreateIfNull(ref overlaySettings); m_Monitors = new Dictionary<MonitorType, Monitor> { { MonitorType.LightMeter, lightMeter }, { MonitorType.Histogram, histogram }, { MonitorType.Waveform, waveform }, { MonitorType.Vectorscope, vectorscope } }; foreach (var kvp in m_Monitors) kvp.Value.OnEnable(); } internal void OnDisable() { foreach (var kvp in m_Monitors) kvp.Value.OnDisable(); DestroyDebugOverlayTarget(); } void DestroyDebugOverlayTarget() { RuntimeUtilities.Destroy(debugOverlayTarget); debugOverlayTarget = null; } // Per-frame requests public void RequestMonitorPass(MonitorType monitor) { m_Monitors[monitor].requested = true; } public void RequestDebugOverlay(DebugOverlay mode) { debugOverlay = mode; } // Sets the current frame size - used to make sure the debug overlay target is always the // correct size - mostly useful in the editor as the user can easily resize the gameview. internal void SetFrameSize(int width, int height) { frameWidth = width; frameHeight = height; debugOverlayActive = false; } // Blits to the debug target and mark this frame as using a debug overlay public void PushDebugOverlay(CommandBuffer cmd, RenderTargetIdentifier source, PropertySheet sheet, int pass) { if (debugOverlayTarget == null || !debugOverlayTarget.IsCreated() || debugOverlayTarget.width != frameWidth || debugOverlayTarget.height != frameHeight) { RuntimeUtilities.Destroy(debugOverlayTarget); debugOverlayTarget = new RenderTexture(frameWidth, frameHeight, 0, RenderTextureFormat.ARGB32) { name = "Debug Overlay Target", anisoLevel = 1, filterMode = FilterMode.Bilinear, wrapMode = TextureWrapMode.Clamp, hideFlags = HideFlags.HideAndDontSave }; debugOverlayTarget.Create(); } cmd.BlitFullscreenTriangle(source, debugOverlayTarget, sheet, pass); debugOverlayActive = true; } internal DepthTextureMode GetCameraFlags() { if (debugOverlay == DebugOverlay.Depth) return DepthTextureMode.Depth; if (debugOverlay == DebugOverlay.Normals) return DepthTextureMode.DepthNormals; if (debugOverlay == DebugOverlay.MotionVectors) return DepthTextureMode.MotionVectors | DepthTextureMode.Depth; return DepthTextureMode.None; } internal void RenderMonitors(PostProcessRenderContext context) { // Monitors bool anyActive = false; bool needsHalfRes = false; foreach (var kvp in m_Monitors) { bool active = kvp.Value.IsRequestedAndSupported(); anyActive |= active; needsHalfRes |= active && kvp.Value.NeedsHalfRes(); } if (!anyActive) return; var cmd = context.command; cmd.BeginSample("Monitors"); if (needsHalfRes) { cmd.GetTemporaryRT(ShaderIDs.HalfResFinalCopy, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, context.sourceFormat); cmd.Blit(context.destination, ShaderIDs.HalfResFinalCopy); } foreach (var kvp in m_Monitors) { var monitor = kvp.Value; if (monitor.requested) monitor.Render(context); } if (needsHalfRes) cmd.ReleaseTemporaryRT(ShaderIDs.HalfResFinalCopy); cmd.EndSample("Monitors"); } internal void RenderSpecialOverlays(PostProcessRenderContext context) { if (debugOverlay == DebugOverlay.Depth) { var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays); PushDebugOverlay(context.command, BuiltinRenderTextureType.None, sheet, 0); } else if (debugOverlay == DebugOverlay.Normals) { var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays); sheet.ClearKeywords(); if (context.camera.actualRenderingPath == RenderingPath.DeferredLighting) sheet.EnableKeyword("SOURCE_GBUFFER"); PushDebugOverlay(context.command, BuiltinRenderTextureType.None, sheet, 1); } else if (debugOverlay == DebugOverlay.MotionVectors) { var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays); sheet.properties.SetVector(ShaderIDs.Params, new Vector4(overlaySettings.motionColorIntensity, overlaySettings.motionGridSize, 0f, 0f)); PushDebugOverlay(context.command, context.source, sheet, 2); } else if (debugOverlay == DebugOverlay.NANTracker) { var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays); PushDebugOverlay(context.command, context.source, sheet, 3); } else if (debugOverlay == DebugOverlay.ColorBlindnessSimulation) { var sheet = context.propertySheets.Get(context.resources.shaders.debugOverlays); sheet.properties.SetVector(ShaderIDs.Params, new Vector4(overlaySettings.colorBlindnessStrength, 0f, 0f, 0f)); PushDebugOverlay(context.command, context.source, sheet, 4 + (int)overlaySettings.colorBlindnessType); } } internal void EndFrame() { foreach (var kvp in m_Monitors) kvp.Value.requested = false; if (!debugOverlayActive) DestroyDebugOverlayTarget(); debugOverlay = DebugOverlay.None; } } }