スクリーンスペースデリバティブを使用して、ピクセルシェーダーでパラメトリック形状をアンチエイリアスするにはどうすればよいですか?


8

バルブのアルファテスト済み倍率紙、それはアンチエイリアシングを行うための「ピクセル単位のスクリーン空間誘導体」を使用して言及しています。私の理解では、これがあることであるddxddyHLSLでの組み込み関数?

シェーダーでパラメトリックシェイプ(たとえば、円:x²+y²<1)を描画しようとしていますが、このテクニックを使用して、シェイプのエッジピクセルを正しくアンチエイリアスする方法がわかりません。誰かが例を提供できますか?

完全を期すために、私が作成している種類のピクセルシェーダーの例を次に示します。

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float dist = input.TexCoord.x * input.TexCoord.x
               + input.TexCoord.y * input.TexCoord.y;
    if(dist < 1)
        return float4(0, 0, 0, 1);
    else
        return float4(1, 1, 1, 1);
}

回答:


10

たとえば、距離のステップ関数があり、完全にハードな(エイリアスされた)エッジが生成されます。円をアンチエイリアスする簡単な方法は、それを次のようにソフトしきい値に変えることです。

float distFromEdge = 1.0 - dist;  // positive when inside the circle
float thresholdWidth = 0.01;  // a constant you'd tune to get the right level of softness
float antialiasedCircle = saturate((distFromEdge / thresholdWidth) + 0.5);
return lerp(outsideColor, insideColor, antialiasedCircle);

ここでは、ソフトしきい値関数にクランプされた線形ランプを使用しましたが、smoothstep他のものを使用することもできます。+ 0.5エッジの数学的な位置にランプをセンタリングすることです。とにかく、重要なのは、この関数が一定の範囲の距離からoutsideColorに滑らかに変化することです。そのため、適切にinsideColor選択thresholdWidthすると、アンチエイリアスのように見えるエッジが得られます。

しかし、どのように選ぶべきですかthresholdWidth?小さすぎると再びエイリアシングが発生し、大きすぎるとエッジが過度にぼやけてしまいます。さらに、それは一般にカメラの位置に依存します。distワールド空間またはテクスチャ空間の単位で測定された場合thresholdWidth、あるカメラ位置で機能するは別のカメラ位置では機能しません。

ここで、画面空間の導関数が登場します(そうです、それらは、あなたが推測したとおりのddxおよびddy関数です)。グラデーションの長さを計算するdistことで、画面空間でのグラデーションの変化の速さを把握し、それを使用してを推定できますthresholdWidth

float derivX = ddx(distFromEdge);
float derivY = ddy(distFromEdge);
float gradientLength = length(float2(derivX, derivY));
float thresholdWidth = 2.0 * gradientLength;  // the 2.0 is a constant you can tune

希望のレベルの柔らかさになるように調整できる値はまだありますが、カメラの位置に関係なく一貫した結果が得られるはずです。


良い答え-コードはうまく機能します。+1して受け入れました。しかし、あなたの答えを拡張して、なぜこれが機能するのを説明するのは難しいでしょうか?私は何derivXderivY実際に表現するかについて少し混乱しています。
アンドリューラッセル

@AndrewRussell微積分学のように、導関数に精通していますか? derivXおよびderivYは、画面空間xおよびyに関して、ddxand ddyに渡す式の偏導関数(の近似)です。微積分を勉強していないのであれば、ここで説明するよりも大きなトピックです。:)
ネイサンリード

私の微積分学は少し錆びています-私は行って微分とは何かを再学習しなければなりませんでした。しかし、そこからは理解できたと思います。ありがとう:)
アンドリュー・ラッセル

OpenGLはddx / ddyをサポートしていないため、これらのケースでは、基本的に事前計算されたテクスチャを使用して使用されるミップマップレベルを特定し、ddx / ddyを概算するこのhttp.developer.nvidia.com/GPUGems/gpugems_ch25.htmlが必要になる場合があります。
Runonthespot 2013

2
@Runonthespot OpenGLには派生物があります。それらは別の名前で呼ばれます:dFdx/のdFdy代わりにddx/ ddy
Nathan Reed
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.