using
UnityEngine;
using
UnityEngine.UI;
[ExecuteAlways]
/// <summary>
/// Blurを2Passを使って効率化するためのクラス
/// </summary>
public
class
BoxBlur2PassController
:
MonoBehaviour
{
[SerializeField]
private
Image
targetImage;
[SerializeField]
private
Shader
targetShader;
[SerializeField,
Range(0,
20)]
private
int
blurCount
=
0;
[SerializeField,
Range(1,
10)]
private
float
blurDistance
=
2;
private
Texture2D
sourceTexture;
private
Material
createdMaterial;
private
RenderTexture
tmpRenderTexture;
//変更があったときだけ更新するためのキャッシュ
private
int
_lastBlurCount;
private
float
_lastBlurDistance;
/// <summary>
/// 初期化処理の必要性がある場合trueを返す
/// </summary>
private
bool
NeedsInitialization
=>
sourceTexture
==
null
||
sourceTexture
!=
targetImage.sprite.texture
||
createdMaterial
==
null
||
targetImage.material
!=
createdMaterial
||
tmpRenderTexture
==
null;
/// <summary>
/// インスペクターのパラメータに変化があったかチェック
/// </summary>
private
bool
CahngedParameter
=>
blurCount
!=
_lastBlurCount
||
!Mathf.Approximately(blurDistance,
_lastBlurDistance);
/// <summary>
/// 初期化処理
/// </summary>
private
void
Init()
{
Release();
sourceTexture
=
targetImage.sprite.texture;
createdMaterial
=
new
(targetShader);
createdMaterial.hideFlags
=
HideFlags.DontSave;
targetImage.material
=
createdMaterial;
//処理負荷軽減のため、大元の画像サイズから1/2のサイズでtmpRenderTextureを作成
//tmpRenderTextureはぼかし処理のための画像なので、サイズが小さくても見た目に違和感は出ない
tmpRenderTexture
=
new
RenderTexture(sourceTexture.width
/
2,
sourceTexture.height
/2,
0);
//事前にBlitで更新される予定のtmpRenderTextureを、_CustomTexの名前でシェーダー側と紐づけておく
//後はCanvasRender内の処理で自動的にPass0を実行させて、その_CustomTexを画像に反映させる
targetImage.material.SetTexture("_CustomTex",
tmpRenderTexture);
//初期化後は問答無用でUpdateTextureを呼ぶ
UpdateTexture();
}
/// <summary>
/// 最初にUnityが1回だけ呼ぶ処理
/// </summary>
private
void
Start()
{
if
(NeedsInitialization)
{
Init();
}
}
/// <summary>
/// Unityから毎フレーム呼ばれる処理
/// </summary>
private
void
Update()
{
if
(targetImage
==
null
||
targetImage.sprite
==
null
||
targetShader
==
null)
{
return;
}
if
(NeedsInitialization)
{
Init();
}
else
if(CahngedParameter)
{
UpdateTexture();
}
}
/// <summary>
/// 対象のシェーダーの2Passを実行させる
/// </summary>
private
void
UpdateTexture()
{
_lastBlurCount
=
blurCount;
_lastBlurDistance
=
blurDistance;
//Blur設定をセット
createdMaterial.SetInt("_BlurCount",
blurCount);
createdMaterial.SetFloat("_BlurDistance",
blurDistance);
//第1引数の画像を元に、Blitでシェーダー内のPass1を実行させ、結果を第2引数に書き込む
//Blitの仕様上、この書き込み処理は、第3引数のMaterial内の_MainTexを通して行われる
Graphics.Blit(sourceTexture,
tmpRenderTexture,
createdMaterial,
1);
}
/// <summary>
/// 作成したRenderTextureやMaterialのメモリを解放する
/// </summary>
private
void
Release()
{
if
(tmpRenderTexture
!=
null)
{
tmpRenderTexture.Release();
}
if
(createdMaterial
!=
null)
{
DestroyImmediate(createdMaterial);
}
}
/// <summary>
/// このGameObjectを非表示にした時の処理
/// </summary>
private
void
OnDisable()
{
Release();
}
}