SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

MikuMikuEffectで学ぶHLSL入門

3DCGツール「MikuMikuDance」のエフェクトを拡張する「MikuMikuEffect」
ポストエフェクトの作成方法

MikuMikuEffectで学ぶHLSL入門(5)

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード sample.zip (10.5 KB)

ぼかしフィルタ

 それでは、ぼかしフィルタ(ガウシアンぼかし)を実装してみましょう。

原理

 ぼかしフィルタでは、図4のように、入力ピクセルの色を周囲に拡散させるような処理を行います。

図4 ぼかし
図4 ぼかし

 これをシェーダ上で実装するには、ピクセルシェーダでピクセルの出力色を計算する際に、そのピクセルの周囲一定距離内のピクセルの色をサンプリングして、それぞれ適当な係数を掛けた合計値を出力色にします(重み付き加算)。

図5 重み付き加算
図5 重み付き加算

 ここでは、この重み係数に図6のようなガウス関数を用います。

図6 ガウス関数
図6 ガウス関数

 また、ぼかし処理は、図7のようにまずX方向にぼかしてから、Y方向にぼかすという2段階に分けて行います。

図7 ぼかし処理2段階
図7 ぼかし処理2段階
補足2 XY分割とガウス関数

 このように本来2次元的なぼかし処理を1次元な処理2回に分割すると、1つのピクセルの色を計算するのに必要なサンプリング回数を大幅に減らすことが出来、高速化することができます。

 例えばぼかしの範囲を縦横10ピクセルとすると、2次元で処理するならば10x10ピクセルの計100ピクセルをサンプリングする作業が必要になりますが、1次元な処理2回に分割すると、10ピクセルのサンプリングを2回行うだけで済むようになります。

 なお、重み係数にガウス関数を用いた場合、その数学的特性により、このように処理をX方向とY方向に分割しても、分割しなかった場合と同様に円形にぼかすことができるという利点があります。

エフェクトファイルの編集

 それでは、BasicPostEffect.fxをベースに、エフェクトファイルを編集していきます。

テクニックの2パス化

 ぼかし処理を、いったんX方向にぼかした後、それを入力としてY方向にぼかす、というように2回に分けて行うため、X方向にぼかした結果を記録するためにレンダリングターゲットのテクスチャがもう一つ必要になります。

図8 ぼかし処理フロー
図8 ぼかし処理フロー

 そのため、以下のようにレンダリングターゲットのテクスチャを2つに増やします。

レンダリングターゲット追加
texture ScnMap : RENDERCOLORTARGET <
    float2 ViewPortRatio = {1.0,1.0};
>;
sampler ScnSamp = sampler_state {
    texture = <ScnMap>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
};

// 以下を追加
texture ScnMap2 : RENDERCOLORTARGET <
    float2 ViewPortRatio = {1.0,1.0};
>;
sampler ScnSamp2 = sampler_state {
    texture = <ScnMap2>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
};

 これに合わせて、ピクセルシェーダもX方向とY方向の処理のものに増やし、名前も変更します。頂点シェーダについては共通で使用するので増やす必要はありません。

シェーダ追加
VS_OUTPUT VS_DrawBuffer( float4 Pos : POSITION, float4 Tex : TEXCOORD0 ){
    VS_OUTPUT Out = (VS_OUTPUT)0; 
    
    Out.Pos = Pos;
    Out.Tex = Tex + ViewportOffset;
    
    return Out;
}

// 関数名を変更
float4 PS_GaussianX(float2 Tex: TEXCOORD0) : COLOR
{   
    float4 Color = tex2D( ScnSamp, Tex );
    
    // 何か処理
    
    return Color;
}

// 以下を追加
float4 PS_GaussianY(float2 Tex: TEXCOORD0) : COLOR
{   
    // 入力するテクスチャをScnMapからScnMap2に変更
    float4 Color = tex2D( ScnSamp2, Tex );
    
    // 何か処理
    
    return Color;
}

 また、テクニックのパスやスクリプトの記述も追加します。

テクニック 改変
technique PostEffect <
    string Script = 
        "RenderColorTarget0=ScnMap;"
        "RenderDepthStencilTarget=DepthBuffer;"
        "ClearSetColor=ClearColor;"
        "ClearSetDepth=ClearDepth;"
        "Clear=Color;"
        "Clear=Depth;"
        "ScriptExternal=Color;"
        
        // 以下を追加
        "RenderColorTarget0=ScnMap2;"
        "RenderDepthStencilTarget=DepthBuffer;"
        "ClearSetColor=ClearColor;"
        "ClearSetDepth=ClearDepth;"
        "Clear=Color;"
        "Clear=Depth;"
        "Pass=GaussianX;"
        
        "RenderColorTarget0=;"
        "RenderDepthStencilTarget=;"
        "Pass=GaussianY;" //パス名を変更
    ;
> {
    // パス名とピクセルシェーダの関数名を変更
    pass GaussianX < string Script= "Draw=Buffer;"; > {
        AlphaBlendEnable = FALSE;
        VertexShader = compile vs_2_0 VS_DrawBuffer();
        PixelShader  = compile ps_2_0 PS_GaussianX();
    }
    // 以下のパスを追加
    pass GaussianY < string Script= "Draw=Buffer;"; > {
           AlphaBlendEnable = FALSE;
           VertexShader = compile vs_2_0 VS_DrawBuffer();
           PixelShader  = compile ps_2_0 PS_GaussianY();
    }
}

 このように記述することで、まずテクスチャScnMapに各オブジェクトが描画され、その後のパスGaussianXの処理結果がテクスチャScnMap2に描画されます。

 この時点ではまだ、実行結果はBasicPostEffect.fxと変化ありません。

次のページ
ディフュージョンフィルタ

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
MikuMikuEffectで学ぶHLSL入門連載記事一覧

もっと読む

この記事の著者

舞力介入P(ブリョクカイニュウピー)

ニコニコ動画でMMD関連のツール開発者として活動中。代表作は「MikuMikuEffect」。我流のAPI Hookを常套手段とする、邪道プログラマです。ニコニコ動画マイリスト

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6298 2011/12/09 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング