[UnityShader入门精要读书笔记]30.Bloom效果

       Bloom特效是游戏中常见的一种屏幕效果。这种特效可以模拟真实摄像机的一种图像效果,它让画面中较亮的区域“扩散”到周围的区域中,造成一种“朦胧”的效果。Bloom的实现原理非常简单:首选根据一个阈值提取出图像中的较亮区域,把它们存储在一张渲染纹理中,再利用高斯模糊对这张渲染纹理进行模糊处理,模拟光线扩散的效果,最后再将其和原图像进行混合,得到最终的效果。

C#代码:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class Bloom : PostEffectBase {

    public Shader bloomShader;

    private Material bloomMaterial = null;

 

    public Material material

    {

        get

        {

            bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);

            return bloomMaterial;

        }

    }

    [Range(0,4)]

    public int iterations = 3;

 

    //blurSpread和downSample都是出于性能考虑,在高斯核维数不变的情况下,_BlurSize越大,模糊程度越高,但采样数却不会受到影响。但过道的_BlurSize值会造成虚影。而downSample越大,需要处理的像素数越少,同事也能进一步提高模糊程序,但过大的downSample可能回事图像像素化。新增了luminanceThreshold来控制提取较亮区域使用阈值大小

    [Range(0.2f, 3.0f)]

    public float blurSpread = 0.6f;

 

    [Range(1, 8)]

    public int downSample = 2;

    //尽管在绝大多数情况下,图像的亮度值不会超过1。但如果我们开启了HDR,硬件会允许我们把颜色值存储在一个更高精度范围的缓冲中,此时像素的亮度值可能会超过1。因此,在这里我们把luminanceThreshold的值规定在[0,4]的范围内。

    [Range(0.0f, 4.0f)]

    public float luminanceThreshold = 0.6f;

 

    void OnRenderImage(RenderTexture src, RenderTexture dest)

    {

        if(material != null)

        {

            //Bloom效果需要3个步骤:首先,提取图像中较量的区域,通过调用Graphics.Blit(src, buffer0, material, 0)来使用Shader中的第一个Pass提取图像中的较亮区域,提取得到的较亮区域将存储在buffer0中。然后,我们进行高斯模糊迭代处理。模糊后的较亮区域存储在buffer0中,此时,我们再把buffer0传递给材质中的_Bloom纹理属性,并调用Graphics.Blit(src,dest,material,3)使用Shader中的第四个Pass来进行最后混合,将结果存储在目标渲染纹理dest中。最后,释放临时缓存。

            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;

            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);

 

                Graphics.Blit(buffer0, buffer1, material, 1);

 

                RenderTexture.ReleaseTemporary(buffer0);

                buffer0 = buffer1;

                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);

 

                Graphics.Blit(buffer0, buffer1, material, 2);

                RenderTexture.ReleaseTemporary(buffer0);

                buffer0 = buffer1;

            }

            material.SetTexture("_Bloom",buffer0);

            Graphics.Blit(src, dest, material, 3);

            RenderTexture.ReleaseTemporary(buffer0);

        }       

        else

        {

            Graphics.Blit(src, dest);           

        }

    }

}

Shader代码:

Shader "Bloom" {

    Properties {

        _MainTex ("Base (RGB)", 2D) = "white" {}

        _Bloom ("Bloom (RGB)", 2D) = "black" {}

        _LuminanceThreshold ("Luminance Threshold", Float) = 0.5

        _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 = mul(UNITY_MATRIX_MVP, v.vertex);

            

            o.uv = v.texcoord;

                     

            return o;

        }

        

        fixed luminance(fixed4 color) {

            return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 

        }

        

        fixed4 fragExtractBright(v2f i) : SV_Target {

            fixed4 c = tex2D(_MainTex, i.uv);

            fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);

            

            return c * val;

        }

        

        struct v2fBloom {

            float4 pos : SV_POSITION; 

            half4 uv : TEXCOORD0;

        };

        

        v2fBloom vertBloom(appdata_img v) {

            v2fBloom o;

            

            o.pos = mul (UNITY_MATRIX_MVP, 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 "GaussianBlur/GAUSSIAN_BLUR_VERTICAL"

        

        UsePass "GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL"

        

        Pass {  

            CGPROGRAM  

            #pragma vertex vertBloom  

            #pragma fragment fragBloom  

            

            ENDCG  

        }

    }

    FallBack Off

}

你可能感兴趣的:([UnityShader入门精要读书笔记]30.Bloom效果)