205

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

しかし、ほとんどの場合、固定機能パイプラインを使用してテクスチャ付きクワッドをレンダリングすることについて説明しています。確かにシェーダーはより良い方法を作る必要があります。

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

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

  • 位置と向き、文字シーケンスなどを受け入れ、テクスチャ付きのクワッドを放出するジオメトリ シェーダー
  • ベクター フォントをレンダリングするジオメトリ シェーダー
  • 上記と同様ですが、代わりにテッセレーション シェーダーを使用します
  • フォントのラスタライズを行う計算シェーダー
4

5 に答える 5

209

アウトラインのレンダリングは、合計で 12 文字のみをレンダリングしない限り、曲率を概算するために 1 文字あたりに必要な頂点の数が原因で、「ダメ」のままです。代わりにピクセル シェーダーでベジエ曲線を評価するアプローチがありましたが、これらは容易にアンチエイリアシングされないという問題があり、これは距離マップ テクスチャ クワッドを使用すると些細なことであり、シェーダーで曲線を評価することは依然として必要以上に計算コストがかかります。

「高速」と「品質」の間の最良のトレードオフは、署名されたディスタンス フィールド テクスチャを持つテクスチャ化されたクワッドです。プレーンな通常のテクスチャ クワッドを使用するよりもわずかに遅くなりますが、それほどではありません。一方、品質はまったく異なる球場にあります。結果は本当に驚くべきもので、可能な限り高速で、グローなどの効果も簡単に追加できます。また、必要に応じて、この手法を古いハードウェアに適切にダウングレードすることもできます。

この手法については、有名なValve の論文を参照してください。

この手法は、ポリゴンを生成しませんが、暗黙的なサーフェス (メタボールなど) が機能する方法と概念的に似ています。これは完全にピクセル シェーダーで実行され、テクスチャからサンプリングされた距離を距離関数として取得します。選択したしきい値 (通常は 0.5) を超えるものはすべて "in" で、それ以外はすべて "out" です。最も単純なケースでは、シェーダーに対応していない 10 年前のハードウェアで、アルファ テストのしきい値を 0.5 に設定すると、まったく同じことが行われます (ただし、特殊効果とアンチエイリアシングはありません)。
フォントにもう少し太さを追加したい場合 (偽の太字)、コードを 1 行も変更せずに、わずかに小さいしきい値でうまくいきます ("font_weight" ユニフォームを変更するだけです)。グロー効果の場合、単純に、あるしきい値を超えるすべてのものを「イン」と見なし、別の (小さい) しきい値を超えるすべてを「アウトだがグローイン」と見なし、2 つの間の LERP を考慮します。アンチエイリアシングも同様に機能します。

この手法では、1 ビットではなく 8 ビットの符号付き距離値を使用することで、テクスチャ マップの有効解像度を各次元で 16 倍に増加させます (黒と白の代わりに、可能なすべての陰影が使用されるため、256 倍になります)。同じストレージを使用する情報)。しかし、16 倍をはるかに超えて拡大しても、結果はまだ許容できるものに見えます。長い直線は最終的に少し波打つようになりますが、典型的な「ブロック状」のサンプリング アーティファクトはありません。

ポイントからクワッドを生成するためにジオメトリ シェーダーを使用できます (バス帯域幅を減らします) が、正直なところ、得られるものはわずかです。GPG8 で説明されているように、インスタンス化されたキャラクターのレンダリングについても同じことが言えます。インスタンス化のオーバーヘッドは、描画するテキストが多い場合にのみ償却されます。私の意見では、その利点は、追加された複雑さと非ダウングレード性とは関係ありません。さらに、定数レジスタの量によって制限されるか、テクスチャ バッファ オブジェクトから読み取る必要がありますが、これはキャッシュ コヒーレンスにとって最適ではありません (そして、最初から最適化することが目的でした!)。
シンプルでプレーンな古い頂点バッファーは、アップロードを少し前にスケジュールすると、同じくらい高速 (場合によっては高速) になり、過去 15 年間に構築されたすべてのハードウェアで実行されます。また、フォント内の特定の文字数や、レンダリングする特定の文字数に制限されることもありません。

フォントの文字数が 256 文字を超えていないことが確実な場合は、ジオメトリ シェーダーでポイントからクワッドを生成するのと同様の方法でバス帯域幅を取り除くために、テクスチャ配列を検討する価値があります。配列テクスチャを使用する場合、すべてのクワッドのテクスチャ座標は同一、定数s、および座標を持ち、レンダリングする文字インデックスに等しい座標tのみが異なります。 しかし、他の手法と同様に、前世代のハードウェアとの互換性がないという犠牲を払って、期待される利益はわずかです。r

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

更新: Programmable Vertex Pulling
(D. Rákos、「OpenGL Insights」、pp. 239) で 最近指摘されたように、最新世代の GPU のシェーダーから頂点データをプログラムでプルすることに関連する大幅な追加のレイテンシーやオーバーヘッドはありません。標準の固定機能を使用して同じことを行うのと比較して。 また、最新世代の GPU では、ますます合理的なサイズの汎用 L2 キャッシュ (nvidia Kepler では 1536kiB など) が使用されるようになっているため、バッファ テクスチャからクワッド コーナーのランダム オフセットを取得するときに、一貫性のないアクセスの問題が発生する可能性があります。問題。

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

  • このインデックスと を渡す頂点シェーダーへの唯一の入力として、文字インデックス (表示される文字ごとに 1 つ) のみをアップロードし、gl_VertexIDそれをジオメトリ シェーダーで 4 ポイントに増幅し、文字インデックスと頂点 ID (この唯一の属性として「頂点シェーダーで利用可能になった gl_primitiveID」) になり、変換フィードバックを介してこれをキャプチャします。
  • 出力属性が 2 つしかないため (GS の主なボトルネック)、これは高速になります。
  • フォント内の各文字について、ベース ポイントに対するテクスチャ化されたクワッドの頂点位置を含むバッファ テクスチャをバインドします (これらは基本的に「フォント メトリック」です)。このデータは、左下の頂点のオフセットのみを格納し、軸に沿ったボックスの幅と高さをエンコードすることで、クワッドごとに 4 つの数値に圧縮できます (ハーフ フロートを想定すると、これは 1 文字あたり 8 バイトの定数バッファーになります --典型的な 256 文字のフォントは、2kiB の L1 キャッシュに完全に収まる可能性があります)。
  • ベースラインのユニフォームを設定する
  • バッファ テクスチャを水平オフセットにバインドします。これらおそらく GPU で計算することもできますが、CPU でそのようなことを行う方がはるかに簡単で効率的です。これは厳密に連続した操作であり、まったく簡単ではないためです (カーニングを考えてください)。また、別の同期ポイントとなる別のフィードバック パスが必要になります。
  • フィードバック バッファーから以前に生成されたデータをレンダリングします。頂点シェーダーは、基点の水平オフセットとバッファー オブジェクトからのコーナー頂点のオフセットを取得します (プリミティブ ID と文字インデックスを使用)。送信された頂点の元の頂点 ID が「プリミティブ ID」になりました (GS が頂点を四角形に変えたことを思い出してください)。

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

ただし、75% の削減を想定しても、「妥当な」量のテキストを表示するための頂点データは 50 ~ 100kiB 程度しかないため (これは実質的にゼロです)GPU または PCIe バスに) -- 複雑さが増し、下位互換性が失われることに、本当に苦労する価値があるかどうかはまだ疑問です。ゼロを 75% 削減してもゼロにすぎません。私は確かに上記のアプローチを試したことはありません. それでも、誰かが本当に驚くべきパフォーマンスの違いを実証できない限り (数十億の文字ではなく、「通常の」量のテキストを使用してください!)、頂点データについては、シンプルでプレーンな古い頂点バッファーで十分であるという私の見解は変わりません。 「最先端のソリューション」の一部と見なされます。シンプルでわかりやすく、機能し、うまく機能します。

上記の「 OpenGL Insights 」を既に参照したので、ディスタンス フィールドレンダリングについて詳細に説明している Stefan Gustavson による「ディスタンス フィールドによる 2D シェイプ レンダリング」の章も指摘する価値があります。

更新 2016:

一方、極端な倍率で邪魔になるコーナーの丸みアーティファクトを除去することを目的とした追加の技術がいくつかあります。

1 つのアプローチは、距離フィールドの代わりに疑似距離フィールドを使用するだけです (違いは、距離が実際の輪郭ではなく、輪郭または端から突き出た想像上の線までの最短距離であることです)。これはいくらか良く、同じ量のテクスチャ メモリを使用して同じ速度 (同じシェーダー) で実行されます。

別のアプローチでは、 github で入手可能な3 チャネル テクスチャの詳細と実装で 3 の中央値を使用します。これは、問題に対処するために以前に使用された and-or ハックを改善することを目的としています。品質が高く、わずかに、ほとんど目立たず、遅くなりますが、3 倍のテクスチャ メモリを使用します。また、追加の効果 (グローなど) を正しく設定するのは困難です。

最後に、文字を構成する実際のベジエ曲線を保存し、それらをフラグメント シェーダーで評価することが実用的になりました。パフォーマンスはわずかに劣りますが (問題になるほどで​​はありません)、最高の倍率でも素晴らしい結果が得られます。
この手法を使用して大きな PDF をリアルタイムでレンダリングする WebGL のデモは、こちらから入手できます。

于 2011-03-11T21:16:40.840 に答える
15

http://code.google.com/p/glyphy/

GLyphy と他の SDF ベースの OpenGL レンダラーとの主な違いは、他のほとんどのプロジェクトが SDF をテクスチャにサンプリングすることです。これには、サンプリングが持つ通常の問題がすべて含まれています。すなわち。輪郭がゆがみ、低品質です。代わりに、GLyphy は GPU に送信された実際のベクトルを使用して SDF を表します。これにより、非常に高品質のレンダリングが得られます。

欠点は、コードが OpenGL ES を使用する iOS 用であることです。おそらく、Windows/Linux OpenGL 4.x ポートを作成する予定です (ただし、作成者が実際のドキュメントを追加してくれることを願っています)。

于 2013-11-08T19:11:46.143 に答える
14

最も普及している手法は、依然としてテクスチャード加工された大腿四頭筋です。しかし、2005年に、LORIAはベクターテクスチャと呼ばれるものを開発しました。つまり、ベクターグラフィックをプリミティブ上のテクスチャとしてレンダリングします。これを使用してTrueTypeまたはOpenTypeフォントをベクターテクスチャに変換すると、次のようになります。

http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005

于 2011-03-10T17:02:53.480 に答える
10

Mark Kilgard の赤ん坊であるNV_path_rendering (NVpr) が上記のいずれにも言及されていないことに驚いています。その目的はフォントのレンダリングよりも一般的ですが、フォントからテキストをレンダリングし、カーニングを使用することもできます。OpenGL 4.1 も必要ありませんが、現時点ではベンダー/Nvidia 専用の拡張機能です。基本的に、フォントをパスに変換しますglPathGlyphsNV。これは、メトリックなどを取得するために freetype2 ライブラリに依存します。次に、カーニング情報にアクセスし、glGetPathSpacingNVNVpr の一般的なパス レンダリング メカニズムを使用して、パス「変換された」フォントを使用してテキストを表示することもできます。(実際の変換がないため、引用符で囲みます。曲線はそのまま使用されます。)

NVpr のフォント機能の記録されたデモは、残念ながら特に印象的ではありません。(おそらく、誰かがインターチューブで見つけることができる、よりおしゃれな SDF デモに沿ったものを作成する必要があります...)

フォント部分の 2011 NVpr API プレゼンテーション トークはここから始まり、次の部分に続きます。そのプレゼンテーションがどのように分割されているかは少し残念です。

NVpr に関するより一般的な資料:

  • Nvidia NVpr ハブ、ただしランディング ページの一部の資料は最新のものではありません
  • 「ステンシル、次にカバー」(StC)と呼ばれるパスレンダリング方法の頭脳に関するSiggraph 2012論文。この論文では、Direct2D などの競合する技術がどのように機能するかについても簡単に説明しています。フォント関連のビットは、論文の付録に追いやられました。ビデオ/デモのようないくつかのエキストラもあります。
  • 更新ステータスのGTC 2014 プレゼンテーション。一言で言えば、現在は Google の Skia でサポートされており (Nvidia は 2013 年後半と 2014 年にコードを提供しました)、Google Chrome で使用され、[Skia とは独立して、私が思うに] Adob​​e Illustrator CC 2014 のベータ版で使用されています。
  • OpenGL 拡張レジストリの公式ドキュメント
  • USPTO は、NVpr に関連して Kilgard/Nvidia に少なくとも 4 つの特許を付与しました。StC を自分で実装したい場合は、おそらく知っておく必要があります: US8698837US8698808US8704830、およびUS8730253。これに関連して「として公開された」USPTO文書がさらに17件あることに注意してください。そのほとんどは特許出願であるため、それらからさらに多くの特許が付与される可能性は十分にあります.

そして、「ステンシル」という言葉は、私の回答の前にこのページでヒットしなかったため、このページに参​​加したSOコミュニティのサブセットは、かなり多数であるにもかかわらず、テッセレーションフリーのステンシルバッファを認識​​していなかったようです-一般的なパス/フォント レンダリングのベース メソッド。Kilgard はopengl フォーラムに FAQ のような投稿をしています。これは、[GP]GPU をまだ使用しているにもかかわらず、テッセレーションのないパス レンダリング方法が標準的な 3D グラフィックスとどのように異なるかを明らかにする可能性があります。(NVpr には CUDA 対応のチップが必要です。)

歴史的な観点から言えば、Kilgard は、2011 年にデビューしたステンシル ベースのNVprと混同しないでください。


NVpr のようなステンシル ベースのメソッドや GLyphy のような SDF ベースのメソッド (他の回答で既にカバーされているため、ここではこれ以上説明しません) を含む、このページで説明されている最近のメソッドのすべてではないにしても、ほとんどには 1 つの制限があります。従来の(〜100 DPI)モニターでの大きなテキスト表示に適しており、どのスケーリングレベルでもジャギーがなく、高DPIの網膜のようなディスプレイでは、小さなサイズでも見栄えがします. ただし、Microsoft の Direct2D+DirectWrite が提供するもの、つまり主流のディスプレイでの小さなグリフのヒントを完全に提供するわけではありません。(一般的なヒンティングの視覚的な調査については、たとえば、このタイポテーク ページを参照してください。より詳細なリソースは、antigrain.com にあります。)

私は、現時点で Microsoft がヒントを得てできることを実行できる、オープンで製品化された OpenGL ベースのものを認識していません。(Apple の OS X GL/Quartz の内部構造については無知であることを認めます。なぜなら、私の知る限りでは、Apple は GL ベースのフォント/パスのレンダリング方法を公開していないからです。OS X は、MacOS 9 とは異なり、そうではないようです。とにかく、INRIA の Nicolas P. Rougier によって書かれたOpenGLシェーダーを介したヒンティングに対処する 2013 年の研究論文が 1 つあります。OpenGL からヒントを得る必要がある場合は、おそらく読む価値があります。ヒントに関しては、freetype のようなライブラリが既にすべての作業を行っているように見えるかもしれませんが、実際にはそうではありません。次の理由により、論文から引用しています。

FreeType ライブラリは、RGB モードでサブピクセル アンチエイリアシングを使用してグリフをラスタライズできます。ただし、これは問題の半分にすぎません。グリフを正確に配置するためにサブピクセルの配置も実現したいからです。テクスチャ化されたクワッドを小数ピクセル座標で表示しても、問題は解決されません。これは、ピクセル全体レベルでテクスチャ補間が行われるだけだからです。代わりに、サブピクセル ドメインで正確なシフト (0 と 1 の間) を達成したいと考えています。これはフラグメント シェーダーで実行できます [...]。

解決策は簡単ではないので、ここでは説明しません。(論文はオープンアクセスです。)


Rougier の論文から学んだもう 1 つのこと (Kilgard は考慮していないようです) は、(Microsoft + Adob​​e) であるフォントの力が 1 つではなく 2 つのカーニング仕様方法を作成したことです。古いものはいわゆるkernテーブルに基づいており、freetype でサポートされています。新しいものは GPOS と呼ばれ、フリー ソフトウェアの世界では HarfBuzz や pango などの新しいフォント ライブラリでのみサポートされています。NVpr はこれらのライブラリのいずれもサポートしていないように見えるため、一部の新しいフォントでは NVpr をそのまま使用するとカーニングが機能しない場合があります。このフォーラムの議論によると、それらのいくつかは明らかに野生のものです。

最後に、複雑なテキスト レイアウト (CTL)を行う必要がある場合、OpenGL ベースのライブラリが存在しないように見えるため、現在 OpenGL ではうまくいかないようです。(一方、DirectWrite は CTL を処理できます。) CTL をレンダリングできる HarfBuzz のようなオープンソースのライブラリがありますが、(ステンシル ベースのメソッドを使用する場合のように) それらをうまく機能させる方法がわかりません。 OpenGL。おそらく、再形成されたアウトラインを抽出し、パスとして NVpr または SDF ベースのソリューションにフィードするために、グルー コードを記述する必要があります。

于 2014-08-07T15:03:34.417 に答える
3

あなたの最善の策は、OpenGL バックエンドでcairo グラフィックスを調べることだと思います。

3.3 コアでプロトタイプを開発するときに私が抱えていた唯一の問題は、OpenGL バックエンドでの非推奨関数の使用でした。1~2年前なので状況は改善されているかもしれませんが…

いずれにせよ、将来デスクトップの opengl グラフィックス ドライバーが OpenVG を実装することを願っています。

于 2011-03-10T19:11:46.840 に答える