后处理+FEEL完全改进

This commit is contained in:
SoulliesOfficial
2025-12-22 18:36:29 -05:00
parent c3914da4ac
commit a2052bfe16
1427 changed files with 193092 additions and 374110 deletions

View File

@@ -0,0 +1,60 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace Echovoid.Runtime.Behavior.Rendering
{
public static class InternalShaderHelpers
{
public static Material GenerateTransientMaterial(string shaderName)
{
var shader = Shader.Find(shaderName);
return CoreUtils.CreateEngineMaterial(shader);
}
public static class ID
{
// RGB Split Glitch
public static readonly int _RGBSplitGlitchParams = Shader.PropertyToID("_RGBSplitGlitchParams");
public static readonly int _RGBSplitGlitchIntensity = Shader.PropertyToID("_RGBSplitGlitchIntensity");
// Radial Blur
public static readonly int _RadialBlurParams = Shader.PropertyToID("_RadialBlurParams");
public static readonly int _BlurRadius = Shader.PropertyToID("_BlurRadius");
public static readonly int _RadialCenterX = Shader.PropertyToID("_RadialCenterX");
public static readonly int _RadialCenterY = Shader.PropertyToID("_RadialCenterY");
// Speed Lines
public static readonly int _SpeedLinesColour = Shader.PropertyToID("_Colour");
public static readonly int _SpeedLinesTiling = Shader.PropertyToID("_SpeedLinesTiling");
public static readonly int _SpeedLinesRadialScale = Shader.PropertyToID("_SpeedLinesRadialScale");
public static readonly int _SpeedLinesPower = Shader.PropertyToID("_SpeedLinesPower");
public static readonly int _SpeedLinesRemap = Shader.PropertyToID("_SpeedLinesRemap");
public static readonly int _SpeedLinesAnimation = Shader.PropertyToID("_SpeedLinesAnimation");
public static readonly int _MaskScale = Shader.PropertyToID("_MaskScale");
public static readonly int _MaskHardness = Shader.PropertyToID("_MaskHardness");
public static readonly int _MaskPower = Shader.PropertyToID("_MaskPower");
// --- Strobe Flash ---
public static readonly int _StrobeColorHigh = Shader.PropertyToID("_StrobeColorHigh");
public static readonly int _StrobeColorLow = Shader.PropertyToID("_StrobeColorLow");
public static readonly int _StrobeParams = Shader.PropertyToID("_StrobeParams");
public static readonly int _StrobeAdvParams = Shader.PropertyToID("_StrobeAdvParams");
public static readonly int _LuminanceWeights = Shader.PropertyToID("_LuminanceWeights");
// --- Sharpen ---
public static readonly int _SharpnessParams = Shader.PropertyToID("_SharpnessParams");
// --- Advanced Chromatic Aberration ---
public static readonly int _ACA_Params1 = Shader.PropertyToID("_ACA_Params1");
public static readonly int _ACA_Params2 = Shader.PropertyToID("_ACA_Params2");
public static readonly int _ACA_Split = Shader.PropertyToID("_ACA_Split");
public static readonly int _DispersionMap = Shader.PropertyToID("_DispersionMap");
// --- Advanced Vignette ---
public static readonly int _ColorInner = Shader.PropertyToID("_ColorInner");
public static readonly int _ColorOuter = Shader.PropertyToID("_ColorOuter");
public static readonly int _VignetteParams1 = Shader.PropertyToID("_VignetteParams1");
public static readonly int _VignetteCenter = Shader.PropertyToID("_VignetteCenter");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e46d8eed8c36ac84caf7ea20f2a0b134

View File

@@ -0,0 +1,102 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace SLSFramework.Rendering.PostProcessing
{
public class ScriptablePostProcessorFeature : ScriptableRendererFeature
{
private List<ScriptablePostProcessorVolume> postProcessorVolumes;
private ScriptablePostProcessorPass afterTransparentPass;
private ScriptablePostProcessorPass beforePostProcessPass;
private ScriptablePostProcessorPass afterPostProcessPass;
public override void Create()
{
var stack = VolumeManager.instance.stack;
postProcessorVolumes = VolumeManager.instance.baseComponentTypeArray
.Where(t => t.IsSubclassOf(typeof(ScriptablePostProcessorVolume)))
.Select(t => stack.GetComponent(t) as ScriptablePostProcessorVolume)
.ToList();
var afterTransparentPostProcessors = postProcessorVolumes
.Where(c => c.InjectionPoint == CustomPostProcessInjectionPoint.AfterTransparent)
.OrderBy(c => c.OrderInInjectionPoint)
.ToList();
afterTransparentPass =
new ScriptablePostProcessorPass("Custom PostProcessor - after Transparent", afterTransparentPostProcessors)
{
renderPassEvent = RenderPassEvent.AfterRenderingTransparents
};
var beforePostProcessPostProcessors = postProcessorVolumes
.Where(c => c.InjectionPoint == CustomPostProcessInjectionPoint.BeforePostProcess)
.OrderBy(c => c.OrderInInjectionPoint)
.ToList();
beforePostProcessPass =
new ScriptablePostProcessorPass("Custom PostProcessor - before PostProcessing", beforePostProcessPostProcessors)
{
renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing
};
var afterPostProcessPostProcessors = postProcessorVolumes
.Where(c => c.InjectionPoint == CustomPostProcessInjectionPoint.AfterPostProcess)
.OrderBy(c => c.OrderInInjectionPoint)
.ToList();
afterPostProcessPass =
new ScriptablePostProcessorPass("Custom PostProcessor - after PostProcessing", afterPostProcessPostProcessors)
{
renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing
};
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// 只有在相机开启后处理时才执行
if (renderingData.cameraData.postProcessEnabled)
{
// 关键点:将 renderingData 传递给 Pass 的 Setup 方法
// 这样我们就能把数据缓存下来给 RenderGraph 使用了
if (afterTransparentPass.Setup(ref renderingData))
{
afterTransparentPass.ConfigureInput(ScriptableRenderPassInput.Color);
renderer.EnqueuePass(afterTransparentPass);
}
if (beforePostProcessPass.Setup(ref renderingData))
{
beforePostProcessPass.ConfigureInput(ScriptableRenderPassInput.Color);
renderer.EnqueuePass(beforePostProcessPass);
}
if (afterPostProcessPass.Setup(ref renderingData))
{
afterPostProcessPass.ConfigureInput(ScriptableRenderPassInput.Color);
renderer.EnqueuePass(afterPostProcessPass);
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (postProcessorVolumes != null)
{
foreach (var item in postProcessorVolumes)
{
item.Dispose();
}
}
afterTransparentPass = null;
beforePostProcessPass = null;
afterPostProcessPass = null;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 278f6128b25bcd644b3e798a37d9827b

View File

@@ -0,0 +1,146 @@
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;
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;
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; // 数据结构保持不变
}
// 修改 Setup接收 RenderingData 并保存
// 注意:这里的 Setup 需要在 AddRenderPasses 中调用
public bool Setup(ref RenderingData renderingData)
{
this.m_RenderingData = renderingData; // 捕获数据
activePostProcessorIndex.Clear();
for (int i = 0; i < postProcessors.Count; i++)
{
postProcessors[i].Setup();
if (postProcessors[i].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;
// 1. 获取相机的基础描述符 (这是旧的 RenderTextureDescriptor)
var cameraDesc = cameraData.cameraTargetDescriptor;
// 2. 【核心修正】创建一个新的 RenderGraph 专用描述符 (TextureDesc)
// 只有 TextureDesc 才能设置 name也不能直接把 cameraDesc 强转过去,必须手动赋值
var rgDesc = new TextureDesc(cameraDesc.width, cameraDesc.height);
rgDesc.colorFormat = cameraDesc.graphicsFormat;
rgDesc.depthBufferBits = DepthBits.None; // 后处理不需要深度
rgDesc.msaaSamples = MSAASamples.None; // 后处理通常不需要 MSAA
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;
// 使用我们在 Setup 中缓存的旧版数据 (解决 UniversalRenderingData 找不到的问题)
passData.RenderingData = m_RenderingData;
// 3. 【核心修正】设置名字并创建纹理
// 这里使用的是 rgDesc (TextureDesc 类型),它有 name 属性
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);
}
});
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5c198108d8fe5ea4fad878bf9623c573

View File

@@ -0,0 +1,49 @@
using System;
using Echovoid.Runtime.Behavior.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace SLSFramework.Rendering.PostProcessing
{
public enum CustomPostProcessInjectionPoint
{
AfterTransparent,
BeforePostProcess,
AfterPostProcess
}
public abstract class ScriptablePostProcessorVolume : VolumeComponent, IPostProcessComponent, IDisposable
{
public virtual CustomPostProcessInjectionPoint InjectionPoint =>
CustomPostProcessInjectionPoint.AfterPostProcess;
public virtual int OrderInInjectionPoint => 0;
protected Material material;
protected abstract string GetShaderName();
public virtual void Setup()
{
material = InternalShaderHelpers.GenerateTransientMaterial(GetShaderName());
}
public abstract void Render(CommandBuffer cmd, ref RenderingData renderingData, RTHandle source, RTHandle destination);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing)
{
CoreUtils.Destroy(material);
}
public abstract bool IsActive();
public bool IsTileCompatible() => false;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: da1ac4541bff9ba4980b8e18d53bb76e