レンズゴーストの実装

レンズゴースト

レンズゴーストを実装します。
レンズゴーストはブルームと違って,レンズ内部で反射を繰り返した光がハッキリと像となって写り込んだものです。

http://av.jpn.support.panasonic.com/support/dsc/knowhow/knowhow15.html

今回は以下のサイトの実装を参考にしました。

http://john-chapman-graphics.blogspot.jp/2013/02/pseudo-lens-flare.html

実装

実装のアイディア自体は非常に簡単です。

f:id:hikita12312:20171208165214p:plain:w400

光源となるテクスチャを用意して,画面中心に対して点対称となるようにテクスチャをフェッチすれば,レンズゴーストになります。 このときに,フェッチする回数を増やしたり,カラースケールを変更することでレンズゴーストっぽくなります。 HLSLのコードは以下のような感じになりました。

Texture2D g_SrcTexture : register(t0);
SamplerState g_LinearSampler : register(s0);

#define DISPERSION_SCALE g_aTemp[0].x
#define DISPERSION_OFFSET g_aTemp[0].y
#define GHOST_MASK_RADIUS g_aTemp[0].z
#define GHOST_MASK_FADE g_aTemp[0].w
#define GHOST_COLOR(index) g_aTemp[(index)%4+1].xyz
static const float2 CENTER = float2(0.5f, 0.5f);

float4 PS_Create(PPFX_OUT In) : SV_TARGET0
{
    float4 outColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
    const float2 uv = In.UV.xy;
    const float2 ghostBaseUV = float2(1.0f, 1.0f) - uv;
    const float2 toCenterVec = (CENTER - ghostBaseUV) * DISPERSION_SCALE;
    for (uint index = 0; index < ITERATION_NUM; ++index)
    {
        const float2 ghostUV = ghostBaseUV + toCenterVec * (DISPERSION_OFFSET + index);
        float3 ghostColor = SampleLod0(g_SrcTexture, g_LinearSampler, ghostUV).rgb;

        const float r = length(CENTER - ghostUV);
        const float fadeoutR = (r - GHOST_MASK_RADIUS);
        const float weight =
            (r / length(CENTER)) // 光源が重なったときに極端に明るくさせない重み
            * (1.0f - smoothstep(0.0f, GHOST_MASK_FADE, r - GHOST_MASK_RADIUS)) // 外周をフェードアウトさせる重み
            ;
        outColor.rgb += ghostColor * GHOST_COLOR(index) * weight;
    }

    return outColor;
}

フェッチするマスクのフェードアウト項

     const float weight =
            (r / length(CENTER)) // 光源が重なったときに極端に明るくさせない重み
            * (1.0f - smoothstep(0.0f, GHOST_MASK_FADE, r - GHOST_MASK_RADIUS)) // 外周をフェードアウトさせる重み
            ;

画面の端のほうもフェッチすると,画面の境界で見切れてしまった像が映ってしまうので,端に行くほど滑らかにフェードアウトさせる重みを与えます。 また,画面中心に光源が存在する場合は,中央がとても明るくなってしまうので,適当に減衰させています。

パスの繰り返し
このシェーダーのITERATION_NUMを増やせばゴーストの像はたくさん作られますが,数十回もループさせると負荷が心配です。 そこで,このシェーダーの適用結果を入力にして,繰り返して適用することで,ピンポンブラー的にフェッチ数を増やすことが出来ます。 ITERATION_NUM=8のパスを2回繰り返せば64個のゴーストが生成されます。 また,繰り返すことでゴーストの色合いを作るマスクも繰り返し適用されるので,複雑な色合いも表現できます。

適用結果

f:id:hikita12312:20171208170719p:plain:w600

f:id:hikita12312:20171208170747g:plain

高速化の為に,ブルーム効果のフィルタ1レベル目のブラー結果を入力として,ゴースト用のテクスチャは1/4サイズの縮小バッファを利用しています。 像がハッキリと出るタイプのゴーストではないですが,まあまあキレイに適用できている気がします。