ラジアルブラー!

あらすじ:ラジアルブラーのソース載せます

さーて、仕事が2年目に突入して少しだけ時間に余裕が出来る様になりました。ここぞとばかりにMMEやりましょうかね。

ラジアルブラーについて。

説明は要らないかもしれないけど自分の為にちょい説明を。ラジアルってのは放射状っていう意味で、ラジアルブラーって言うのは放射状にブラー(ぼかし)をかける手法のこと。どうやって放射状にするかというと、ある中心点Cを決めて現在の座標PとのベクトルPCを方向ベクトルにします。この方向ベクトル上で色を拾ってボカシをかけてあげるとラジアルブラーの出来上がり。

他に注意する点は

  • パラメータは方向ベクトルを伸ばしたり縮めたりするPower
  • 自分に近い色の要素を強く拾ってくるように重みをかける
    • 合計が1にならないと色が減ったり増えたりしちゃうので注意
    • ガウシアンブラーの重みをつかうのがベター

位ですかね。

ソース

//===================================================================
// ラジアルブラー
//===================================================================

//===================================================================
// 定数・定義
//===================================================================

//-------------------------------------
// パラメータ:ブラーパワー
// 個人的に弱20.0f,中30.0f,強50.0f
//-------------------------------------
float blur_power = 20.0f;


//-------------------------------------
//-------------------------------------
float Script : STANDARDSGLOBAL <
    string ScriptOutput = "color";
    string ScriptClass = "scene";
    string ScriptOrder = "postprocess";
> = 0.8;

//-------------------------------------
// スクリーンサイズ
//-------------------------------------
float2 ViewportSize : VIEWPORTPIXELSIZE;
static float2 ViewportOffset = (float2(0.5,0.5)/ViewportSize);
//-------------------------------------
// レンダリングターゲットのクリア値
//-------------------------------------
float4 ClearColor = {1,1,1,1};
float ClearDepth  = 1.0;


//-------------------------------------------------------------------
// レンダーターゲット・テクスチャ
//-------------------------------------------------------------------

//-------------------------------------
// オリジナルの描画結果を記録するためのレンダーターゲット
//-------------------------------------
texture2D ScnMap : RENDERCOLORTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    int MipLevels = 1;
    string Format = "A8R8G8B8" ;
>;
sampler2D ScnSamp = sampler_state {
    texture = <ScnMap>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU  = CLAMP;
    AddressV = CLAMP;
};


//-------------------------------------
// デプスバッファー
//-------------------------------------
texture2D DepthBuffer : RENDERDEPTHSTENCILTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    string Format = "D24S8";
>;

//===================================================================
// 構造体
//===================================================================

//-------------------------------------
// VS->PS
//-------------------------------------
struct VS_OUTPUT {
    float4 Pos      : POSITION;
  float2 Tex      : TEXCOORD0;
};

//===================================================================
// 頂点シェーダ
//===================================================================
VS_OUTPUT VS( float4 Pos : POSITION, float4 Tex : TEXCOORD0 ) {
    VS_OUTPUT Out = (VS_OUTPUT)0; 

    Out.Pos = Pos;
    Out.Tex = Tex + float2(0, ViewportOffset.y);
    return Out;
}


//===================================================================
// ピクセルシェーダ
//===================================================================

//-------------------------------------
// ラジアルフィルタ
//-------------------------------------
float4 PS_Radial(
  float2 Tex: TEXCOORD0
  ) : COLOR 
{

  float4 color[10];
  float2 center = float2( 0.5f, 0.5f );
  float2 dir = center - Tex;
  float len = length( dir );
  float2 offset = normalize( dir ) * ViewportOffset;
  offset *= ( blur_power * len );

  // ( シーンのテクスチャ,座標+オフセット )*ガウシアンウェイト
  color[0] = tex2D( ScnSamp, Tex                 ) * 0.19f;
  color[1] = tex2D( ScnSamp, Tex + offset        ) * 0.17f;
  color[2] = tex2D( ScnSamp, Tex + offset * 2.0f ) * 0.15f;
  color[3] = tex2D( ScnSamp, Tex + offset * 3.0f ) * 0.13f;
  color[4] = tex2D( ScnSamp, Tex + offset * 4.0f ) * 0.11f;
  color[5] = tex2D( ScnSamp, Tex + offset * 5.0f ) * 0.09f;
  color[6] = tex2D( ScnSamp, Tex + offset * 6.0f ) * 0.07f;
  color[7] = tex2D( ScnSamp, Tex + offset * 7.0f ) * 0.05f;
  color[8] = tex2D( ScnSamp, Tex + offset * 8.0f ) * 0.03f;
  color[9] = tex2D( ScnSamp, Tex + offset * 9.0f ) * 0.01f;

  float4 Color = float4( 0.0f, 0.0f, 0.0f, 0.0f );
  Color = (  color[0] + color[1] + color[2] + color[3] + color[4]
           + color[5] + color[6] + color[7] + color[8] + color[9] );
  return Color;
}

//===================================================================
// テクニック指定
//===================================================================

//-------------------------------------
// ガウシアン1回描画
//-------------------------------------
technique Radial <
  string Script = 

    "RenderColorTarget0=ScnMap;"
    "RenderDepthStencilTarget=DepthBuffer;"
      "ClearSetColor=ClearColor;"
      "ClearSetDepth=ClearDepth;"
      "Clear=Color;"
      "Clear=Depth;"
    
    "ScriptExternal=Color;"
    
    "RenderColorTarget0=;"
      "RenderDepthStencilTarget=;"
      "ClearSetColor=ClearColor;"
      "ClearSetDepth=ClearDepth;"
      "Clear=Color;"
      "Clear=Depth;"
      "Pass=Radial;"

    ;
> {
    pass Radial < string Script= "Draw=Buffer;"; > {
        AlphaBlendEnable = FALSE;
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS_Radial();
    } 
}

//==============================[EOF]==============================//

複数回かける?

そもそも、方向ベクトルに沿って離散的に色を拾うので、ガビガビになります。ガビガビにならないようにするには離散的にならないように方向ベクトルを縮めると考えますが、それだと本当にただボケただけになります。
広い範囲でボカしつつガビガビにならないようにするには同じ事を数回やってガビガビ自体をボカしつつ広範囲に影響が行くようにします。経験的に、ブラーPowerを毎回変えてかけると綺麗になります。
上記のソースのPowerだけをかえたラジアルブラーに名前をつけて複数回かけてみたりしたのが以下です。

ブラーなし

ブラー1回(Power=20.0f)

ブラー2回(Power=20.0f,30.0f)

ブラー3回(Power=20.0f,30.0f,50.0f)

アクセサリで複数回読み込むだけでokです。

今後の展開

  • 最初っから複数回かけたラジアルブラーを作成する
  • ゲームみたいにうにょん!って発生させる
  • ラジアルブラー卒業してSSAOやる

まあ、複数回かけたソースあげろよって話だけど、まだソースが汚いのでこれまた今度w
MMDには使う用途がないかもしれないですが、動的なラジアルブラーが見たいんですよ。ゲームで使ってるような。今のラジアルだと静的なんですよね。ちょうどクリックに反応するものがあったので、押してからカウンタを進める作りにすれば多分ゲームみたいに発生させることが出来るんじゃないかと画策中!

SSAOはやり方が若干まだわかってない…。
そもそもデプステクスチャがあってフェッチ出来ることが自分の中での前提だったのでちょっと悩み中。デプス計算するの自体は簡単なんだけど、そのテクスチャを他の演算にもってこれるのか?という悩みです。一回シーンを書きつつデプスをテクスチャに保存してそれからフィルター処理すればいいのはわかってるんだが、MMEでそれをどうやれば出来るのかがわかってないのです。。。まあリファレンス嫁って話ですね^p^

ただ、このソース(サンプルのガウンシアンブラーが元になってる)に、

//-------------------------------------
// デプスバッファー
//-------------------------------------
texture2D DepthBuffer : RENDERDEPTHSTENCILTARGET <
    float2 ViewPortRatio = {1.0,1.0};
    string Format = "D24S8";
>;
とか記述があって、あれ?もしかして?状態なのは内緒。

まあ、気まぐれなので何からアップするかは気分しだいって事で!
それではまたの機会をお待ちください!