FXAA3の組み込み

FXAA

スクリーンスペースのアンチエイリアスの処理として,NVIDIAのFXAAが有名です。
ソースはNVIDIAのGameWorksのサンプルにあります。

https://developer.nvidia.com/gameworks-directx-samples

現在FXAAのバージョンは3.11のようで,FXAAの3系はマクロによって,スケーラブルにクォリティを決定できます。
細かい実装は把握していませんが,テクスチャの輝度情報からエッジを検出し,エッジ部分をボカすような事を行っているような気がします。

何よりも,1パスで手軽にそれなりのアンチエイリアスが掛けられるのが利点かと思います。 ちなみに,UnityのPost Processing StackもFXAAでアンチエイリアスを掛けているようです。

FXAAの組み込み

まず,NVIDIAのGameWorksを落としてきて,FXAA.hlslのサンプルコードを持ってきます。 FXAA.hlslのコメントにかかれている通りに組み込めば良いだけですが輝度について,少しだけ修正を行いました。

FXAA.hlslの725行目付近に以下のような定義があります。

#if (FXAA_GREEN_AS_LUMA == 0)
    FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; }
#else
    FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; }
#endif   

FXAA_GREEN_AS_LUMAマクロによって,テクスチャのどの成分を輝度値とみなすかを切り替える関数ですが, 輝度値をAlpha成分に格納したり,G成分で代用するよりも,直接輝度の計算を行うべきかと思ったので,内積計算に置き換えます。

FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return dot(rgba.rgb, float3(0.298912f, 0.586611f, 0.114478f)); }

あとは,以下のようにピクセルシェーダーのパスに組み込めば,FXAAを利用する準備ができました。

#define FXAA_PC 1
#define FXAA_HLSL_5 1
//#define FXAA_QUALITY__PRESET 12
#include "FXAA.hlsl"

#define    PIXEL_SIZE g_aTemp[0].xy
#define    SUBPIX g_aTemp[1].x
#define    EDGE_THRESHOLD g_aTemp[1].y
#define    EDGE_THRESHOLD_MIN g_aTemp[1].z

float4 PS_FXAA3(PPFX_OUT In) : SV_TARGET0
{
    float2 uv = In.UV.xy;
    FxaaTex InputFXAATex = { g_LinearSampler, g_SrcTexture };
    return FxaaPixelShader(
        uv,                         // FxaaFloat2 pos,
        FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f),     // FxaaFloat4 fxaaConsolePosPos,
        InputFXAATex,                   // FxaaTex tex,
        InputFXAATex,                   // FxaaTex fxaaConsole360TexExpBiasNegOne,
        InputFXAATex,                   // FxaaTex fxaaConsole360TexExpBiasNegTwo,
        PIXEL_SIZE,                 // FxaaFloat2 fxaaQualityRcpFrame,
        FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f),     // FxaaFloat4 fxaaConsoleRcpFrameOpt,
        FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f),     // FxaaFloat4 fxaaConsoleRcpFrameOpt2,
        FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f),     // FxaaFloat4 fxaaConsole360RcpFrameOpt2,
        SUBPIX,                     // FxaaFloat fxaaQualitySubpix,
        EDGE_THRESHOLD,             // FxaaFloat fxaaQualityEdgeThreshold,
        EDGE_THRESHOLD_MIN,         // FxaaFloat fxaaQualityEdgeThresholdMin,
        0.0f,                          // FxaaFloat fxaaConsoleEdgeSharpness,
        0.0f,                          // FxaaFloat fxaaConsoleEdgeThreshold,
        0.0f,                          // FxaaFloat fxaaConsoleEdgeThresholdMin,
        FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f)      // FxaaFloat fxaaConsole360ConstDir,
    );
}

PS3とか,Xbox360のコンソール機向けのパラメータがありますが,基本的に0.0で問題ないと思います。

結果

FXAA_QUALITY__PRESET=12として,FXAAをかけた結果です。

f:id:hikita12312:20171216155643p:plain:w300
FXAA OFF
f:id:hikita12312:20171216155701p:plain:w300
FXAA ON

拡大すると分かりやすい気がします。

f:id:hikita12312:20171216155806p:plain:w600

GPU実行時間は,GTX970の環境で1280x720サイズのテクスチャで.0.15ms程度でした。 FXAA_QUALITY__PRESETを高品質のもの(39とか)にすると,さらに負荷はかかりますが,少しキレイになります。