Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成。
一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客:
https://www.cnblogs.com/koshio0219/p/11152534.html
计算方法:
总共需要用到4个Pass,它们的顺序如下:
Pass 1:得到纹理的亮度值(灰度值),由此计算出亮部区域,传递给一个临时的新纹理,这里叫_Bloom
Pass 2,3:单独对_Bloom进行高斯模糊(纵横),_Bloom纹理更新
Pass 4:混合原始纹理和_Bloom纹理,得到最终效果
为了得到更为细致的Bloom效果,建议将游戏的颜色空间由默认的伽马空间转为线性空间,必要时还可开启HDR
控制脚本:
1 using UnityEngine;
2
3 public class BloomCtrl : ScreenEffectBase
4 {
5 private const string _LuminanceThreshold = "_LuminanceThreshold";
6 private const string _BlurSize = "_BlurSize";
7 private const string _Bloom = "_Bloom";
8
9 [Range(0, 4)]
10 public int iterations = 3;
11 [Range(0.2f, 3.0f)]
12 public float blurSize = 0.6f;
13 [Range(1, 8)]
14 public int dowmSample = 2;
15 [Range(0.0f, 4.0f)]
16 public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大
17
18 private void OnRenderImage(RenderTexture source, RenderTexture destination)
19 {
20 if (Material != null)
21 {
22 Material.SetFloat(_LuminanceThreshold, luminanceThreshold);
23
24 int rth = source.height / dowmSample;
25 int rtw = source.width / dowmSample;
26
27 RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
28 buffer0.filterMode = FilterMode.Bilinear;
29
30 //第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
31 Graphics.Blit(source, buffer0,Material,0);
32
33 for(int i = 0; i < iterations; i++)
34 {
35 Material.SetFloat(_BlurSize, blurSize*i+1.0f);
36
37 //第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
38 RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0);
39 Graphics.Blit(buffer0, buffer1, Material,1);
40 RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release();
41
42 buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
43 Graphics.Blit(buffer1, buffer0, Material, 2);
44 RenderTexture.ReleaseTemporary(buffer1);
45 }
46
47 //第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
48 Material.SetTexture(_Bloom, buffer0);
49 Graphics.Blit(source,destination,Material,3);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
50 RenderTexture.ReleaseTemporary(buffer0);
51 }
52 else
53 Graphics.Blit(source, destination);
54 }
55 }
基类脚本见:
https://www.cnblogs.com/koshio0219/p/11131619.html
Shader脚本:
1 Shader "MyUnlit/Bloom"
2 {
3 Properties
4 {
5 _MainTex ("Texture", 2D) = "white" {}
6 _Bloom("Bloom",2D)="black"{}
7 _LuminanceThreshold("Luminance Threshold",Float)=0.5
8 _BlurSize("Blur Size",Float)=1.0
9 }
10 SubShader
11 {
12 CGINCLUDE
13
14 #include "UnityCG.cginc"
15
16 sampler2D _MainTex;
17 half4 _MainTex_TexelSize;
18 sampler2D _Bloom;
19 float _LuminanceThreshold;
20 float _BlurSize;
21
22 struct v2f
23 {
24 half2 uv : TEXCOORD0;
25 float4 pos : SV_POSITION;
26 };
27
28 struct v2fBloom
29 {
30 //half4是因为这里还要存储_Bloom纹理
31 half4 uv:TEXCOORD0;
32 float4 pos:SV_POSITION;
33 };
34
35 v2f vert(appdata_img v)
36 {
37 v2f o;
38 o.pos=UnityObjectToClipPos(v.vertex);
39 o.uv=v.texcoord;
40 return o;
41 }
42
43 v2fBloom vertBloom(appdata_img v)
44 {
45 v2fBloom o;
46 o.pos=UnityObjectToClipPos(v.vertex);
47
48 //xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
49 o.uv.xy=v.texcoord;
50 o.uv.zw=v.texcoord;
51
52 //纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
53 //同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
54 //主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
55 #if UNITY_UV_STARTS_AT_TOP
56 if(_MainTex_TexelSize.y<0){
57 o.uv.w=1.0-o.uv.w;
58 }
59 #endif
60
61 return o;
62 }
63
64 //提取超过亮度阈值的图像
65 fixed4 fragExtractBright(v2f i):SV_Target
66 {
67 fixed4 col=tex2D(_MainTex,i.uv);
68 fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
69 return col*val;
70 }
71
72 //对xy和zw对应的纹理采样进行混合
73 fixed4 fragBloom(v2fBloom i):SV_Target
74 {
75 return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
76 }
77
78 ENDCG
79
80 ZTest Always
81 Cull Off
82 ZWrite Off
83
84 //Pass 1:提亮部
85 Pass
86 {
87 CGPROGRAM
88 #pragma vertex vert
89 #pragma fragment fragExtractBright
90 ENDCG
91 }
92
93 //Pass 2,3:高斯模糊,这里直接调用以前写的Pass
94 UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V"
95
96 UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H"
97
98 //Pass 4:混合原图和模糊后亮部
99 Pass
100 {
101 CGPROGRAM
102 #pragma vertex vertBloom
103 #pragma fragment fragBloom
104 ENDCG
105 }
106 }
107 Fallback Off
108 }
效果如下:
来源:oschina
链接:https://my.oschina.net/u/4407645/blog/3469154