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 }