Unity: ImageEffectのスクリプトの書き方
Unity5 からフリー版でもImageEffectが使用できるようなりましたね. というわけで,エフェクトを自分で作成する際の基本をメモしておきます.
ImageEffect による画像処理
ImageEffect ととは,cameraから出力される画像(映像)に対して,shaderを当てて処理するものです.
ImageEffect 使用するには,下記のようなスクリプトを用意し,cameraに追加します.
すると,Inspector 上の当該スクリプトの箇所にshader の設定項目がでてきますので,そこに用いたいshader を指定します.
using UnityEngine; [ExecuteInEditMode] public class test : ImageEffect { void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, material); } }
ここで,source: 元のテクスチャ,destination: 出力されるテクスチャです.
上記のスクリプトは,単にカメラから得たテクスチャを shader に渡し,その結果を出力・もしくは後段の処理に引き渡すものです.
出力されるテクスチャを保持する場合
例えば,最初のImageEffectで,ラプラシアンを取得し,後段のImageEffectでそのラプラシアンを使用したい場合,予めAssetにRenderTexture を用意し,そのRenderTextureに書き込むようにします.
public class test : ImageEffect { public RenderTexture rt; void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, rt, material); } }
後段の処理でそのRenderTextureを使用する場合は,そいつを
material.SetTexture("shader上のtexture名", rt);
でshaderに渡してあげます.
シェーダに複数のパスを書いて,特定のパスを実行する
シェーダ内の複数のパスから特定のパスを選んで実行する場合,下記のように第四引数にパスのインデックスを指定します.
material.SetTexture(source, rt, material, 0);
ImageEffectの例
3x3 Gaussian Blur
3x3 ガウシアンブラーの例です.
シェーダ側が完全にべた書きですが,3x3 ならそんなに変わらないだろうということで・・・
考慮する近傍画素数が増えると,x 軸, y 軸を順にブラーかけた方が早いです.
まずは,C#の例から
using UnityEngine; [ExecuteInEditMode] public class GaussianBlur : ImageEffectBase { public int _Width = 1920; public int _Height = 1080; void Start() { material.SetFloat("_OneWidth", 1.0f / _Width); material.SetFloat("_OneHeight", 1.0f / _Height); } void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, material); } }
つづいて,対応するシェーダです.
Shader "Custom/GaussianBulr"
{
Properties
{
_MainTex ("", any) = "" {}
_OneWidth("Width of one pixel", Float) = 0.00052083333
_OneHeight("Height of one pixel", Float) = 0.00092592592
}
CGINCLUDE
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float _OneWidth;
float _OneHeight;
v2f vert( appdata_img v )
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord;
return o;
}
half4 frag(v2f i) : SV_Target
{
half4 color = tex2D(_MainTex, i.uv) / 4;
color += tex2D(_MainTex, half2(i.uv.x, i.uv.y + _OneHeight)) / 8;
color += tex2D(_MainTex, half2(i.uv.x, i.uv.y - _OneHeight)) / 8;
color += tex2D(_MainTex, half2(i.uv.x + _OneWidth, i.uv.y)) / 8;
color += tex2D(_MainTex, half2(i.uv.x - _OneWidth, i.uv.y)) / 8;
color += tex2D(_MainTex, half2(i.uv.x + _OneWidth, i.uv.y + _OneHeight)) / 16;
color += tex2D(_MainTex, half2(i.uv.x + _OneWidth, i.uv.y - _OneHeight)) / 16;
color += tex2D(_MainTex, half2(i.uv.x - _OneWidth, i.uv.y + _OneHeight)) / 16;
color += tex2D(_MainTex, half2(i.uv.x - _OneWidth, i.uv.y - _OneHeight)) / 16;
return color;
}
ENDCG
SubShader
{
Pass {
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
Fallback off
}