来自于《Unity Shader 入门精要》书本的学习
先上图
代码分3部分
1.PostEffectsBase.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; //在编辑器状态下可执行该脚本来查看效果 [ExecuteInEditMode] //屏幕后处理特效一般需要绑定在摄像机上 [RequireComponent(typeof(Camera))] public class PostEffectsBase : MonoBehaviour {void Start () {CheckResources();}protected void CheckResources(){bool isSupported = CheckSupport();//如果显卡检测 返回falseif (isSupported == false){//NotSupported()方法,即不显示 NotSupported();}}//检查显卡是否支持protected bool CheckSupport(){//如果显卡不支持图像后期处理if (SystemInfo.supportsImageEffects == false){//返回falsereturn false;}//如果支持图像后处理,返回truereturn true;}//图像不显示protected void NotSupported(){enabled = false;}//CheckShaderAndCreateMaterial函数接受两个参数,第一个参数指定了改特效需要使用的Shader//第二个参数则是用于后期处理的材质。该函数首先检查Shader的可用性,检查通过后就返回一个使//用了该shader的材质,否则返回null.protected Material CheckShaderAndCreateMaterial(Shader shader, Material material){ //如果shader为空if (shader == null){return null;}//shader.isSupported:能在终端用户的图形卡上运行这个着色器&& 并且存在material 他的shader是我们输入的shaderif (shader.isSupported && material && material.shader == shader){return material;}if (!shader.isSupported){return null;}//上面都不满足的话,重新创建新的材质球else{material = new Material(shader);//hideFlags:控制对象销毁的位掩码//HideFlags.DontSave对象不会保存到场景中。加载新场景时不会被破坏。material.hideFlags = HideFlags.DontSave;return material;}}}
2.bloom.using System.Collections;
using System.Collections.Generic; using UnityEngine;public class bloom : PostEffectsBase {public Shader bloomShader;private Material bloomMaterial;public Material material{get{//根据PostEffectsBase中的方法检测,第一个参数指定了该特效需要使用的Shader,第二个参数则是用于后期处理的材质;//该函数首先检查Shader的可用性,检查通过后返回一个使用了该shader的材质,否则返回Null.bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);return bloomMaterial;}}//高斯模糊的叠带次数[Range(0, 4)]public int iterations = 3;//高斯模糊的叠带范围[Range(0.2f, 4.0f)]public float blurSpread = 0.6f;//降采样的数值[Range(1, 8)]public int downSample = 2;//luminanceThreshold,大多数情况下图像亮度不会超过1.但如果我们开启了HDR,硬件会允许我们把颜色值储存在一个更高精度范围的缓冲中,//此时像素的亮度就会超过1.[Range(0.0f, 4.0f)]public float luminanceThreshold = 0.6f;//OnRenderImage函数void OnRenderImage (RenderTexture src , RenderTexture dest){if (material != null){material.SetFloat("_luminanceThreshold", luminanceThreshold);//将图像进行降采样不仅可以减少需要处理的像素,提高性能,而且适当的降采样旺旺还可以得到更好的模糊效果int rtW = src.width / downSample;int rtH = src.height / downSample;//定义第一个缓存buffer0,并吧src中的图像缩放后储存到buffer0中。RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);buffer0.filterMode = FilterMode.Bilinear;//调用shader中的第一个Pass提取图像中较亮的区域,提到的较亮区域将储存在buffer0 中。Graphics.Blit(src, buffer0, material, 0);for (int i = 0; i < iterations; i++){material.SetFloat("_BlurSize", 1.0f + i * blurSpread);//定义buffer1RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);//调用第二个pass,输入buffer0,输出buffer1.Graphics.Blit(buffer0, buffer1, material, 1);RenderTexture.ReleaseTemporary(buffer0);//将输出的buffer1重新赋值给buffer0buffer0 = buffer1;buffer1 = RenderTexture.GetTemporary(rtW, rtH,0);//调用第三个pass,输入buffer0(上面输出的buffer1),输出buffer1(新的buffer1)Graphics.Blit(buffer0, buffer1, material, 2);//将新的buffer1再次给buffer0赋值buffer0 = buffer1;}//第四个Pass,将buffer0赋值给贴图_Bloommaterial.SetTexture("_Bloom", buffer0);Graphics.Blit(src, dest, material, 3);RenderTexture.ReleaseTemporary(buffer0);}else{Graphics.Blit(src, dest);}} }
3.bloom.shader
Shader "Unlit/Bloom" {Properties{_MainTex ("Texture", 2D) = "white" {}//高斯模糊较亮的区域 _Bloom ("Bloom(RGB)",2D) = "Black"{}//阔值,提取大于这个亮度的区域 后面将在 大于这个值 的区域里进行高斯模糊_luminanceThreshold("luminanceThreshold",Float) = 0.5//控制不同迭代之间高斯模糊的模糊区域范围 也就是uv偏移的范围_BlurSize ("Blur Size",Float) = 1.0}SubShader{CGINCLUDE#include "UnityCG.cginc" sampler2D _MainTex;half4 _MainTex_TexelSize;sampler2D _Bloom;Float _luminanceThreshold;float _BlurSize;///提取交亮区域的 顶点.片元 着色器struct v2f {float4 pos :SV_POSITION;half2 uv :TEXCOORD0;};v2f vertExtractBright (appdata_img v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;return o;}//通过主贴图得到一个灰度值 fixed4 luminance (fixed4 color){return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;}fixed4 fragExtractBright (v2f i ):SV_Target {///我们降采样得到的亮度值减去阔值_luminanceThreshold,并把结果截取到0到1的范围内,然后///我们把该值和原像素相乘,得到提取后的两部区域///这样就是低于_luminanceThreshold显示为黑色fixed c = tex2D(_MainTex , i.uv);//clamp(x,a,b),如果x<a,返回a,x>b,返回b,否则返回为x;fixed val = clamp (luminance(c) - _luminanceThreshold, 0.0, 1.0);return c * val;}///使用Unity提供的_MainTex_Texel_TexelSize变量,计算相邻文理坐标的的偏移(也是高斯模糊的写法)//竖方向跟横方向的两个顶点着色器公用的v2f输出定义struct v2fBlur {float4 pos : SV_POSITION;half2 uv[5]:TEXCOORD0;};//竖直方向的 v2fBlur vertBlurV (appdata_img v){v2fBlur o;o.pos = UnityObjectToClipPos (v.vertex);half2 uv = v.texcoord;o.uv[0] = uv;o.uv[1] = uv + float2 (0.0,_MainTex_TexelSize.y * 1.0) * _BlurSize;o.uv[2] = uv - float2 (0.0,_MainTex_TexelSize.y * 1.0) * _BlurSize;o.uv[3] = uv + float2 (0.0,_MainTex_TexelSize.y * 2.0) * _BlurSize;o.uv[4] = uv - float2 (0.0,_MainTex_TexelSize.y * 2.0) * _BlurSize;return o;}//水平方向的 v2fBlur vertBlurH (appdata_img v){v2fBlur o;o.pos = UnityObjectToClipPos (v.vertex);half2 uv = v.texcoord;o.uv[0] = uv;o.uv[1] = uv + float2 (_MainTex_TexelSize.x * 1.0 , 0.0) * _BlurSize;o.uv[2] = uv - float2 (_MainTex_TexelSize.x * 1.0 , 0.0) * _BlurSize;o.uv[3] = uv + float2 (_MainTex_TexelSize.x * 2.0 , 0.0) * _BlurSize;o.uv[4] = uv - float2 (_MainTex_TexelSize.x * 2.0 , 0.0) * _BlurSize;return o;}//定义两个pass公用的片元着色器 fixed4 fragBlur (v2fBlur i) : SV_Target{float weight [3] = {0.4026, 0.2442, 0.0545};fixed3 sum = tex2D (_MainTex,i.uv[0]).rgb * weight[0];for (int j = 1; j<3; j++ ){sum += tex2D(_MainTex,i.uv[j*2-1]).rgb * weight[j];sum += tex2D(_MainTex,i.uv[j*2]).rgb * weight[j];}return fixed4 (sum,1.0);}///混合亮部图像和原图像时使用的 顶点.片元 着色器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_TOPif (_MainTex_TexelSize.y < 0.0)o.uv.w = 1.0 - o.uv.w;#endifreturn o;}fixed4 fragBloom (v2fBloom i):SV_Target{return tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom,i.uv.zw);}ENDCGZTest Always Cull Off ZWrite Off pass { CGPROGRAM#pragma vertex vertExtractBright#pragma fragment fragExtractBrightENDCG}pass {CGPROGRAM#pragma vertex vertBlurV#pragma fragment fragBlurENDCG}pass {CGPROGRAM#pragma vertex vertBlurH#pragma fragment fragBlurENDCG}pass {CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloomENDCG}}FallBack Off }