using System; using System.Drawing.Drawing2D; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.Universal; namespace UVC.Rendering { public class EdgeDetection : ScriptableRendererFeature { private class EdgeDetectionPass : ScriptableRenderPass { private Material material; private static readonly int OutlineThicknessProperty = Shader.PropertyToID("_OutlineThickness"); private static readonly int OutlineColorProperty = Shader.PropertyToID("_OutlineColor"); public EdgeDetectionPass() { profilingSampler = new ProfilingSampler(nameof(EdgeDetectionPass)); } public void Setup(ref EdgeDetectionSettings settings, ref Material edgeDetectionMaterial) { material = edgeDetectionMaterial; renderPassEvent = settings.renderPassEvent; material.SetFloat(OutlineThicknessProperty, settings.outlineThickness); material.SetColor(OutlineColorProperty, settings.outlineColor); } private class PassData { } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { var resourceData = frameData.Get(); using var builder = renderGraph.AddRasterRenderPass("Edge Detection", out var passData); builder.SetRenderAttachment(resourceData.activeColorTexture, 0); builder.UseAllGlobalTextures(true); builder.AllowPassCulling(false); builder.SetRenderFunc((PassData pd, RasterGraphContext context) => { Blitter.BlitTexture(context.cmd, Vector2.one, material, 0); }); } } [Serializable] public class EdgeDetectionSettings { public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents; [Range(0, 15)] public float outlineThickness = 3; public Color outlineColor = Color.black; public LayerMask layerMask = ~0; } [SerializeField] EdgeDetectionSettings settings; public Material edgeDetectionMaterial; EdgeDetectionPass edgeDetectionPass; public override void Create() { edgeDetectionPass ??= new EdgeDetectionPass(); } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection || UniversalRenderer.IsOffscreenDepthTexture(ref renderingData.cameraData)) { return; } if (edgeDetectionMaterial == null) { edgeDetectionMaterial= CoreUtils.CreateEngineMaterial(Shader.Find("Custom/EdgeDetectionOutline")); if(edgeDetectionMaterial == null) { Debug.LogWarning("Not all required materials could be created. Edge Detection will not render."); return; } } edgeDetectionPass.ConfigureInput(ScriptableRenderPassInput.Depth | ScriptableRenderPassInput.Normal | ScriptableRenderPassInput.Color); edgeDetectionPass.requiresIntermediateTexture = true; edgeDetectionPass.Setup(ref settings, ref edgeDetectionMaterial); renderer.EnqueuePass(edgeDetectionPass); } protected override void Dispose(bool disposing) { edgeDetectionPass = null; if (edgeDetectionMaterial != null) GameObject.DestroyImmediate(edgeDetectionMaterial); } } }