こんにちは。
プログラマの中村です。
このブログのアイコンとして自分の写真を使う際に、
無加工だと少し恥ずかしいので加工したいと思います。
今回はそれに用いた手法について書いていきます。
※本来画像の加工等は専用のツールを使うのが普通ですが、面白そうなのでシェーダーを使います。
画像にかける処理について
画像には、
「ぼかし」を表現できるブラーと、
イラスト風に加工できるポスタリゼーションをかけたいと思います。
ブラー
ブラーは画像処理やゲームグラフィックスで頻繁に用いられる処理の1つです。
隣接するピクセルの色の平均をとることで、ぼかされたような画像を作ることができます。
ポスタリゼーション
ポスタリゼーション(ポスタライズ)とは、色を256階調から指定の階調数まで減らすことで、イラスト風に見せる加工です。
一般的に、ポスタライズの処理は以下の式で表せます。
$$out = floor( in * step ) / step$$
inは入力、outは出力、stepは階調数になります。
シェーダーを描く
ブラーについては、単純に中心のピクセルと周辺8ピクセルの平均をとりたいと思います。
実際に実装する場合はガウシアンブラーやバイラテラルフィルタなどを使う場合が多いです。
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;
}
次にポスタリゼーションの処理を書いてきます。
上述の式をそのまま実装すればいいので以下のようになります。
float3 Posterize( float3 x, float step )
{
return floor( x * step ) / step;
}
2つを組み込んだ最終的なシェーダーが以下になります。
クリックしてソースコード全文を見る
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などのゲームエンジンを使えば手軽に結果が確認できるので、
興味のある方は試してみてはいかがでしょうか。