Unity Shader 屏幕后效果——Bloom外发光
Posted koshio0219
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity Shader 屏幕后效果——Bloom外发光相关的知识,希望对你有一定的参考价值。
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
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
效果如下:
以上是关于Unity Shader 屏幕后效果——Bloom外发光的主要内容,如果未能解决你的问题,请参考以下文章
Unity Shader屏幕后处理4.0:基于高斯模糊的Bloom