首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
using UnityEngine;
using UnityEngine.UI;
namespace NBF.Blur
{
public class TestBlur : MonoBehaviour
{
public RawImage raw;
public void Test()
{
Shader.SetGlobalInt("_UIBlurRefresh", 1);
// var blur = URPRendererFeatureUtil.GetRendererFeature<UIBlurDualKawaseFeature>();
// blur?.RefreshOnce();
}
void LateUpdate()
{
if (!raw) return;
raw.texture = Shader.GetGlobalTexture("_UIBlurTexture");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d6c5972785cf41e997b1bd6164a04e00
timeCreated: 1770108402

View File

@@ -0,0 +1,93 @@
using FairyGUI;
using NBF;
using UnityEngine;
using UnityEngine.UI;
public class UIBlur : MonoBehaviour
{
[Header("Quality")] public RenderTexture blurRT;
[Range(1, 6)] public int iterations = 2; // 模糊迭代次数
[Range(0.5f, 4f)] public float blurSize = 1.2f;
[Header("Shader")] public Shader blurShader;
Material _mat;
RenderTexture _capturedRT;
public static UIBlur Instance { get; private set; }
void Awake()
{
blurRT = new RenderTexture((int)(Screen.width * 0.5f), (int)(Screen.height * 0.5f), 0,
RenderTextureFormat.ARGB32);
_mat = new Material(blurShader);
DontDestroyOnLoad(gameObject);
Instance = this;
}
public void CaptureAndBlurOnce()
{
if (blurRT == null) return;
var captureCamera = Camera.main;
if (captureCamera == null) return;
int w = blurRT.width;
int h = blurRT.width;
ReleaseRTs();
var oldEnabled = StageCamera.main.enabled;
StageCamera.main.enabled = false;
_capturedRT = new RenderTexture(w, h, 0, RenderTextureFormat.ARGB32);
_capturedRT.Create();
// 1) 抓摄像机画面到RT不做ReadPixels
var prevTarget = captureCamera.targetTexture;
captureCamera.targetTexture = _capturedRT;
captureCamera.Render();
captureCamera.targetTexture = prevTarget;
StageCamera.main.enabled = oldEnabled;
// 2) 模糊ping-pong
var rt1 = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32);
var rt2 = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(_capturedRT, rt1);
_mat.SetFloat("_BlurSize", blurSize);
for (int i = 0; i < iterations; i++)
{
// 横向
_mat.SetVector("_Direction", new Vector2(1, 0));
Graphics.Blit(rt1, rt2, _mat);
// 纵向
_mat.SetVector("_Direction", new Vector2(0, 1));
Graphics.Blit(rt2, rt1, _mat);
}
Graphics.Blit(rt1, blurRT);
RenderTexture.ReleaseTemporary(rt1);
RenderTexture.ReleaseTemporary(rt2);
}
void ReleaseRTs()
{
if (_capturedRT != null)
{
_capturedRT.Release();
Destroy(_capturedRT);
_capturedRT = null;
}
}
void OnDestroy()
{
ReleaseRTs();
if (_mat) Destroy(_mat);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9a0a734b63534f5e8f244a76a4a8f48d
timeCreated: 1770122480

View File

@@ -0,0 +1,179 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
public class UIBlurDualKawaseFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;
[Range(0.25f, 1f)] public float downscale = 0.5f; // 0.5(中高端) / 0.25(低端更稳)
[Range(1, 6)] public int blurPasses = 4; // 3~4 移动端常用
[Range(0.5f, 4f)] public float offset = 1.0f; // 糊的“扩散感”
public bool updateEveryFrame = false; // 推荐 false只在需要时刷新
public string refreshFlagName = "_UIBlurRefresh"; // UI 触发用
public string globalTextureName = "_UIBlurTexture";
public Shader blurShader; // Hidden/URP/DualKawaseBlur
}
public Settings settings = new Settings();
class Pass : ScriptableRenderPass
{
readonly Settings s;
readonly Material mat;
// 持久 RT让 UI 能跨帧拿到(需要 ImportTexture:contentReference[oaicite:2]{index=2}
RTHandle persistentOutput;
static readonly int SourceTexId = Shader.PropertyToID("_SourceTex");
static readonly int OffsetId = Shader.PropertyToID("_Offset");
public Pass(Settings settings, Material material)
{
s = settings;
mat = material;
}
public RTHandle OutputRT => persistentOutput;
public void EnsureOutput(ref RenderTextureDescriptor desc, int w, int h)
{
desc.width = w;
desc.height = h;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
desc.useMipMap = false;
desc.autoGenerateMips = false;
RenderingUtils.ReAllocateIfNeeded(
ref persistentOutput,
desc,
FilterMode.Bilinear,
TextureWrapMode.Clamp,
name: s.globalTextureName
);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
// 资源/相机数据(官方示例也是这么取 activeColorTexture:contentReference[oaicite:3]{index=3}
var resourceData = frameData.Get<UniversalResourceData>();
var cameraData = frameData.Get<UniversalCameraData>();
// 避免从 backbuffer blit官方示例也这么做:contentReference[oaicite:4]{index=4}
if (resourceData.isActiveTargetBackBuffer)
return;
// 刷新策略:不每帧更新时,只有收到 UI 请求才做一轮
if (!s.updateEveryFrame)
{
if (Shader.GetGlobalInt(s.refreshFlagName) == 0)
return;
Shader.SetGlobalInt(s.refreshFlagName, 0);
}
// 基础描述符(跟相机一致)
var desc = cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
int baseW = Mathf.Max(16, Mathf.RoundToInt(desc.width * s.downscale));
int baseH = Mathf.Max(16, Mathf.RoundToInt(desc.height * s.downscale));
EnsureOutput(ref desc, baseW, baseH);
// 把持久 RTHandle 导入 RenderGraph跨帧可用:contentReference[oaicite:5]{index=5}
TextureHandle outTex = renderGraph.ImportTexture(persistentOutput);
// 生成金字塔0层(base), 1层(/2), 2层(/4)...
int n = Mathf.Clamp(s.blurPasses, 1, 8);
TextureHandle[] pyr = new TextureHandle[n];
for (int i = 0; i < n; i++)
{
int w = Mathf.Max(8, baseW >> i);
int h = Mathf.Max(8, baseH >> i);
var d = desc;
d.width = w;
d.height = h;
pyr[i] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, d, $"_UIBlurPyr{i}", false);
}
mat.SetFloat(OffsetId, s.offset);
// source相机颜色
TextureHandle src = resourceData.activeColorTexture;
// Downsample chain (pass 0)
{
var p = new RenderGraphUtils.BlitMaterialParameters(src, pyr[0], mat, 0);
renderGraph.AddBlitPass(p, "UIBlur DualKawase Down 0");
}
for (int i = 1; i < n; i++)
{
var p = new RenderGraphUtils.BlitMaterialParameters(pyr[i - 1], pyr[i], mat, 0);
renderGraph.AddBlitPass(p, $"UIBlur DualKawase Down {i}");
}
// Upsample chain (pass 1)
for (int i = n - 1; i > 0; i--)
{
var p = new RenderGraphUtils.BlitMaterialParameters(pyr[i], pyr[i - 1], mat, 1);
renderGraph.AddBlitPass(p, $"UIBlur DualKawase Up {i}");
}
// 最终写到持久输出 RT
{
var p = new RenderGraphUtils.BlitMaterialParameters(pyr[0], outTex, mat, 1);
renderGraph.AddBlitPass(p, "UIBlur DualKawase Final");
}
}
public void Cleanup()
{
persistentOutput?.Release();
persistentOutput = null;
}
}
Material _mat;
Pass _pass;
public override void Create()
{
if (settings.blurShader == null)
settings.blurShader = Shader.Find("Hidden/URP/DualKawaseBlur");
if (settings.blurShader != null)
_mat = CoreUtils.CreateEngineMaterial(settings.blurShader);
_pass = new Pass(settings, _mat) { renderPassEvent = settings.passEvent };
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (_mat == null) return;
if (renderingData.cameraData.cameraType != CameraType.Game) return;
// 这里提前把全局纹理指向持久 RT即使本帧不刷新也能用旧结果
if (_pass.OutputRT != null)
Shader.SetGlobalTexture(settings.globalTextureName, _pass.OutputRT);
renderer.EnqueuePass(_pass);
}
protected override void Dispose(bool disposing)
{
_pass?.Cleanup();
CoreUtils.Destroy(_mat);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1d992ccf80d34101a9e62b066d753dc3
timeCreated: 1770108262