Troika: テキストのアンチエイリアスを改善するための簡単なアイデア

作成日 2021年06月17日  ·  7コメント  ·  ソース: protectwise/troika

古いバージョンを使用しているため、最近アンチエイリアスコードを更新したかどうかはわかりませんが、シェーダーで描画された円のアンチエイリアスを実行するための優れた方法を見つけた後、テキストでも試してみたかったのです。 、テキストはSDFベースであり、円のアンチエイリアスも距離ベースであるためです。

私の現在のバージョンのTroikaでは、距離に対してreturn length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.5;を実行します。 これには、斜めに表示すると、左端と右端のエッジがやや目に見えるぼやけになるというアーティファクトがあります。
image

スカラーに変更しました。 サークルコードと同じように、距離: return fwidth(distance) * 0.5; troikaGetFragDistValueから渡された距離は次のようになります: float distance = troikaGetFragDistValue(); float aaDist = troikaGetAADist(distance);
このようにすると、ぼやけたアーティファクトが発生しません。
image

0.5係数を増やして、アンチエイリアスをスムーズにすることができます。 例: 0.8
image

私と同じように、この方法に気付いていないのではないかと思ったので、共有したいと思いました。 私の「実装」には奇妙なアーティファクトがいくつかありますが(以下を参照)、おそらくこれが他の方法を選択した理由です。 また、シェーダーコードでaaDist変数をどのように使用するか正確にはわからないため、これを実装するための準備が整っている可能性があります。 たとえば、この変更のために変更または削除する必要のあるコードがいくつかあるかもしれません。これにより、私の「実装」がさらに改善される可能性があります。

image

この方法は、bgolusの投稿https://forum.unity.com/threads/antialiasing-circle-shader.432119/で見つけました。詳細については、こちらをご覧ください。 彼はまた、これが無視できるかどうかはわかりませんが、たとえばlength(vec2(dFdx(distance), dFdy(distance))) fwidth(distance) $ 6 $#$を実行して、さらに精度を高めることができると言います。

全てのコメント7件

提案をありがとう! 斜めの角度でそれらのぼやけたエッジにも気づき、それらを排除したいので、私は間違いなくこれを調べます。

理論的には、 distanceの変更とvTroikaGlyphUV * vTroikaGlyphDimensionsの変更はどちらもフォントスペース単位の距離を表すため、同等であると思いますが、微妙な違いがあるはずです。見落とされました。 あなたが示したアーティファクトを回避できれば、変更を統合させていただきます。 :)

すごい! 変更はその1行と同じくらい簡単です(そしてそれを収容するためにその距離引数を渡します)。 それでも生のコードが必要な場合は、明日仕事をしているときに送信できます。

理論的には、距離の変化とvTroikaGlyphUV * vTroikaGlyphDimensionsの変化はどちらもフォント空間単位で距離を表すため、同等である必要があると思います。

導関数がどのように同じになるかを正確に理解していません。 distanceは私が推測するSDF距離ですが、もう1つはスケーリングされたUV位置です。 私はコードとそれらがどのように比較されるかを見ていませんが、それらの派生物は異なっているはずだと感じています。 私の知る限り、 fwidthは、引数として渡された特定の入力値と、隣接するフラグメント内の同じ特定の入力値との差を取ります。これは、隣接するフラグメントが同時に並行して実行されるために可能です。 今日、 gl_FragColor.rgb = vec3(fwidth(gl_FragColor.x + gl_FragColor.g + gl_FragColor.b));を使用してテストを実行し、エッジ検出/ソーベルフィルターのようにエッジがレンダリングされるかどうかを確認し、その事実を少し確認しようとしました。

議論してくれてありがとう、このようなものは時々私の脳を壊します。 ;)

私がそれらが「同等」であると言ったとき、私はそれらが両方とも同じ単位で距離を表すことを意味しました、しかしあなたは正しいです、それらは完全に同じではありません。

バックアップするために、ここで必要なのは、フラグメント間の_潜在的な_変化率です。 提案しているようにdistance変数の変更を使用すると、多くの場合正確になりますが、場合によっては非常に不正確になります。 これは、その値がサンプリングされるSDFが_不均一_であるためです。 曲がり、グリフ全体で変化の方向を切り替えます。 したがって、隣接するフラグメント間のdistanceの導関数は、距離フィールドがグリフパスの途中で増加から減少に切り替わる場合のように、ゼロでさえも小さすぎるか、テキストが表示される場合のように大きすぎる場合があります。サイズが小さい場合、フラグメントグリッドは予測できない場所でSDFをオーバーレイします。 それがあなたが見ているアーティファクトの少なくともいくつかを説明しているのではないかと思います。

では、 distanceを使用せずに、どのようにして_潜在的な_変化率を決定できるでしょうか。 さて、あなたがそれを呼ぶときのその「スケーリングされたUV位置」は、本質的にグリフの長方形内のx / y座標であり、 distanceと同じ単位を使用します。 そのx/yの導関数は、フラグメント間の潜在的な移動率を示します。 全体として、 distanceを使用するよりも良い結果が得られます。これは、グリフ全体の_均一な_変化率に基づいているため、アーティファクトが発生せず、小さいサイズでより正確になるためです。

しかし、あなたが見てきたように、それが崩壊する場所は斜めの角度です。 そのような場合、垂直方向の潜在的なx / y変化の速度は、水平方向のそれとは大きく異なります。 そのため、一方の方向では大きすぎ、もう一方の方向では小さすぎる潜在的な変化率に単一の値を使用することになり、そのフラグメントでのSDFの実際の変化方向に応じてぼやけた線や途切れ途切れの線が生じます。

そうですね、斜格の場合は間違いなく改善の余地がありますが、 distanceの導関数を使用するだけでは十分ではありません。 もちろん、これを改善するためのアイデアを受け入れています。 1つの可能性は、シナリオ(斜めの角度で大きなテキストサイズ、パスに近い)を検出し、その1つの場合にのみdistance派生物を使用することです。

ええ、このようなものは考えるのが混乱しています、ハハ。 ええ、距離フィールドが滑らかではないことがわかります。

それらのグリッチなピクセルは、そこにあるフラグメントがいくつかの奇妙な距離値を持っているためかもしれません。

遠くから見るとそれほど途切れることはありませんが、UVの方が優れていることは間違いありません。 おそらく、距離変数とカメラの距離に依存するUVの間の補間がうまくいくでしょう。 近くにあるときはfwidth(distance)を多く選択し、遠くにあるときはfwidth(uv)を多く選択します。

比較のために(まったく同じカメラの位置と向きで2つをキャプチャしませんでしたが、とにかく違いをよく示していると思います):
距離(0.8ファクター):
image
UV:
image

この変更により、カスタムテキスト変換の結果が大幅に改善されることに気づきました。 これは、 createDerivedMaterialを使用して曲線に従うように変更されたテキストです(この手法を参照)。 これは、現在のtroika-three-textシェーダーを使用します。

image

これは同じスクリーンショットですが、 @asbjornlystruptroikaGetAADistに変更されています。

image

セカンドショットでは、非常に伸びた「GREAT!」をご覧いただけます。 かなりクリスピーです。

逸話的に:定数を0.25(0.5から)に微調整すると、鮮明なエッジも得られることもわかりました。

return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.25;

@canadaduaneに感謝します、私は確かに伸ばされた部分の改善を見ることができます。 また、HELLOのLの間に醜いアーティファクトがポップアップしているのを見ることができます。これは、この変更を採用する前に確実に把握する必要があります。

このページは役に立ちましたか?
0 / 5 - 0 評価