1. ホーム
  2. opengl

[解決済み】OpenGLのテキストレンダリングは、バージョン4.1現在、何が最先端なのでしょうか?[クローズド]。

2022-04-18 08:27:49

質問

<余談
クローズド . この質問はもっと必要です 集中的 . 現在、回答は受け付けておりません。

<パス

この質問を改善したいですか? 問題を更新して、1つの問題だけに焦点を当てるようにする。 本論文の編集 .

クローズド 4年前 .

など、OpenGLでのテキストレンダリングに関する質問がすでに多数寄せられています。

しかし、主に議論されているのは、固定関数パイプラインを使用したテクスチャ付き四角形のレンダリングです。 確かに、シェーダーはより良い方法を作る必要があります。

私の文字列のほとんどはプロットの目盛りラベル(日付と時間、または純粋な数値)なので、国際化についてはあまり心配していません。 しかし、プロットは画面のリフレッシュレートで再レンダリングされ、かなりの量のテキストがあります(画面上に数千グリフを超えることはありませんが、ハードウェアアクセラレーションによるレイアウトが望ましいほど十分な量です)。

最新のOpenGLを使ったテキストレンダリングの推奨されるアプローチは何でしょうか? (そのアプローチを使っている既存のソフトウェアを引用することは、それがうまく機能していることの良い証拠になります)。

  • ジオメトリシェーダは、例えば位置と方向と文字列を受け取り、テクスチャ付きの四角形を出力します。
  • ベクターフォントをレンダリングするジオメトリシェーダ
  • 上記と同様ですが、代わりにテッセレーションシェーダを使用します。
  • フォントのラスタライズを行うコンピュートシェーダ

解決方法は?

アウトラインのレンダリングは、合計で 12 個のキャラクターしかレンダリングしない場合を除き、曲率を近似するためにキャラクターごとに必要な頂点の数のために、依然として "no go" となっています。代わりにピクセルシェーダでベジエ曲線を評価するアプローチがありますが、これらは簡単にアンチエイリアスをかけられないという問題があり、距離マップテクスチャ付きのクワッドを使えば些細なことです。

高速性と品質との間の最良のトレードオフは、やはり、符号付き距離フィールドテクスチャを持つテクスチャ付き四角形です。それは ごくわずかに は、通常のテクスチャを貼ったプレーンなクワッドを使うよりも遅いですが、それほどでもありません。一方、クオリティはまったく別の次元にあります。結果は実に見事で、これ以上ないほど速く、グローなどのエフェクトも些細なことで簡単に追加できます。また、必要であれば、この技術は古いハードウェアにもうまくダウングレードすることができます。

有名な バルブ論文 は、そのテクニックを紹介します。

このテクニックは、ポリゴンを生成しないものの、暗黙面(メタボールなど)の仕組みと概念的に似ています。これは完全にピクセルシェーダで実行され、テクスチャからサンプリングされた距離を距離関数として取ります。選択されたしきい値(通常は 0.5)より上はすべて "in"、それ以外はすべて "out"である。最も単純なケースでは、10年前の非シェーダ対応ハードウェアでは、アルファテストの閾値を0.5に設定すると、まさにその通りになります(ただし、特殊効果やアンチエイリアスはありません)。

もし、フォントにもう少し重さを加えたい場合(擬似太字)、閾値を少し小さくすれば、一行のコードも変更せずにトリックを行うことができます(単に "font_weight" ユニフォームを変更するだけ)。グロー効果については、ある閾値より上のものはすべて"in"とみなし、別の(より小さい)閾値より上のものはすべて"out, but in glow"として、その2つの間でLERPsを行うだけです。アンチエイリアシングも同じように機能します。

1 ビットではなく 8 ビットの符号付き距離値を使用することで、このテクニックはテクスチャマップの有効解像度を各次元で 16 倍にします(黒と白ではなく、すべての可能な色合いを使用するため、同じストレージで 256 倍の情報を使用することになります)。しかし、16倍をはるかに超えて拡大しても、結果はまったく問題ありません。長い直線が少しくねくねしますが、典型的な「ブロック状」サンプリングアーチファクトはありません。

ジオメトリシェーダを使用してポイントから四角形を生成することができます(バス帯域幅を減らす)が、正直なところ、利益はかなりわずかです。GPG8 で説明されているように、インスタンス化されたキャラクタレンダリングについても同じことが言えます。インスタンス化のオーバーヘッドを償却できるのは ロット のテキストを描画します。私の意見では、追加された複雑さとダウングレードできないことに比べて、得られるものは全くありません。さらに、定数レジスタの量に制限されるか、テクスチャバッファオブジェクトから読み込む必要がありますが、これはキャッシュコヒーレンスにとって最適ではありません(そもそも最適化することが目的なのですから!)。

シンプルで古くからある頂点バッファは、アップロードを少し先にスケジュールすれば、同じように速く(もしかしたら速く)、過去15年間に作られたすべてのハードウェアで動作します。また、フォント内の特定の文字数や、レンダリングする文字数にも制限されません。

フォント内の文字数が256を超えないことが確実な場合、ジオメトリシェーダでポイントから四角形を生成するのと同様の方法でバス帯域を削減するために、テクスチャアレイは検討する価値があるかもしれません。アレイテクスチャを使用する場合、すべてのクワッドのテクスチャ 座標は同一で、一定の st の座標が異なるだけであり r の座標で、これはレンダリングする文字のインデックスと同じです。

しかし、他の手法と同様、前世代のハードウェアと互換性がない代償に、期待される利益はわずかです。

Jonathan Dummerによる距離テクスチャ生成のための便利なツールがあります。 説明ページ

更新しました。

で指摘されているように、最近では プログラマブル頂点プーリング (D. Rákos, "OpenGL Insights", pp. 239), 最新世代の GPU でシェーダからプログラム的に頂点データを引き 出すことには、標準の固定関数を使って同じことをするのと比べて、大きな レイテンシやオーバーヘッドが伴いません。

また、最新世代の GPU は、合理的な大きさの汎用 L2 キャッシュをますます多く搭載しており(たとえば、nvidia Kepler では 1536kB)、バッファテクスチャから 4 角のランダムオフセットを取得する際の非干渉性アクセスの問題は、あまり問題になら ないと予測されます。

このため、バッファテクスチャから一定のデータ(クアッドサイズなど)を引き出すというアイデアは、より魅力的なものとなっています。したがって、仮想的な実装では、このようなアプローチで、PCIe とメモリ転送、および GPU メモリを最小に抑えることができます。

  • 文字インデックス(表示する文字ごとに1つ)のみをアップロードし、このインデックスを渡すバーテックスシェーダへの唯一の入力とし gl_VertexID そして、ジオメトリシェーダでそれを 4 ポイントに増幅し、キャラク タインデックスと頂点 ID(これは頂点シェーダで利用できる "gl_primitiveID;)を唯一の属性として持ち、変換 フィードバックによってこれを捕捉します。
  • GSの主なボトルネックである出力アトリビュートが2つしかないので、これは高速になりますし、そうでなければ両ステージとも"no-op"に近いです。
  • フォント内の各文字について、基点に対するテクスチャを貼ったクワッドの頂点位置を含むバッファテクスチャをバインドします(これらは基本的に "フォントメトリクス"です)。このデータは、左下頂点のオフセットのみを格納し、軸合わせされたボックスの幅と高さをエンコードすることにより、1quadあたり4数値に圧縮できます(ハーフフロートと仮定すると、これは1文字あたり8バイトの定数バッファとなり、通常の256文字のフォントはL1キャッシュの2kBに完全にフィットすることができます)。
  • ベースラインの一様性を設定する
  • バッファテクスチャを水平オフセットでバインドします。これらは 可能 GPUでも計算できるかもしれませんが、この種のことはCPUで行う方がはるかに簡単で効率的です。なぜなら、これは厳密に連続した操作であり、まったく些細なことではないためです(カーニングを考えてみてください)。また、別のフィードバックパスが必要になり、これも同期ポイントになるでしょう。
  • フィードバックバッファから以前に生成されたデータをレンダリングします。バーテックスシェーダはバッファオブジェクトから基点の水平オフセットとコーナー頂点のオフセットを引き出します(プリミティブIDと文字インデックスを使用します)。提出された頂点の元の頂点IDは現在、我々の"プリミティブID"です(GSは頂点を四角形に変えたことを覚えておいてください)。

このように、理想的には必要な頂点の帯域を75%削減(償却)することができますが、1本の線しかレンダリングすることができません。1回の描画呼び出しで複数のラインをレンダリングしたい場合は、ユニフォームを使用するのではなく、バッファテクスチャにベースラインを追加する必要があります(帯域幅の利得が小さくなります)。

しかし、75%削減したとしても、妥当な量のテキストを表示するための頂点データは50-100kiB程度であるため(これは実質的に ゼロ GPUやPCIeバスに対して)複雑さが増し、後方互換性が失われることが、トラブルに見合うものなのかどうか、私はまだ疑っています。ゼロを75%減らしても、まだゼロでしかありません。私は上記の方法を試したことがないので、本当に適格な発言をするにはもっと調査が必要でしょう。しかし、誰かが本当に驚くべき性能差(数十億文字ではなく、通常の量のテキストを使用)を示さない限り、私の見解は、頂点データについては、シンプルで古い頂点バッファは、最先端のソリューションの一部と見なされるのに十分であると正当化されます。シンプルでわかりやすく、機能的で、うまく機能します。

すでに「" OpenGLインサイト の章も参照してください。 距離場による2Dシェイプレンダリング。 Stefan Gustavsonによる距離場のレンダリングについて詳しく説明されています。

2016年の更新情報です。

一方、極端な倍率で気になる角丸のアーチファクトを除去するための技術もいくつか存在します。

その一つは、距離フィールドの代わりに擬似距離フィールドを単純に使用する方法です(距離は実際のアウトラインではなく、アウトラインへの最短距離であるという違いがあります)。 または架空の の線が端からはみ出る)。これはいくらか優れており、同じ速度(同一のシェーダ)で、同じ量のテクスチャメモリを使用して実行されます。

もう一つのアプローチは、3チャンネルテクスチャの詳細と実装において、median-of-threeを使用するものです。 githubで入手可能 . これは、この問題に対処するために以前に使用されたアンドオアハックを改善することを目的としています。品質が良く、若干、ほとんど目立たない程度に遅くなりますが、テクスチャメモリは3倍ほど使用します。また、余分なエフェクト(グローなど)は、正しく取得するのが難しくなっています。

最後に、キャラクターを構成する実際のベジェ曲線を保存し、フラグメントシェーダで評価すること が実用化されました。 性能は若干劣りますが、問題になるほどではありません)、最高倍率でも素晴らしい結果を得ることができます。

この手法で大きなPDFをリアルタイムにレンダリングするWebGLのデモが公開されています。 こちら .