159 lines
6.5 KiB
C#
159 lines
6.5 KiB
C#
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<ScriptablePostProcessorVolume> postProcessors;
|
|
private List<int> activePostProcessorIndex;
|
|
|
|
private string profilerTag;
|
|
private List<ProfilingSampler> profilingSamplers;
|
|
|
|
// 核心:材质缓存池,确保每个 Shader 只对应一个材质实例
|
|
private Dictionary<string, Material> m_MaterialCache = new Dictionary<string, Material>();
|
|
|
|
public ScriptablePostProcessorPass(string profilerTag, List<ScriptablePostProcessorVolume> postProcessors)
|
|
{
|
|
this.profilerTag = profilerTag;
|
|
this.postProcessors = postProcessors;
|
|
activePostProcessorIndex = new List<int>(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<int> ActiveIndices;
|
|
public List<ScriptablePostProcessorVolume> Volumes;
|
|
public List<ProfilingSampler> 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<UniversalResourceData>();
|
|
var cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
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<PassData>(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);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} |