グラフィック

シェーダーを使って画像を加工してみた

グラフィック
この記事は約5分で読めます。


こんにちは。
プログラマの中村です。

このブログのアイコンとして自分の写真を使う際に、
無加工だと少し恥ずかしいので加工したいと思います。

今回はそれに用いた手法について書いていきます。

※本来画像の加工等は専用のツールを使うのが普通ですが、面白そうなのでシェーダーを使います。

画像にかける処理について

画像には、
「ぼかし」を表現できるブラーと、
イラスト風に加工できるポスタリゼーションをかけたいと思います。

ブラー

ブラーは画像処理やゲームグラフィックスで頻繁に用いられる処理の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などのゲームエンジンを使えば手軽に結果が確認できるので、
興味のある方は試してみてはいかがでしょうか。

タイトルとURLをコピーしました