Unity自定义后处理——Bloom效果

大家好,我是阿赵。
  继续介绍屏幕后处理效果,这一期讲一下Bloom效果。

一、Bloom效果介绍

Unity自定义后处理——Bloom效果_第1张图片

还是拿这个模型作为背景。
Unity自定义后处理——Bloom效果_第2张图片

Bloom效果,就是一种全屏泛光的效果,让模型和特效有一种真的在发光的感觉。

Unity自定义后处理——Bloom效果_第3张图片
Unity自定义后处理——Bloom效果_第4张图片

根据参数不一样,可以做出不同的发光效果。

二、原理介绍

  之前在介绍模糊效果的时候说过,Bloom效果也是基于模糊效果制作的。
  Bloom的原理很简单,先用模糊处理,算出一张模糊后的图片,然后把这张图片的RGB和原始屏幕图片的RGB相加就可以了。由于是RGB颜色叠加,所以本身图片颜色越接近白色的地方,越容易爆掉,所以越接近白色的地方发光的感觉就越明显。如果想Bloom的效果更爆一点,就自己对模糊后的图片进一步做处理吧,最常见的手段就是先乘后加,或者Power后再相加也可以
Unity自定义后处理——Bloom效果_第5张图片

实现很简单,在原来的模糊效果代码上面,我们应该再加多一个叠加的Shader就可以了。

half4 frag (v2f_img i) : SV_Target
{
    half4 col = tex2D(_MainTex, i.uv);
	half4 brightCol = tex2D(_brightTex, i.uv);
	col.rgb += brightCol.rgb;
    return col;
}

  我这里在处理模糊之前,先加多了一个BrightRange的计算。这是为了控制一下发光的范围。BrightRange的算法很简单,先取原始图片的rgb三个通道颜色值最大的通道的值,然后用这个最大值减去一个我们指定的值。最后把原图的rgb颜色乘以这个值就可以了。

fixed4 frag (v2f_img i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
	float br = max(max(col.r, col.g), col.b);
	br = max(0, (br - _BrightCut)) / max(br, 0.00001);
	col.rgb *= br;
    return col;
}

通过这个值,我们就可以更好的控制发光的范围
三、源码
1、C#部分

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

public class BloomCtrl : MonoBehaviour
{
    private Material blurMat;
    private Material brightMat;
    private Material bloomMat;
    public bool isBlur = false;
    [Range(0, 4)]
    public float blurSize = 0;
    [Range(-3, 3)]
    public float blurOffset = 1;
    [Range(1, 3)]
    public int blurType = 3;
    [Range(0, 1)]
    public float brightCut = 0.5f;
    void Start()
    {

    }


    void Update()
    {

    }

    private Material GetBlurMat(int bType)
    {
        if (bType == 1)
        {
            return new Material(Shader.Find("Hidden/AzhaoBoxBlur"));
        }
        else if (bType == 2)
        {
            return new Material(Shader.Find("Hidden/AzhaoGaussianBlur"));
        }
        else if (bType == 3)
        {
            return new Material(Shader.Find("Hidden/AzhaoKawaseBlur"));
        }
        else
        {
            return null;
        }
    }

    private void ReleaseRT(RenderTexture rt)
    {
        if (rt != null)
        {
            RenderTexture.ReleaseTemporary(rt);
        }
    }

    private bool CheckNeedCreateBlurMat(Material mat, int bType)
    {
        if (mat == null)
        {
            return true;
        }
        if (mat.shader == null)
        {
            return true;
        }
        if (bType == 1)
        {
            if (mat.shader.name != "Hidden/AzhaoBoxBlur")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else if (bType == 2)
        {
            if (mat.shader.name != "Hidden/AzhaoGaussianBlur")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else if (bType == 3)
        {
            if (mat.shader.name != "Hidden/AzhaoKawaseBlur")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    private void BlurFun(RenderTexture source, RenderTexture destination, float blurTime, int bType, float offset)
    {
        if (CheckNeedCreateBlurMat(blurMat, bType) == true)
        {
            blurMat = GetBlurMat(bType);
        }
        if (blurMat == null || blurMat.shader == null || blurMat.shader.isSupported == false)
        {
            return;
        }
        blurMat.SetFloat("_BlurOffset", offset);
        float width = source.width;
        float height = source.height;
        int w = Mathf.FloorToInt(width);
        int h = Mathf.FloorToInt(height);
        RenderTexture rt1 = RenderTexture.GetTemporary(w, h);
        RenderTexture rt2 = RenderTexture.GetTemporary(w, h);
        Graphics.Blit(source, rt1);
        for (int i = 0; i < blurTime; i++)
        {
            ReleaseRT(rt2);
            width = width / 2;
            height = height / 2;
            w = Mathf.FloorToInt(width);
            h = Mathf.FloorToInt(height);
            rt2 = RenderTexture.GetTemporary(w, h);
            Graphics.Blit(rt1, rt2, blurMat, 0);
            width = width / 2;
            height = height / 2;
            w = Mathf.FloorToInt(width);
            h = Mathf.FloorToInt(height);
            ReleaseRT(rt1);
            rt1 = RenderTexture.GetTemporary(w, h);
            Graphics.Blit(rt2, rt1, blurMat, 1);
        }
        for (int i = 0; i < blurTime; i++)
        {
            ReleaseRT(rt2);
            width = width * 2;
            height = height * 2;
            w = Mathf.FloorToInt(width);
            h = Mathf.FloorToInt(height);
            rt2 = RenderTexture.GetTemporary(w, h);
            Graphics.Blit(rt1, rt2, blurMat, 0);
            width = width * 2;
            height = height * 2;
            w = Mathf.FloorToInt(width);
            h = Mathf.FloorToInt(height);
            ReleaseRT(rt1);
            rt1 = RenderTexture.GetTemporary(w, h);
            Graphics.Blit(rt2, rt1, blurMat, 1);
        }
        Graphics.Blit(rt1, destination);
        ReleaseRT(rt1);
        rt1 = null;
        ReleaseRT(rt2);
        rt2 = null;
        return;
    }
    private bool BrightRangeFun(RenderTexture source, RenderTexture destination)
    {
        if (brightMat == null)
        {
            brightMat = new Material(Shader.Find("Hidden/BrightRange"));
        }
        if (brightMat == null || brightMat.shader == null || brightMat.shader.isSupported == false)
        {
            return false;
        }
        brightMat.SetFloat("_BrightCut", brightCut);
        Graphics.Blit(source, destination, brightMat);
        return true;

    }

    private bool BloomAddFun(RenderTexture source, RenderTexture destination, RenderTexture brightTex)
    {
        if (bloomMat == null)
        {
            bloomMat = new Material(Shader.Find("Hidden/AzhaoBloom"));
        }
        if (bloomMat == null || bloomMat.shader == null || bloomMat.shader.isSupported == false)
        {
            return false;
        }
        bloomMat.SetTexture("_brightTex", brightTex);
        Graphics.Blit(source, destination, bloomMat);
        return true;
    }
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (isBlur == true)
        {
            RenderTexture finalRt = source;
            RenderTexture rt2 = RenderTexture.GetTemporary(source.width, source.height);
            RenderTexture rt3 = RenderTexture.GetTemporary(source.width, source.height);
            BrightRangeFun(source, rt2);
            if (blurSize > 0)
            {
                BlurFun(rt2, rt3, blurSize, blurType, blurOffset);
                BloomAddFun(source, finalRt, rt3);
            }
            Graphics.Blit(finalRt, destination);
            ReleaseRT(finalRt);
            ReleaseRT(rt2);
            ReleaseRT(rt3);

        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }
}

2、Shader
  模糊shader就不重复了,参考之前的文章
这里提供一下Bloom和BrightRange的shader
1.Bloom

Shader "Hidden/AzhaoBloom"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_brightTex("BrightTex",2D) = "black"
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"



            sampler2D _MainTex;
		sampler2D _brightTex;

			half4 frag (v2f_img i) : SV_Target
            {
                half4 col = tex2D(_MainTex, i.uv);
				half4 brightCol = tex2D(_brightTex, i.uv);
				col.rgb += brightCol.rgb;
                return col;
            }
            ENDCG
        }
    }
}

2.BrightRange

Shader "Hidden/BrightRange"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_BrightCut("LightVal",Range(0,1)) = 0.5
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"



            sampler2D _MainTex;
			float _BrightCut;

            fixed4 frag (v2f_img i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
				float br = max(max(col.r, col.g), col.b);
				br = max(0, (br - _BrightCut)) / max(br, 0.00001);
				col.rgb *= br;
                return col;
            }
            ENDCG
        }
    }
}

你可能感兴趣的:(Unity屏幕后处理,unity,游戏引擎,Bloom,屏幕后处理)