using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class OutlineRenderFeature : ScriptableRendererFeature { class OutlinePass : ScriptableRenderPass { private RenderTargetHandle tempColorTexture; private Material outlineMaterial; private RenderTargetIdentifier cameraTarget; public OutlinePass(Material material) { outlineMaterial = material; tempColorTexture.Init("_TemporaryColorTexture"); } public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) { cmd.GetTemporaryRT(tempColorTexture.id, cameraTextureDescriptor); // Create temp texture ConfigureTarget(tempColorTexture.Identifier()); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { if (outlineMaterial == null) return; CommandBuffer cmd = CommandBufferPool.Get("Outline Pass"); cameraTarget = renderingData.cameraData.renderer.cameraColorTargetHandle; // ✅ Safe usage here Blit(cmd, cameraTarget, tempColorTexture.Identifier()); // Copy to temp texture Blit(cmd, tempColorTexture.Identifier(), cameraTarget, outlineMaterial); // Apply outline effect context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } public override void OnCameraCleanup(CommandBuffer cmd) { cmd.ReleaseTemporaryRT(tempColorTexture.id); // Cleanup } } [SerializeField] private Material outlineMaterial; private OutlinePass outlinePass; public override void Create() { outlinePass = new OutlinePass(outlineMaterial) { renderPassEvent = RenderPassEvent.AfterRenderingOpaques // ✅ Executes after opaque objects }; } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (outlinePass != null) { renderer.EnqueuePass(outlinePass); } } }