using UnityEngine; using System.Collections; [ExecuteInEditMode] public class BloomEffect : PostEffectBase { //分辨率 public int downSample = 1; //采样率 public int samplerScale = 1; //高亮部分提取阈值 public Color colorThreshold = Color.gray; //Bloom泛光颜色 public Color bloomColor = Color.white; //Bloom权值 [Range(0.0f, 1.0f)] public float bloomFactor = 0.5f; void OnRenderImage(RenderTexture source, RenderTexture destination) { if (_Material) { //申请两块RT,并且分辨率按照downSameple降低 RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format); RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format); //直接将场景图拷贝到低分辨率的RT上达到降分辨率的效果 Graphics.Blit(source, temp1); //根据阈值提取高亮部分,使用pass0进行高亮提取 _Material.SetVector("_colorThreshold", colorThreshold); Graphics.Blit(temp1, temp2, _Material, 0); //高斯模糊,两次模糊,横向纵向,使用pass1进行高斯模糊 _Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0)); Graphics.Blit(temp2, temp1, _Material, 1); _Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0)); Graphics.Blit(temp1, temp2, _Material, 1); //Bloom,将模糊后的图作为Material的Blur图参数 _Material.SetTexture("_BlurTex", temp2); _Material.SetVector("_bloomColor", bloomColor); _Material.SetFloat("_bloomFactor", bloomFactor); //使用pass2进行景深效果计算,清晰场景图直接从source输入到shader的_MainTex中 Graphics.Blit(source, destination, _Material, 2); //释放申请的RT RenderTexture.ReleaseTemporary(temp1); RenderTexture.ReleaseTemporary(temp2); } } }
Shader "Custom/BloomEffect" { Properties{ _MainTex("Base (RGB)", 2D) = "white" {} _BlurTex("Blur", 2D) = "white"{} } CGINCLUDE #include "UnityCG.cginc" //用于阈值提取高亮部分 struct v2f_threshold { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; //用于blur struct v2f_blur { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 uv01 : TEXCOORD1; float4 uv23 : TEXCOORD2; float4 uv45 : TEXCOORD3; }; //用于bloom struct v2f_bloom { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_TexelSize; sampler2D _BlurTex; float4 _BlurTex_TexelSize; float4 _offsets; float4 _colorThreshold; float4 _bloomColor; float _bloomFactor; //高亮部分提取shader v2f_threshold vert_threshold(appdata_img v) { v2f_threshold o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; //dx中纹理从左上角为初始坐标,需要反向 #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1 - o.uv.y; #endif return o; } fixed4 frag_threshold(v2f_threshold i) : SV_Target { fixed4 color = tex2D(_MainTex, i.uv); //仅当color大于设置的阈值的时候才输出 return saturate(color - _colorThreshold); } //高斯模糊 vert shader(上一篇文章有详细注释) v2f_blur vert_blur(appdata_img v) { v2f_blur o; _offsets *= _MainTex_TexelSize.xyxy; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1); o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0; o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0; return o; } //高斯模糊 pixel shader(上一篇文章有详细注释) fixed4 frag_blur(v2f_blur i) : SV_Target { fixed4 color = fixed4(0,0,0,0); color += 0.40 * tex2D(_MainTex, i.uv); color += 0.15 * tex2D(_MainTex, i.uv01.xy); color += 0.15 * tex2D(_MainTex, i.uv01.zw); color += 0.10 * tex2D(_MainTex, i.uv23.xy); color += 0.10 * tex2D(_MainTex, i.uv23.zw); color += 0.05 * tex2D(_MainTex, i.uv45.xy); color += 0.05 * tex2D(_MainTex, i.uv45.zw); return color; } //Bloom效果 vertex shader v2f_bloom vert_bloom(appdata_img v) { v2f_bloom o; //mvp矩阵变换 o.pos = mul(UNITY_MATRIX_MVP, v.vertex); //uv坐标传递 o.uv.xy = v.texcoord.xy; o.uv1.xy = o.uv.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1 - o.uv.y; #endif return o; } fixed4 frag_bloom(v2f_bloom i) : SV_Target { //取原始清晰图片进行uv采样 fixed4 ori = tex2D(_MainTex, i.uv1); //取模糊普片进行uv采样 fixed4 blur = tex2D(_BlurTex, i.uv); //输出= 原始图像,叠加bloom权值*bloom颜色*泛光颜色 fixed4 final = ori + _bloomFactor * blur * _bloomColor; return final; } ENDCG SubShader { //pass 0: 提取高亮部分 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_threshold #pragma fragment frag_threshold ENDCG } //pass 1: 高斯模糊 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_blur #pragma fragment frag_blur ENDCG } //pass 2: Bloom效果 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_bloom #pragma fragment frag_bloom ENDCG } } }注:PostEffectBase类是后处理类的基类,在 前面的文章已有详细介绍,这里不再贴出。
本篇文章介绍的主要是全屏泛光的实现方式,也就是泛光的部分只是通过一个全屏的颜色阈值来进行设定,超过这一阈值的颜色就进行泛光操作,否则不会泛光。这样做效率较高,但是没办法控制单独的物体进行泛光。网上也有这种针对单独对象的bloom操作,可以实现更加细致的Bloom效果,这篇文章可以进行参考。