using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.Universal; namespace SLSFramework.Rendering.PostProcessing { public class ScriptablePostProcessorPass : ScriptableRenderPass { private List postProcessors; private List activePostProcessorIndex; private string profilerTag; private List profilingSamplers; // 核心:材质缓存池,确保每个 Shader 只对应一个材质实例 private Dictionary m_MaterialCache = new Dictionary(); public ScriptablePostProcessorPass(string profilerTag, List postProcessors) { this.profilerTag = profilerTag; this.postProcessors = postProcessors; activePostProcessorIndex = new List(postProcessors.Count); profilingSamplers = postProcessors.Select(c => new ProfilingSampler(c.ToString())).ToList(); } private RenderingData m_RenderingData; // 清理函数,由 Feature.Dispose 调用 public void Cleanup() { foreach (var mat in m_MaterialCache.Values) { if (mat != null) CoreUtils.Destroy(mat); } m_MaterialCache.Clear(); } private Material GetOrCreateMaterial(string shaderName) { if (string.IsNullOrEmpty(shaderName)) return null; if (m_MaterialCache.TryGetValue(shaderName, out var mat) && mat != null) return mat; // 调用你的静态工具类创建材质 var shader = Shader.Find(shaderName); if (shader == null) return null; mat = CoreUtils.CreateEngineMaterial(shader); m_MaterialCache[shaderName] = mat; return mat; } private class PassData { public TextureHandle SourceTexture; public TextureHandle TargetTexture; public TextureHandle TempTextureA; public TextureHandle TempTextureB; public List ActiveIndices; public List Volumes; public List Profilers; public RenderingData RenderingData; } public bool Setup(ref RenderingData renderingData) { this.m_RenderingData = renderingData; activePostProcessorIndex.Clear(); for (int i = 0; i < postProcessors.Count; i++) { var volume = postProcessors[i]; // 关键修复:从 Pass 的缓存池获取材质并注入给 Volume var mat = GetOrCreateMaterial(volume.GetShaderName()); volume.SetMaterial(mat); volume.Setup(); if (volume.IsActive()) { activePostProcessorIndex.Add(i); } } return activePostProcessorIndex.Count != 0; } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { var resourceData = frameData.Get(); var cameraData = frameData.Get(); if (activePostProcessorIndex.Count == 0) return; var cameraDesc = cameraData.cameraTargetDescriptor; var rgDesc = new TextureDesc(cameraDesc.width, cameraDesc.height); rgDesc.colorFormat = cameraDesc.graphicsFormat; rgDesc.depthBufferBits = DepthBits.None; rgDesc.msaaSamples = MSAASamples.None; using (var builder = renderGraph.AddUnsafePass(profilerTag, out var passData)) { passData.SourceTexture = resourceData.activeColorTexture; passData.TargetTexture = resourceData.activeColorTexture; passData.ActiveIndices = activePostProcessorIndex; passData.Volumes = postProcessors; passData.Profilers = profilingSamplers; passData.RenderingData = m_RenderingData; rgDesc.name = "_TemporaryRenderTextureA"; passData.TempTextureA = renderGraph.CreateTexture(rgDesc); rgDesc.name = "_TemporaryRenderTextureB"; passData.TempTextureB = renderGraph.CreateTexture(rgDesc); builder.UseTexture(passData.SourceTexture, AccessFlags.Read); builder.UseTexture(passData.TempTextureA, AccessFlags.ReadWrite); builder.UseTexture(passData.TempTextureB, AccessFlags.ReadWrite); builder.UseTexture(passData.TargetTexture, AccessFlags.ReadWrite); builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => { var cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd); var source = data.SourceTexture; var target = data.TargetTexture; var tempA = data.TempTextureA; var tempB = data.TempTextureB; if (data.ActiveIndices.Count == 1) { int index = data.ActiveIndices[0]; using (new ProfilingScope(cmd, data.Profilers[index])) { data.Volumes[index].Render(cmd, ref data.RenderingData, source, tempA); } Blitter.BlitCameraTexture(cmd, tempA, target); } else { Blitter.BlitCameraTexture(cmd, source, tempA); var currSource = tempA; var currDest = tempB; foreach (int index in data.ActiveIndices) { var postProcessor = data.Volumes[index]; using (new ProfilingScope(cmd, data.Profilers[index])) { postProcessor.Render(cmd, ref data.RenderingData, currSource, currDest); } CoreUtils.Swap(ref currSource, ref currDest); } Blitter.BlitCameraTexture(cmd, currSource, target); } }); } } } }