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