Skip to content
Go back

Distance-to-edge AA (DEAA)

· Updated:

url

拙訳

結果(Results)

上段が元画像であり、下段がアンチエイリアスした結果である。

このアンチエイリアシング手法はMLAAやポストプロセスとして処理する他のすべてのアンチエイリアシングエフェクトと同じファミリーの一部である。我々が取っているこのアプローチはbeautyパス中にピクセルシェーダでエッジまでの距離を計算して、その色と一緒にブラーヒントを書き出すことである。このテクニックの大きな利点は、最大256の異なるブラーレベルにより、とても滑らかなエッジを供給し、回転するエッジのcrawlingのようなMLAAテクニックが持つ時間的な問題の多くを避ける能力を持つことである。

これは標準のMLAAとは異なる強みと弱みを持つ。distance-to-edgeは解析的に計算されるので、ピクセルの近傍でのエッジ検索が存在しない。なので、高価な局所検索local-searchステップは完全にスキップされる。対応する欠点は、distance-to-edge情報を格納するためのフレームバッファに追加スペースが必要になることである。8ビットあれば大丈夫だが、32ビットが理想的だろう。

その他2、3つ欠点を持つが、それは取り扱おうと思う。

我々はAPBにそれを適用することを調査した。我々が直面する問題を入念に調査する。明白な質問は、なぜこれが間に合わなかったのか、ということである。その理由は極めて退屈であるためである。この手法は我々がそれらのコンテンツと共に実行したときに2、3の問題を抱えていた。我々は未だにこれらの問題に取り組んでおり、ローンチのためにアセットを最終的に確定lock downしていたとき、それの統合について考え始める準備が整っていなかった。

エッジへの距離(Distance to edge)

このテクニックの最も重要な部分は、ピクセルシェーダで最も近いトライアングルのエッジへの距離を計算する手法である。なので、そこから始めようと思う。

与えられたトライアングルに対して、頂点プログラムがある頂点でv = 1を、その他の頂点/反対側のエッジでv = 0を出力する場合、補間された値vは大まかにそのエッジからの距離に比例する。

(ννx,ννy)\left( \frac{-\nu}{\frac{\partial \nu}{\partial x}}, \frac{-\nu}{\frac{\partial \nu}{\partial y}} \right)
distance_x = -v / ddx(v)
distance_y = -v / ddy(v)

distance_x = -v / (dv / dx)distance_y = -v / (dv / dy)はスクリーンピクセルでのトライアングルのエッジへの符号付き距離を与える。もしdistance_xが正ならば、トライアングルエッジは現在のピクセルの右側にあり、負ならば、現在のピクセルの左側にある。

この手法はピクセルシェーダが、とても良好な精度で、トライアングルのある特定のエッジへの距離を計算できるようにする。パースペクティブ補正のため、vはトライアングルのいたる所で線形に補間される訳ではなく、計算は厳密な値ではなく推定値をもたらす。

基本のddx/ddyのスクリーン空間のエッジへの距離の計算mathに対する興味深い使い方がたくさんあるが、このトークではそこまで触れないと思う。

ともかく、次のステップは、スキンメッシュや変形メッシュ、プロシージャルに生成されるジオメトリ、こんにちのゲームで見られるその他すべてをサポートする、輪郭の頂点で0を、その他で1を出力する、高速でロバストなコードを頂点プログラムでセットアップすることである。

残念ながら、私はそのようなコードを一切知らない。たくさんの手法で実験したが、選択肢に入るようなロバストかつ高速なものを見つけることはできなかった。私は、すべてのエイリアスしたエッジに対してdistance-to-edgeヒントを書き出し、色の差に基づいてブラーするかどうかをポストプロセスに決めさせる、まったく異なるアプローチを取ることを提案したいと思った。

3つのエッジすべてに対するdistance-to-edgeの値の計算は素直である。vをスカラではなく3要素のベクトルとすることでこれを行う。この画像は色としてベクトルvを示す。3つの頂点のそれぞれである要素が1に、それ以外が0になっている。別の言い方をすれば、トライアングルの各エッジに沿うと、確定でひとつの要素が0になる --- 例えば、画像では、上のエッジは青の要素によって、左のエッジは緑の要素によって暗示される。

故に、我々は現在シェーディングしているピクセルの上下左右の4方向におけるトライアングルのエッジへの距離を計算できる。正確には、方向ごとに3つのトライアングルエッジへの距離を測定し、その3つの値の最小を取る。

恐らくあなたの想像通りに、すべての計算mathはベクトル化でき、完全に分岐なしにできる。

このダイアグラムは描画された大きなトライアングルを示す。黒い線はそのトライアングルのエッジである。線の下のピクセルはトライアングルの内側であり、ラスタライズされる。矢印はトライアングルエッジへの上方向の距離が1ピクセルより小さい所のピクセルを指し示す --- 間もなく明らかになる理由により、1ピクセルより大きい距離について気にしない。

我々は上下左右の4方向の距離の値を計算した。要素あたり8ビットのRGBAレンダターゲットにこれらを格納することは自然な選択である。これはかなり高価な品物である --- これが取引を失敗させるdealbreaker場合には、いくつか他の選択肢がある。

このトライアングルが表面の一部であるならば、黒の線によって示されるエッジのもう一方の側でレンダリングされ、ここに示される下方向の距離の厳密に逆の値である上方向に対するdistance-to-edgeの値を書き出す相補的なトライアングルを期待するだろう。しかし、黒の線が輪郭のエッジであるならば、これは起こらないだろう。そして、相補的なピクセルの距離は任意の値になる。これらのケースはポストプロセスについて話すときにもう一度やって来るだろう。

これらの距離ヒントはエッジがアンチエイリアシングを必要とするか否かに関わらず、何があろうと書き込まれることにも注意。

ポストプロセス(The postprocess)

どのようにポストプロセスが動作するかを説明するために、1Dの場合から始めよう。

上の画像は2つのケースを示す。緑と青の長方形はラスタライズされたジオメトリの2つの要素piecesを示している。これらは2つのケースで若干異なる。p0、p1、p2の3ピクセルが含まれている。赤の縦長の線は、ラスタライザがジオメトリをサンプルし、この後のパスのピクセルシェーダで実行される所の位置に対応するピクセル中心を示す。黒の短い縦線はピクセル中心の間の中点を示す。矢印はピクセル中心ごとに格納されるdistance-to-edgeを示す。最大距離は1ピクセルにクランプされる。

ダイアグラムでは、立方体が緑色の領域で、空が青色であるとする。ピクセルp1は立方体の一部であり、ピクセルp2は空の一部である。立方体がラスタライズされたとき、p1に書き込み、distance-to-edgeの値をセットアップするが、p2は大きな空のトライアングルの一部であり、関連するdistance-to-edgeヒントを持たない。

この場合、隣り合うペアのひとつのピクセルのみがdistance-to-edgeの値を持つ。これはすべての輪郭のエッジや非多様体non-manifoldに近いエッジに沿って発生するだろう。

考慮すべき他2つのケースがある。2つの隣り合うピクセルは相補的なdistance-to-edgeの値を持つかもしれない --- これは2つのピクセルがエッジを共有する2つの隣接するトライアングルの中にあるときに起こるだろう。あるいは、距離が両方とも定義されるが相補的でないかもしれない。これはサブピクセルトライアングルが大量にあると発生するだろう。

ダイアグラムの上段のケースでは、ブラーされる必要があるピクセルはp1のみである。そのピクセルに対してエンコードされるdistance-to-edgeの値はピクセルカバレッジについて必要なすべての情報を与える。p2を少しだけブレンドする必要がある。

下段のケースはもっと込み入っている。p2に注目。p2のdistance-to-edgeの値は近くにエッジのないことを示唆するけれども、このピクセルは緑と青の混合であるべきである。このケースを正しく扱うため、ポストプロセスは近傍ピクセルのヒント値を調べて、2つの競合する値の間を選択しなければならない。

これらすべてのケースをサポートする素直な方法のひとつは、ブレンドを計算するために2つの競合するdistance-to-edgeの値の最小値を選択するポストプロセスである。

処理の全体像は以下のようになる。ピクセルごとに、各方向でピクセルの半分の中の領域を考える。2つの近傍を調べ、各方向でdistance-to-edgeの値を計算する。distance-to-edgeがピクセルの半分より小さいならば、その近傍はブレンドされる必要がある。3つのピクセルそれぞれの寄与はそれがカバーする1ピクセルのエリアの逆数である。

2Dへの拡張は単純である。ピクセルごとに、垂直か水平かのいずれかに1Dのケースを適用する。各アプローチに関係するdistance-to-edgeの値を合計することで、より小さい合計を持つ軸を用いるかどうかを決める。

より自然な選択肢は水平と垂直の両方のブレンドを計算して組み合わせることである。例えば、中心ピクセルに対する2つの計算したカバレッジ値を乗算して、結果の重みを再び正規化する。これらすべての選択肢はさらなるコストがかかり、私が試した選択肢はクオリティを改善するものはなく、しばしばアーティファクトを引き起こした。

最後に、ブラーは潜在的にエイリアスするエッジにのみ適用される必要がある。これは、MLAAと同じ精神で、エッジにまたがる色の差が目立ったエイリアシングを引き起こすほど大きくはない場合、ピクセルの色を比較してブレンドをスキップすることで決まる可能性がある。

結果(Results)

デモ。

エッジのステップに正確に合致する非常に滑らかな勾配を得る。MLAAでの勾配のクオリティを複製するには非常に大きな近傍検索を必要とするだろう。

MLAAの局所的な近傍が特に目立つような状況のひとつは軸を通り過ぎてゆっくりと回転するエッジことである。MLAAでは、局所的な近傍は各ステップでの局所化されたブラーで正体を表す。これはそれが回転するとしてエッジに沿って進むtravel。DEAAでは、非常に長いエッジステップでコピーするとしてシームレスな遷移を得る。

MLAAがサポートできないケースはエッジのサブピクセルの移動である --- 例えば、完全に垂直な線がスクリーン中を動き回る所。色バッファのみを用いる手法はエッジのサブピクセル位置を推測できない。一方、DEAAは、線が移動するたび、フェードインするピクセルの新しい列を正確にシミュレートする。

問題(Problems)

  • アンダーサンプリング
    • トライアングルがピクセルより薄い。
    • 長く薄いトライアングル --- 例えば、とても長いクアッド。
    • キャラクターのような、有機的なオブジェクトの輪郭近くの縮小したトライアングル
    • サブピクセルギャップ
  • distance-to-edge情報なし
    • 相互貫入するジオメトリ
    • シャドウエッジ
    • テクスチャエイリアシング

(レッジやドアのフレームのような)薄い特徴は、側面や遠くから見ると、ピクセルより薄くなる。

ピクセルより薄いトライアングルは、知覚されるエッジが矛盾するdistance-to-edgeの値を持つので、問題を引き起こす。不自然に低いdistance-to-edge値を持つエッジに沿うピクセルのクラスタはエイリアスして見えるエッジの部分を生成する。他のすべてのエッジはよくアンチエイリアスされているとき、これらの部分は本当に目立つ。

その問題を最小化する方法のひとつは、頂点データを生成するツールをエイリアシング問題をまったく引き起こさないエッジに向かう変化する輪郭パラメータにセットアップしないことである。

これは、キャラクターモデルのような、近傍のトライアングルが若干の曲がりのみを持つ所の、オプションの滑らかな曲面ではない。この場合、サブピクセルトライアングルは輪郭のエッジ近くでは避けられない。GPU Proの記事では、アンダーサンプリング問題を回避するために輪郭のトライアングルが十分に大きいことを保証するための、1ピクセルか半ピクセルだけ外に押し出す背面の頂点を提案した。これは正常に動作するが、キャラクターで使われるとき、太って見えるようにする。その記事では、ポストプロセスでの2ピクセルのブレンドを説明し、これらの場合に本当に酷いクオリティ問題を引き起こす。私が説明する3ピクセルブレンドはもっとうまく処理する。

ジオメトリ間のサブピクセルギャップは、そのギャップはアンダーサンプリングされているので、エイリアス問題を引き起こす。例えば、空を望む2つの柱の間の薄いギャップ。distance-to-edge値は完全に矛盾がないかもしれないが、ブレンドされるピクセルは一貫して空ではない。それは他の柱によることもあるだろう。

最後に、私は、可視エッジがあるがdistance-to-edge情報がない、すなわち、この手法が役立たないであろう3つのケースをリスト化した。比較して、MLAAはこれらのケースそれぞれでアンチエイリアシングを提供する。

DEAAバッファのその他の使い方(Other uses for the DEAA buffer)

  • alpha-to-coverageで透明度をシミュレートする。
  • より良いアルファテストされたエッジ。例えば、枝葉foliage

シミュレートしたアルファブレンディング

次第に新しいオブジェクトをフェードインするためにdistance-to-edgeヒント値を上書きする。上段の一連の中の1つめの画像はオリジナルで、他の6つは50%のalpha-to-coverageのチェッカーボードである。アルファブレンディングは使われていない。distance-to-edge値は0.0から1.0まで変化する。ポストプロセスブラーは近傍ピクセルをアルファブレンドをシミュレートする変化量でブレンドする。

いくつかの制限により、これは半透明の表面にディファードライティングを適用できることを意味する。Alex EvansはLittleBigPlanetが同様の方法で50%の半透明の表面でのディファードライティングを嘘付く方法を説明していた。

他の使い方はより良いクオリティのalpha-to-coverage効果である。

2つめのアイデアは、枝葉のような、アルファテストされたエッジの改善である。

これはかなり単純である。アルファテスト値を計算し、いつも通り0を下回るならばピクセルを殺す。ピクセルが死ななければ、アルファテスト値を既存のdistance-to-edge評価関数とフレームバッファのエンコード処理に食わす。