using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.RenderGraphModule.Util; using UnityEngine.Rendering.Universal; public class GlobalDistortionRendererFeature : ScriptableRendererFeature { [Tooltip("When the custom distortion pass should execute.")] public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; private Material material; private GlobalDistortionPass pass; public override void Create() { if (pass == null) pass = new GlobalDistortionPass(); pass.renderPassEvent = renderPassEvent; EnsureMaterial(); } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (!EnsureMaterial()) return; Camera camera = renderingData.cameraData.camera; if (camera == null) return; if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection) return; if (!renderingData.cameraData.postProcessEnabled) return; GlobalDistortionVolume settings = VolumeManager.instance.stack.GetComponent(); bool hasVolume = settings != null && settings.active; float runtimeIntensity = GlobalDistortionRuntimeController.RuntimeIntensity; float baseIntensity = hasVolume ? settings.intensity.value : 0f; float finalIntensity = Mathf.Clamp01(baseIntensity + runtimeIntensity); if (finalIntensity <= 0.0001f) return; if (camera.cameraType == CameraType.SceneView && hasVolume && !settings.affectSceneView.value) return; pass.Setup( material, finalIntensity, hasVolume ? settings.noiseStrength.value : 0.16f, hasVolume ? settings.radialStrength.value : 0.35f, hasVolume ? settings.noiseScale.value : 12f, hasVolume ? settings.center.value : new Vector2(0.5f, 0.5f), hasVolume ? settings.edgeFade.value : 1.25f ); renderer.EnqueuePass(pass); } protected override void Dispose(bool disposing) { if (pass != null) { pass.Dispose(); pass = null; } if (material != null) { CoreUtils.Destroy(material); material = null; } } private bool EnsureMaterial() { if (material != null) return true; Shader shader = Shader.Find("Hidden/Bansonic/GlobalDistortion"); if (shader == null) return false; material = CoreUtils.CreateEngineMaterial(shader); return material != null; } private sealed class GlobalDistortionPass : ScriptableRenderPass { private static readonly int IntensityId = Shader.PropertyToID("_DistortionIntensity"); private static readonly int NoiseStrengthId = Shader.PropertyToID("_NoiseStrength"); private static readonly int RadialStrengthId = Shader.PropertyToID("_RadialStrength"); private static readonly int NoiseScaleId = Shader.PropertyToID("_NoiseScale"); private static readonly int CenterId = Shader.PropertyToID("_DistortionCenter"); private static readonly int EdgeFadeId = Shader.PropertyToID("_EdgeFade"); private Material passMaterial; private float intensity; private float noiseStrength; private float radialStrength; private float noiseScale; private Vector2 center; private float edgeFade; private RTHandle compatibilityCopy; public void Setup(Material material, float passIntensity, float passNoiseStrength, float passRadialStrength, float passNoiseScale, Vector2 passCenter, float passEdgeFade) { passMaterial = material; intensity = passIntensity; noiseStrength = passNoiseStrength; radialStrength = passRadialStrength; noiseScale = passNoiseScale; center = passCenter; edgeFade = passEdgeFade; requiresIntermediateTexture = true; } public void Dispose() { compatibilityCopy?.Release(); compatibilityCopy = null; } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { if (passMaterial == null) return; UniversalResourceData resourceData = frameData.Get(); if (resourceData.isActiveTargetBackBuffer) return; ApplyMaterialProperties(); TextureHandle source = resourceData.activeColorTexture; TextureDesc tempDesc = renderGraph.GetTextureDesc(source); tempDesc.name = "CameraColor-GlobalDistortionTemp"; tempDesc.clearBuffer = false; TextureHandle tempTexture = renderGraph.CreateTexture(tempDesc); RenderGraphUtils.BlitMaterialParameters effectParameters = new(source, tempTexture, passMaterial, 0); renderGraph.AddBlitPass(effectParameters, passName: "Global Distortion Effect"); renderGraph.AddBlitPass( tempTexture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Global Distortion Restore" ); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { if (passMaterial == null) return; ApplyMaterialProperties(); RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor; descriptor.msaaSamples = 1; descriptor.depthBufferBits = 0; RenderingUtils.ReAllocateHandleIfNeeded(ref compatibilityCopy, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_GlobalDistortionCompatibilityCopy"); CommandBuffer cmd = CommandBufferPool.Get("Global Distortion Pass"); try { Blitter.BlitCameraTexture(cmd, renderingData.cameraData.renderer.cameraColorTargetHandle, compatibilityCopy); Blitter.BlitCameraTexture(cmd, compatibilityCopy, renderingData.cameraData.renderer.cameraColorTargetHandle, passMaterial, 0); context.ExecuteCommandBuffer(cmd); } finally { cmd.Clear(); CommandBufferPool.Release(cmd); } } private void ApplyMaterialProperties() { passMaterial.SetFloat(IntensityId, intensity); passMaterial.SetFloat(NoiseStrengthId, noiseStrength); passMaterial.SetFloat(RadialStrengthId, radialStrength); passMaterial.SetFloat(NoiseScaleId, noiseScale); passMaterial.SetVector(CenterId, center); passMaterial.SetFloat(EdgeFadeId, edgeFade); } } }