たとえば、距離のステップ関数があり、完全にハードな(エイリアスされた)エッジが生成されます。円をアンチエイリアスする簡単な方法は、それを次のようにソフトしきい値に変えることです。
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
希望のレベルの柔らかさになるように調整できる値はまだありますが、カメラの位置に関係なく一貫した結果が得られるはずです。
derivX
をderivY
実際に表現するかについて少し混乱しています。