Files
test/Assets/ModelRenderer/Scripts/RenderFeatures/BloomRenderFeature.cs
2025-12-15 00:12:16 +07:00

175 lines
6.9 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Experimental.Rendering;
public class BloomRenderFeature : ScriptableRendererFeature
{
[System.Serializable]
public class BloomSettings
{
public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingPostProcessing;
public Shader blurShader;
public Shader compositeShader;
[Range(0, 4)]
public int downsample = 1;
[Range(0.0f, 2.0f)]
public float threshold = 1.0f;
[Range(0.0f, 10.0f)]
public float radius = 1.0f;
[Range(0.0f, 10.0f)]
public float intensity = 1.0f;
// x = w2, y = w1, z = w0 (symmetric 5-tap kernel)
public Vector3 weights = new Vector3(0.2f, 0.4f, 0.8f);
}
BloomPass bloomPass;
Material blurMat;
Material compositeMat;
public BloomSettings settings = new BloomSettings();
// ────────────────────────────────────────────────────────────────
// CREATE
// ────────────────────────────────────────────────────────────────
public override void Create()
{
if (settings.blurShader)
blurMat = CoreUtils.CreateEngineMaterial(settings.blurShader);
if (settings.compositeShader)
compositeMat = CoreUtils.CreateEngineMaterial(settings.compositeShader);
bloomPass = new BloomPass(settings);
bloomPass.renderPassEvent = settings.passEvent;
}
// ────────────────────────────────────────────────────────────────
// ONLY enqueue pass here (NO camera target access!)
// ────────────────────────────────────────────────────────────────
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (blurMat == null || compositeMat == null)
return;
// Pass only materials
bloomPass.Setup(blurMat, compositeMat);
renderer.EnqueuePass(bloomPass);
}
// ======================================================================
// BLOOM PASS
// ======================================================================
class BloomPass : ScriptableRenderPass
{
BloomSettings settings;
Material blurMat;
Material compositeMat;
RTHandle rt1;
RTHandle rt2;
// final camera target (RenderTargetIdentifier)
RenderTargetIdentifier source;
string tag = "BloomPass";
public BloomPass(BloomSettings settings)
{
this.settings = settings;
}
public void Setup(Material blurMat, Material compositeMat)
{
this.blurMat = blurMat;
this.compositeMat = compositeMat;
}
// ────────────────────────────────────────────────────────────────
// VALID place to access cameraColorTargetHandle
// ────────────────────────────────────────────────────────────────
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// SAFE: this is the correct place to access cameraColorTargetHandle
source = renderingData.cameraData.renderer.cameraColorTargetHandle;
float scale = 1f / (1 << settings.downsample);
Vector2 scaleFactor = new Vector2(scale, scale);
rt1 = RTHandles.Alloc(
scaleFactor,
colorFormat: GraphicsFormat.R16G16B16A16_SFloat,
filterMode: FilterMode.Bilinear,
name: "_BloomRT1"
);
rt2 = RTHandles.Alloc(
scaleFactor,
colorFormat: GraphicsFormat.R16G16B16A16_SFloat,
filterMode: FilterMode.Bilinear,
name: "_BloomRT2"
);
}
// ────────────────────────────────────────────────────────────────
// EXECUTE BLOOM EFFECT
// ────────────────────────────────────────────────────────────────
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (blurMat == null || compositeMat == null)
return;
CommandBuffer cmd = CommandBufferPool.Get(tag);
// Pass parameters
blurMat.SetFloat("_Threshold", settings.threshold);
blurMat.SetFloat("_Radius", settings.radius);
blurMat.SetFloat("_Intensity", settings.intensity);
blurMat.SetVector("_Weights", new Vector4(settings.weights.x, settings.weights.y, settings.weights.z, 0));
// 1. Extract bright areas
cmd.Blit(source, rt1, blurMat, 0);
// 2. Blur horizontal
blurMat.SetVector("_Direction", new Vector4(1, 0, 0, 0));
cmd.Blit(rt1, rt2, blurMat, 1);
// 3. Blur vertical
blurMat.SetVector("_Direction", new Vector4(0, 1, 0, 0));
cmd.Blit(rt2, rt1, blurMat, 1);
// 4. Composite bloom back
compositeMat.SetFloat("_Intensity", settings.intensity);
cmd.Blit(rt1, source, compositeMat, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
// ────────────────────────────────────────────────────────────────
// CLEANUP (Release RTHandles)
// ────────────────────────────────────────────────────────────────
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (rt1 != null) RTHandles.Release(rt1);
if (rt2 != null) RTHandles.Release(rt2);
}
}
}