直接上代码
shander
Shader "Unlit/CustomBloom"
{
Properties
{
_MainTex ("MainTex", 2D) = "white" {}
_Bloom("Bloom", 2D) = "white" {}
_Size("Size",Range(1,10)) = 1
_Threshold("Threshold",Range(0,1)) = 0
}
SubShader
{
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f_bloom
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
struct v2f
{
float2 uv[5] : TEXCOORD0;
float4 vertex : SV_POSITION;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
half4 _MainTex_TexelSize;
half4 _MainTex_ST;
TEXTURE2D(_BloomTex);
SAMPLER(sampler_BloomTex);
half4 _BloomTex_TexelSize;
half4 _BloomTex_ST;
float _Size;
float _Threshold;
v2f vertH (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);
float2 uv = v.uv;
o.uv[0] = uv;
o.uv[1] = uv + float2(_MainTex_TexelSize.x,0) * _Size;
o.uv[2] = uv - float2(_MainTex_TexelSize.x,0) * _Size;
o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2,0) * _Size;
o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2,0) * _Size;
return o;
}
v2f vertV (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);
float2 uv = v.uv;
o.uv[0] = uv;
o.uv[1] = uv + float2(_MainTex_TexelSize.y,0) * _Size;
o.uv[2] = uv - float2(_MainTex_TexelSize.y,0) * _Size;
o.uv[3] = uv + float2(_MainTex_TexelSize.y * 2,0) * _Size;
o.uv[4] = uv - float2(_MainTex_TexelSize.y * 2,0) * _Size;
return o;
}
float4 frag (v2f i) : SV_Target
{
float weight[3] = {0.4026,0.2442,0.0545};
float4 col = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv[0]) * weight[0];
for (int j = 1;j < 3;j++)
{
col += SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv[2 * j - 1]) * weight[j];
col += SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv[2 * j]) * weight[j];
}
return col;
}
v2f_bloom vert_bloom (appdata v)
{
v2f_bloom o;
o.vertex = TransformObjectToHClip(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_BloomTex);
return o;
}
float4 fragBloom(v2f_bloom i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);
float b = 0.2125 * col.r + 0.7154 * col.g + 0.0721 * col.b;
b = clamp(b - _Threshold,0,1);
return col * b;
}
float4 fragFinal(v2f_bloom i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv) + SAMPLE_TEXTURE2D(_BloomTex,sampler_BloomTex,i.uv);
return col;
}
ENDHLSL
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline"}
Cull Off ZWrite Off ZTest Always
LOD 100
Pass
{
name "passBloom"
HLSLPROGRAM
#pragma vertex vert_bloom
#pragma fragment fragBloom
ENDHLSL
}
Pass
{
name "passh"
HLSLPROGRAM
#pragma vertex vertH
#pragma fragment frag
ENDHLSL
}
Pass
{
name "passv"
HLSLPROGRAM
#pragma vertex vertV
#pragma fragment frag
ENDHLSL
}
Pass
{
name "passFinal"
HLSLPROGRAM
#pragma vertex vert_bloom
#pragma fragment fragFinal
ENDHLSL
}
}
}
配置参数
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace UnityEngine.Rendering.Universal
{
public static class CustomBloomShaderName
{
public const string _Size = "_Size";
public const string _Threshold = "_Threshold";
public const string _MainTex = "_MainTex";
public const string _BloomTex = "_Bloom";
}
public class CustomBloomVolme : VolumeComponent, IPostProcessComponent
{
public FloatParameter size = new FloatParameter(0);
public FloatParameter threshold = new FloatParameter(0.5f);
public IntParameter sampleCount = new IntParameter(1);
public IntParameter downSample = new IntParameter(2);
public bool IsActive()
{
return size.value > 0;
}
public bool IsTileCompatible()
{
return false;
}
}
}
实现方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using FogMode = UnityEngine.Rendering.Universal.FogMode;
public class CustomBloomFeature : ScriptableRendererFeature
{
class CustomBloomPass : ScriptableRenderPass
{
private RTHandle source;
private RTHandle tempTargetHandle;
private RTHandle tempTargetHandle1;
public Material bloomMaterial;
private int sizeId = Shader.PropertyToID(CustomBloomShaderName._Size);
private int thresholdId = Shader.PropertyToID(CustomBloomShaderName._Threshold);
private int mainTexId = Shader.PropertyToID(CustomBloomShaderName._MainTex);
private int bloomTexId = Shader.PropertyToID(CustomBloomShaderName._BloomTex);
int tempbloom = Shader.PropertyToID("tempbloom");
int tempbloom1 = Shader.PropertyToID("tempbloom1");
public CustomBloomPass()
{
tempTargetHandle = RTHandles.Alloc(tempbloom, name: "tempbloom");
tempTargetHandle1 = RTHandles.Alloc(tempbloom1, name: "tempbloom1");
}
public void Setup(RTHandle source,Material bloomMaterial)
{
this.source = source;
this.bloomMaterial = bloomMaterial;
this.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CustomBloomVolme customBloomVolme = VolumeManager.instance.stack.GetComponent<CustomBloomVolme>();
if (customBloomVolme.IsActive())
{
CommandBuffer cmd = CommandBufferPool.Get("CustomBloomPassCmd");
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.msaaSamples = 1;
desc.depthBufferBits = 0;
desc.width = desc.width / customBloomVolme.downSample.value;
desc.height = desc.height / customBloomVolme.downSample.value;
RenderingUtils.ReAllocateIfNeeded(ref tempTargetHandle, desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: tempTargetHandle.name);
RenderingUtils.ReAllocateIfNeeded(ref tempTargetHandle1, desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: tempTargetHandle1.name);
bloomMaterial.SetFloat(sizeId,customBloomVolme.size.value);
bloomMaterial.SetFloat(thresholdId,customBloomVolme.threshold.value);
cmd.Blit(source,tempTargetHandle,bloomMaterial,0);
var lastDown = tempTargetHandle;
for (int i = 0; i < customBloomVolme.sampleCount.value; i++)
{
cmd.Blit(lastDown,tempTargetHandle1,bloomMaterial,1);
lastDown = tempTargetHandle1;
cmd.Blit(lastDown,tempTargetHandle,bloomMaterial,2);
lastDown = tempTargetHandle;
}
cmd.SetGlobalTexture(bloomTexId,lastDown);
cmd.Blit(source,tempTargetHandle1,bloomMaterial,3);
cmd.Blit(tempTargetHandle1,source);
//cmd.Blit(tempTargetHandle1,source);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
//RTHandles.Release(tempTargetHandle);
//RTHandles.Release(tempTargetHandle1);
}
}
}
private CustomBloomPass customBloomPass;
public Material bloomMaterial;
public override void Create()
{
customBloomPass = new CustomBloomPass();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(customBloomPass);
}
public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
customBloomPass.Setup(renderer.cameraColorTargetHandle,bloomMaterial);
}
}