效果
使画面中较亮的区域“扩散”到周围的区域,造成一种朦胧的效果。
思路
对原贴图大于某个阀值的区域进行提取,并缓存到渲染图。
再利用高斯模糊,对这张纹理进行模糊处理,模拟光线扩散的效果。
最后将其和原图进行混合。
实现
c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BloomTest : PostEffectBaseTest {
public Shader gaussianBlurShader;
private Material gaussianBlurMatrial = null;
public Material material
{
get
{
gaussianBlurMatrial = CheckShaderAndCreateMaterial(gaussianBlurShader, gaussianBlurMatrial);
return gaussianBlurMatrial;
}
}
[Range(0, 4)] public int iterations = 3;
[Range(0.2f, 3f)] public float blurSpread = 0.6f;
[Range(1, 8)] public int downSample = 2;
[Range(0f, 4.0f)] public float luminanceThreshold = 0.6f;
//使用迭代系数,渲染出更模糊的效果
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (material)
{
material.SetFloat("luminanceThreshold",luminanceThreshold);
//降采样
int rtW = src.width / downSample;
int rtH = src.height / downSample;
RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);//得到与屏幕图像大小相同的缓存区
buffer0.filterMode = FilterMode.Bilinear; //将渲染纹理的滤波模式设置为双线性
//使用第一个pass(使用原图,计算明亮度,渲染成一张纹理记录到缓存。
Graphics.Blit(src, buffer0, material, 0 );
for (int i = 0; i < iterations; i++)//对画面进行多次模糊渲染
{
material.SetFloat("_BlurSize",1.0f+i*blurSpread);//调节模糊的范围大小
RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);//获取屏幕图像缓存区
//使用索引为1的pass,和模糊范围的参数,对纹理的竖直方向,进行模糊渲染
Graphics.Blit(buffer0,buffer1,material,1);
RenderTexture.ReleaseTemporary(buffer0);//释放缓冲区
buffer0 = buffer1;//记录处理过竖直方向模糊的buffer1
buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);//获取缓冲区
//使用索引为2的pass,和模糊范围的参数,对纹理的水平方向,进行模糊渲染
Graphics.Blit(buffer0,buffer1,material,2);
RenderTexture.ReleaseTemporary(buffer0);//释放屏幕缓冲区
buffer0 = buffer1;
}
Graphics.Blit(buffer0,dest);//多重渲染后,再计算总结果,渲染出最后的图形
material.SetTexture("_Bloom",buffer0);
Graphics.Blit(src,dest,material,3);//多重渲染后,再在索引为3的pass中,进行bloom处理,渲染出最后的图形
RenderTexture.ReleaseTemporary(buffer0);
}
else
{
Graphics.Blit(src,dest);
}
}
}
shader
Shader "Custom/BloomTest" {
Properties {
_MainTex("Base (RGB)",2D) = "white" {}
_BlurSize("_BlurSize",Float) = 1.0
_Bloom("Bloom (RGB)",2D) = "black" {}
}
SubShader {
CGINCLUDE
//引入文件
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_TexelSize;
float _BlurSize;
sampler2D _Bloom;
float luminanceThreshold;
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
fixed luminance(fixed4 color){
return 0.2125*color.r + 0.7154*color.g + 0.0721*color.b;
};
v2f vertExtractBright(appdata_img v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
};
fixed4 fragExtractBright(v2f i):SV_Target{
fixed4 c = tex2D(_MainTex, i.uv);
fixed l = clamp(luminance(c) - luminanceThreshold, 0.0, 1.0);
return c*l;//返回主图的明亮度信息
};
struct v2fBloom{
float4 pos : SV_POSITION;
half4 uv : TEXCOORD0;
};
v2fBloom vertBloom(appdata_img v){
v2fBloom o;
o.pos = UnityObjectToClipPos (v.vertex);
o.uv.xy = v.texcoord;
o.uv.zw = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0)
o.uv.w = 1.0 - o.uv.w;
#endif
return o;
};
fixed4 fragBloom(v2fBloom i ) : SV_Target{
//对原图与
return tex2D(_MainTex,i.uv.xy ) + tex2D(_Bloom,i.uv.zw);
};
ENDCG
ZTest Always Cull Off ZWrite Off
Pass{
CGPROGRAM
#pragma vertex vertExtractBright
#pragma fragment fragExtractBright
ENDCG
}
UsePass "Custom/GaussianBlurShader/GAUSSIAN_BLUR_VERTICAL"
UsePass "Custom/GaussianBlurShader/GAUSSIAN_BLUR_HORIZONTAL"
Pass{
CGPROGRAM
#pragma vertex vertBloom
#pragma fragment fragBloom
ENDCG
}
}
FallBack Off
}