こんにちは。
プログラマの中村です。
このブログのアイコンとして自分の写真を使う際に、
無加工だと少し恥ずかしいので加工したいと思います。
今回はそれに用いた手法について書いていきます。
※本来画像の加工等は専用のツールを使うのが普通ですが、面白そうなのでシェーダーを使います。
画像にかける処理について
画像には、
「ぼかし」を表現できるブラーと、
イラスト風に加工できるポスタリゼーションをかけたいと思います。
ブラー
ブラーは画像処理やゲームグラフィックスで頻繁に用いられる処理の1つです。
隣接するピクセルの色の平均をとることで、ぼかされたような画像を作ることができます。
ポスタリゼーション
ポスタリゼーション(ポスタライズ)とは、色を256階調から指定の階調数まで減らすことで、イラスト風に見せる加工です。
一般的に、ポスタライズの処理は以下の式で表せます。
$$out = floor( in * step ) / step$$
inは入力、outは出力、stepは階調数になります。
シェーダーを描く
ブラーについては、単純に中心のピクセルと周辺8ピクセルの平均をとりたいと思います。
実際に実装する場合はガウシアンブラーやバイラテラルフィルタなどを使う場合が多いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
float3 Blur( float2 uv, float2 offset ) { float3 color = 0; for ( int i = -1; i <= 1; i++ ) { for ( int j = -1; j <= 1; j++ ) { color += tex2D( _MainTex, saturate( uv + offset * float2( i, j ) ) ).rgb; } } color /= 9.0; return color; } |
次にポスタリゼーションの処理を書いてきます。
上述の式をそのまま実装すればいいので以下のようになります。
1 2 3 4 5 |
float3 Posterize( float3 x, float step ) { return floor( x * step ) / step; } |
2つを組み込んだ最終的なシェーダーが以下になります。
クリックしてソースコード全文を見る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
Shader "Sample/SampleShader" { Properties { _MainTex( "Texture", 2D ) = "white" {} _PosterizeStep( "Posterize Step", float ) = 255 _BlurSize( "Blur Size", float ) = 1 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert( appdata v ) { v2f o; o.vertex = UnityObjectToClipPos( v.vertex ); o.uv = v.uv; return o; } sampler2D _MainTex; float4 _MainTex_TexelSize; float _PosterizeStep; float _BlurSize; float3 Posterize( float3 x, float step ) { return floor( x * step ) / step; } float3 Blur( float2 uv, float2 offset ) { float3 color = 0; for ( int i = -1; i <= 1; i++ ) { for ( int j = -1; j <= 1; j++ ) { color += tex2D( _MainTex, saturate( uv + offset * float2( i, j ) ) ).rgb; } } color /= 9.0; return color; } float4 frag( v2f IN ) : SV_Target { float2 uv = IN.uv; float2 offset = _MainTex_TexelSize.xy * _BlurSize; float3 color = 0; color = Blur( uv, offset ); color = Posterize( color, _PosterizeStep ); return float4( color.rgb, 1.0 ); } ENDCG } } } |
結果
シェーダーを確認するためにUnityを使用します。
詳細は省略しますが、シェーダーの確認にはUGUIを、画像の出力にはCustom Render Textureを使用しました。
通勤経路で撮った井の頭公園の桜を使って、結果を確認してみます。
無事に元画像の感じを保ちつつ、ぼかせたのではないでしょうか。
まとめ
今回は、シェーダーを使って画像の加工を行ってみました。
画像処理の手法はポストプロセスなどで使用するので、ゲーム開発において重要な技術の1つです。
もちろん、弊社で開発されたゲームでも多用されています。
Unityなどのゲームエンジンを使えば手軽に結果が確認できるので、
興味のある方は試してみてはいかがでしょうか。