Unity カスタム後処理 - ブルーム効果

皆さんこんにちは、趙です。
  画面の後処理効果の紹介に引き続き、今回はブルーム効果についてお話します。

1. ブルーム効果の概要

ここに画像の説明を挿入

または、このモデルを背景として使用します。
ここに画像の説明を挿入

ブルーム効果はフルスクリーンのフラッドライト効果で、モデルや特殊効果が本当に輝いているように感じられます。

ここに画像の説明を挿入
ここに画像の説明を挿入

さまざまなパラメータに従って、さまざまな照明効果を作成できます。

2. 原理の紹介

  ぼかし効果を紹介する前に述べたように、ブルーム効果もぼかし効果に基づいています。
  ブルームの原理は非常に単純で、まずぼかし処理を行ってぼかした画像を計算し、その画像のRGBを元の画面画像のRGBに加算します。RGBカラーの重ね合わせにより、絵の色が白に近いほど爆発しやすくなるため、白に近いほど光る感じがより顕著になります。ブルームの効果をより爆発的にしたい場合は、ぼかした画像を自分でさらに加工することもできますが、最も一般的な方法は、乗算してから加算するか、パワーを加算してから加算することです。
ここに画像の説明を挿入

実装は非常に簡単で、元のブラー効果コードの上に、重ね合わせたシェーダーを追加する必要があります。

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 のアルゴリズムは非常に単純で、最初に元の画像の 3 つの 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;
}

この値を通じて、ライトの範囲をより適切に制御できます
3. ソースコード
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.シェーダー
  ファジィシェーダーは繰り返しません 前回の記事を参照してください
BloomとBrightRangeのシェーダーです
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.ブライトレンジ

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
        }
    }
}

おすすめ

転載: blog.csdn.net/liweizhao/article/details/131882315