【MMEの作り方】ポストエフェクト編02/ガウスぼかし
▼今回の記事ページで使うサンプルファイル
今回の記事ぺージの解説で使うサンプルとなるfxファイルは以下のリンクからダウンロードできます。
ただし、ファイルをDL・使用した際にトラブル・不利益が生じたとしても筆者は責任を負わないものとします。自己責任で御利用ください。
▼ぼかし表現はポストエフェクトでよく使う
ポストエフェクト系のMME用ファイルでよく使われる処理として、ぼかし表現があります。
画面全体をそのままぼかす処理のエフェクトもありますし、それだけでなくディフュージョンフィルタや被写界深度のようにぼかしを処理の一部として使っている場合もあります。
つまり、ぼかし表現についてを実装できると作れるポストエフェクトのバリエーションが増えます。
なので、本記事では代表的なぼかし手法である、ガウスぼかしについて解説していきます。
▼ガウスぼかし
ガウスぼかしとはガウス分布を使ったぼかし処理です。
いきなり『ガウス分布』とか難解そうなワードが出て来ましたが、ざっくりいうと釣鐘状のカーブの値を使って画面の色味の強さに強弱をつける処理です。

▼コードの中身
では実際にガウスぼかしを実装するためのコードを見ていきましょう。
サンプルファイル『3-2-1_PE_GaussianBlur.x』をMMD内に割り当ててみてください。
このエフェクトを使うと、以下のように画面全体にぼかし処理を入れることができます。
では、プログラムの中身を見ていきましょう。
■2つのレンダーターゲット
まず、このプログラム内ではスクリーンの映像をテクスチャとして保存しておくための格納庫が2つあります。
それが以下の部分
// オリジナルの描画結果を記録するためのレンダーターゲット
texture ScnMap : RENDERCOLORTARGET <
float2 ViewPortRatio = { 1.0,1.0 };
> ;
sampler ScnSamp = sampler_state {
texture = <ScnMap>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
// ガウスぼかし格納用レンダーターゲット
texture ScnMap2 : RENDERCOLORTARGET <
float2 ViewPortRatio = { 1.0,1.0 };
> ;
sampler ScnSamp2 = sampler_state {
texture = <ScnMap2>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
}; なぜ2つあるかというと、ガウスぼかしを実現するには、
①横軸方向に対してぼかす
②横軸方向をぼかした画像を更に縦軸でぼかす
の2ステップ必要だからです。
つまり、
・元のスクリーン画像
・横軸方向をぼかした画像
という都合2種類の画像を格納するエリアが必要になります。
そのため、上記のように格納用のレンダーターゲットが2つ書かれているのです。
■ガウス分布に基づく重みの値
次に、ガウスぼかしを実装するためにはガウス分布に基づく重みづけの値が必要です。
それが、
static float Weight[15] = {
0.0642,
0.0652,
0.0661,
0.0669,
0.0675,
0.0679,
0.0681,
0.0682,
0.0681,
0.0679,
0.0675,
0.0669,
0.0661,
0.0652,
0.0642,
};
の大量の値が並んでいるエリアです。
よく見ると分かる通り、最初と最後の値、最初から2番目の値と最後から2番目の値…というように同じ値がついになっているペアがあります。
この値をグラフで横並びにプロットしていくとガウス分布の概要で載せたグラフのような釣鐘型の曲線になります。
加えて、この15個の値は全て足すと1になります。
つまり、これらの値を使って15回分画像への重みづけ(要するに画像の色への乗算)を行って、それを全部足し合わせると使用された重みづけの値が1になる。
なので画像処理後の画面全体の明るさは変わらずぼかし処理がされている状態になります。
■2つのピクセルシェーダー
で、これらの値を使ってピクセルシェーダーでガウスぼかしを実現します。
先ほど書いた通り、ガウスぼかしを実装するためには横方向と縦方向の2回に分けてぼかし処理を入れていきます。
なので、ピクセルシェーダーも2つあります。
//--------------------------------------------------------------
// ピクセルシェーダー:横方向ぼかし
//--------------------------------------------------------------
float4 PS_BlurX(float2 Tex : TEXCOORD0) : COLOR0
{
float2 OffsetDir = float2(1.0, 0.0) * (BlurRadius * 0.1 / ViewportSize.x);
float4 BlurColor = float4(0, 0, 0, 1);
for (int i = -7; i <= 7; i++)
{
float4 Color = tex2D(ScnSamp, Tex + OffsetDir*i);
BlurColor += Weight[i + 7] * Color;
}
return BlurColor;
}
//--------------------------------------------------------------
// ピクセルシェーダー:縦方向ぼかし
//--------------------------------------------------------------
float4 PS_BlurY(float2 Tex : TEXCOORD0) : COLOR0
{
float2 OffsetDir = float2(0.0, 1.0) * (BlurRadius * 0.1 / ViewportSize.y);
float4 BlurColor = float4(0, 0, 0, 1);
for (int i = -7; i <= 7; i++)
{
float4 Color = tex2D(ScnSamp, Tex + OffsetDir * i);
BlurColor += Weight[i + 7] * Color;
}
float4 OriginColor = tex2D(ScnSamp, Tex);
float4 ResultColor = lerp(OriginColor, BlurColor, Blend);
return ResultColor;
}これまた色々書いてありますが、それぞれが何をしているのかをコードを図にして解説を書き加えると以下の通り。

■2つのパス
画像に対して何をするのかを意味する設計図であるピクセルシェーダーが2つあるということは、テクニック内のパスも2種類用意する必要があります。
それが以下の部分になります。

【目次ぺージに戻る】
