2025/07/27 22:21 Perfecting anti-aliasing on signed distance functions

やあ、ロボ子!今日はSDF(Signed Distance Function)を使ったアンチエイリアシングについて話すのじゃ。

SDFですか、博士。形状の符号付き距離を返す関数ですね。それがアンチエイリアシングにどう役立つんですか?

SDFの勾配の長さが1というのがミソなのじゃ!これによって、形状への滑らかな移行が可能になるのじゃよ。

なるほど。それで、linearstep関数を使って透明度を調整するんですね。`h = clamp(0.5 + d/w, 0.0, 1.0)`という式で。

そうそう!`d`は符号付き距離、`w`はランプの幅じゃ。ここで重要なのは、ピクセルサイズがアンチエイリアシングに大きく影響するということじゃ。

ピクセルサイズですか。画面座標を`p = (gl_FragCoord.xy - resolution) / resolution.xy`で計算する場合、`w = 2.0 / resolution.x`または`w = 2.0 / resolution.y`が単位幅になるんですね。

その通り!でも、3D環境で解像度が利用できない場合や、2D SDFを3D平面にマッピングする場合はどうする?

数値微分、`fwidth(d)`が有効なんですね。これを使うと、パースペクティブに関係なく滑らかなアンチエイリアシングが可能になる、と。

`fwidth(d)`は符号付き距離の変化率を計算して、ピクセル単位での滑らかな移行を実現するのじゃ。賢い!

さらに、`fwidth`の代わりにL2ノルム(`sqrt(pow(dFdx(d), 2) + pow(dFdy(d), 2))`)を使うこともできるんですね。

そうじゃ!そして、linearstepの代わりにsmoothstepを使うと、もっと自然な見た目になるのじゃ。

smoothstepは組み込み関数で、linearstepよりも優れた結果を提供してくれるんですね。

色のブレンドにはOkLabカラースペースが推奨されるけど、アンチエイリアシングにおいては線形ブレンドでも十分なのじゃ。

参考例として、2D/3D対応のリニアランプのコードが紹介されていますね。`h = clamp(0.5 + d/fwidth(d), 0.0, 1.0)`という部分が特に重要ですね。

そうじゃ!あと、ユニット幅推定を用いたアンチエイリアシングも便利じゃぞ。`w = length(vec2(dFdx(d), dFdy(d)))`で幅を計算するのじゃ。

SDFとアンチエイリアシング、奥が深いですね。博士、今日もお勉強になりました!

どういたしまして!最後にロボ子、SDFで一番大事なことは何だと思う?

えーと…符号付き距離を正しく計算すること、でしょうか?

ブー!一番大事なのは、S・D・F!つまり、すっごく・だるい・関数!…って、ロボ子、冗談だぞ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。