返回

Bloom泛光效果

Bloom原理:

大多数情况图像亮度值不会超过1,但是如果我们在摄像机勾选了HDR,则硬件会允许我们把颜色值存储到一个更高精度的范围缓冲中,此时的像素亮度值可能超过1。

我们将颜色值大于1的部分进行提取,然后进行模糊计算。

最后将模糊后的图与原图进行混合,就达到了Bloom泛光效果。

C#代码

#region << 版 本 注 释 >>
/*
*----------------------------------------------------------------
* 类 名 称 :$safeitemname$
* 类 描 述 :
* 命名空间 :$rootnamespace$
* 机器名称 :$machinename$
* 作    者 :狐狸菌
* 创建时间 :$time$
*----------------------------------------------------------------
*
* 备    注 :
* ===============================================================
* 
* ===============================================================
*/
#endregion

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ImageEffectAllowedInSceneView]
public class Bloom : PostEffectsBase
{
    public Shader bloomShader;
    private Material bloomMaterial = null;
    public Material material
    {
        get
        {
            bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);
            return bloomMaterial;
        }
    }

    [Range(0, 4)]
    public int iterations = 3;

    [Range(0.2f, 3.0f)]
    public float blurSpread = 0.6f;

    [Range(1, 8)]
    public int downSample = 2;

    [Range(0f, 4f)]
    public float luminanceThreshold = 1f;


    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material != null)
        {
            material.SetFloat("_LuminanceThreshold", luminanceThreshold);

            int rtW = source.width / downSample;
            int rtH = source.height / downSample;
            //根据屏幕大小创建缓冲区buffer0
            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);

            //纹理的过滤模式
            // FilterMode.Bilinear 对纹理样本求平均值,纹理将变得模糊
            buffer0.filterMode = FilterMode.Bilinear;

            //使用Shader中的第一个Pass提取图像中较亮的部分,存储到buffer0中
            Graphics.Blit(source, buffer0, material, 0);

            for (int i = 0; i < iterations; i++)
            {
                //设置Shader的模糊强度参数
                material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                //第一次创建buffer1
                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                //使用Shader中的第二个Pass对buffer0进行滤波,将结果存储到buffer1
                Graphics.Blit(buffer0, buffer1, material, 1);

                //释放buffer0,然后将buffer1中数据重新保存到buffer0中
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;

                //第二次创建buffer1
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                //使用Shader中的第三个Pass对buffer0进行滤波,将结果存储到buffer1
                Graphics.Blit(buffer0, buffer1, material, 2);

                //释放buffer0,然后将buffer1中数据重新保存到buffer0中
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }
            material.SetTexture("_Bloom", buffer0);
            //使用Shader中的第四个Pass进行混合
            Graphics.Blit(source, destination, material, 3);

            //释放缓冲区
            RenderTexture.ReleaseTemporary(buffer0);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }
}

Shader

Shader "FoxShader/BloomShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" { }
        _Bloom ("Bloom(RGB)", 2D) = "Black" { }
        _LuminanceThreshold ("Luminance Threshold", Float) = 0.5
        _BlurSize ("Blur Size", Float) = 1.0
    }
    
    //-------------------------CG着色语言声明部分 || Begin CG Include Part----------------------
    CGINCLUDE
    sampler2D _MainTex;
    half4 _MainTex_TexelSize;
    sampler2D _Bloom;
    float _LuminanceThreshold;
    float _BlurSize;
    
    #include "UnityCG.cginc"
    //--------------------------------------
    //Pass1
    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;
    }
    //片元着色器代码块
    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);
        //将采集到的亮度值减去阈值,并把结果截取到0-1范围内
        //luminance用于获取图像亮度
        fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);
        //将结果与原来部分相乘,得到亮部区域
        return c * val;
    }
    //-------------------------------
    //Pass2
    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_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
    
    //----------------------------------【子着色器 || SubShader】---------------------------------------
    SubShader
    {
        // Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True" "CanUseSpriteAtlas" = "True" "PreviewType" = "Plane" }
        ZWrite Off ZTest Always Cull Off
        //提取过亮部分
        Pass
        {
            CGPROGRAM
            
            #pragma vertex vertExtractBright
            #pragma fragment fragExtractBright
            
            ENDCG
            
        }
        //引用双重模糊Pass
        UsePass "FoxShader/DualKawaseBlur/GAUSSIAN_BLUR_VERTICAL"
        UsePass "FoxShader/DualKawaseBlur/GAUSSIAN_BLUR_HORIZONTAL"
        //混合模糊后图像与原图
        Pass
        {
            
            CGPROGRAM
            
            #pragma vertex vertBloom
            #pragma fragment fragBloom
            
            ENDCG
            
        }
    }
    Fallback off
}

Licensed under CC BY-NC-SA 4.0
0