Es gibt bereits eine Reihe von Fragen zum Rendern von Text in OpenGL, z.
Meistens wird jedoch das Rendern strukturierter Quads mithilfe der Pipeline mit festen Funktionen diskutiert. Sicherlich müssen Shader einen besseren Weg finden.
Ich bin nicht wirklich besorgt über die Internationalisierung, die meisten meiner Zeichenfolgen sind Plot-Tick-Labels (Datum und Uhrzeit oder rein numerisch). Die Diagramme werden jedoch mit der Bildschirmaktualisierungsrate neu gerendert, und es kann ziemlich viel Text vorhanden sein (nicht mehr als ein paar tausend Glyphen auf dem Bildschirm, aber genug, um das hardwarebeschleunigte Layout zu verbessern).
Was ist der empfohlene Ansatz für das Rendern von Text mit modernem OpenGL? (Das Zitieren vorhandener Software unter Verwendung des Ansatzes ist ein guter Beweis dafür, dass sie gut funktioniert.)
- Geometrie-Shader, die z. B. Position und Ausrichtung sowie eine Zeichenfolge akzeptieren und strukturierte Quads ausgeben
- Geometrie-Shader, die Vektorschriftarten rendern
- Wie oben, jedoch stattdessen Tessellation-Shader verwenden
- Ein Compute-Shader für die Rasterung von Schriftarten
Antworten:
Das Rendern von Konturen bleibt, sofern Sie nicht nur ein Dutzend Zeichen insgesamt rendern, aufgrund der Anzahl der Scheitelpunkte, die pro Zeichen zur Annäherung an die Krümmung benötigt werden, ein "Nein". Obwohl es Ansätze zur Bewertung von Bezierkurven im Pixel-Shader gegeben hat, leiden diese darunter, dass sie nicht leicht antialiasiert werden können, was bei Verwendung eines Quad mit Entfernungskartentextur trivial ist, und die Bewertung von Kurven im Shader ist immer noch rechenintensiver als erforderlich.
Der beste Kompromiss zwischen "schnell" und "Qualität" sind immer noch strukturierte Quads mit einer signierten Distanzfeldtextur. Es ist etwas langsamer als ein normales strukturiertes Quad, aber nicht so sehr. Die Qualität hingegen liegt in einem ganz anderen Stadion. Die Ergebnisse sind wirklich beeindruckend, es ist so schnell wie möglich und Effekte wie Glühen lassen sich ebenfalls ganz einfach hinzufügen. Außerdem kann die Technik bei Bedarf problemlos auf ältere Hardware heruntergestuft werden.
Siehe das berühmte Ventilpapier für die Technik.
Die Technik ähnelt konzeptionell der Funktionsweise impliziter Oberflächen (Metabälle und dergleichen), erzeugt jedoch keine Polygone. Es läuft vollständig im Pixel-Shader und verwendet die von der Textur abgetastete Entfernung als Abstandsfunktion. Alles über einem gewählten Schwellenwert (normalerweise 0,5) ist "in", alles andere ist "out". Im einfachsten Fall bewirkt das Festlegen des Alpha-Test-Schwellenwerts auf 0,5 bei 10 Jahre alter, nicht shaderfähiger Hardware genau dies (allerdings ohne Spezialeffekte und Antialiasing).
Wenn Sie der Schriftart etwas mehr Gewicht hinzufügen möchten (faux fett), reicht ein etwas kleinerer Schwellenwert aus, ohne eine einzelne Codezeile zu ändern (ändern Sie einfach Ihre Uniform "font_weight"). Für einen Glow-Effekt betrachtet man einfach alles über einer Schwelle als "in" und alles über einer anderen (kleineren) Schwelle als "out, but in glow" und LERPs zwischen den beiden. Antialiasing funktioniert ähnlich.
Durch die Verwendung eines vorzeichenbehafteten 8-Bit-Abstandswerts anstelle eines einzelnen Bits erhöht diese Technik die effektive Auflösung Ihrer Texturabbildung in jeder Dimension um das 16-fache (anstelle von Schwarzweiß werden alle möglichen Schattierungen verwendet, sodass wir das 256-fache haben Informationen, die denselben Speicher verwenden). Aber selbst wenn Sie weit über das 16-fache vergrößern, sieht das Ergebnis immer noch akzeptabel aus. Lange gerade Linien werden irgendwann etwas wackelig, aber es gibt keine typischen "blockartigen" Abtastartefakte.
Sie können einen Geometrie-Shader verwenden, um die Quads aus Punkten zu generieren (Busbandbreite reduzieren), aber ehrlich gesagt sind die Gewinne eher gering. Gleiches gilt für das instanziierte Rendern von Zeichen, wie in GPG8 beschrieben. Der Aufwand für die Instanzierung wird nur amortisiert, wenn Sie viel Text zeichnen müssen. Die Gewinne stehen meiner Meinung nach in keinem Zusammenhang mit der zusätzlichen Komplexität und Nicht-Herabstufbarkeit. Außerdem sind Sie entweder durch die Anzahl der konstanten Register begrenzt oder müssen aus einem Texturpufferobjekt lesen, das für die Cache-Kohärenz nicht optimal ist (und die Absicht bestand darin, zunächst zu optimieren!).
Ein einfacher, einfacher alter Vertex-Puffer ist genauso schnell (möglicherweise schneller), wenn Sie den Upload etwas früher planen und auf jeder Hardware ausgeführt werden, die in den letzten 15 Jahren erstellt wurde. Und es ist weder auf eine bestimmte Anzahl von Zeichen in Ihrer Schriftart noch auf eine bestimmte Anzahl von Zeichen beschränkt, die gerendert werden sollen.
Wenn Sie sicher sind, dass Ihre Schriftart nicht mehr als 256 Zeichen enthält, sollten Texturarrays eine Überlegung wert sein, um die Busbandbreite auf ähnliche Weise wie beim Generieren von Quads aus Punkten im Geometrie-Shader zu reduzieren. Bei Verwendung einer Array-Textur haben die Texturkoordinaten aller Quads identische, konstante
s
undt
koordinierte Koordinaten und unterscheiden sich nur in derr
Koordinate, die dem zu rendernden Zeichenindex entspricht.Aber wie bei den anderen Techniken sind die erwarteten Gewinne auf Kosten der Inkompatibilität mit Hardware der vorherigen Generation gering.
Es gibt ein praktisches Tool von Jonathan Dummer zum Generieren von Entfernungstexturen: Beschreibungsseite
Update:
Wie kürzlich in Programmable Vertex Pulling (D. Rákos, "OpenGL Insights", S. 239) ausgeführt wurde, ist das programmgesteuerte Abrufen von Vertex-Daten aus dem Shader bei den neuesten GPU-Generationen nicht wesentlich länger. im Vergleich dazu, dasselbe mit der festen Standardfunktion zu tun.
Außerdem verfügen die neuesten GPU-Generationen über immer größere Allzweck-L2-Caches (z. B. 1536 kB bei nvidia Kepler), sodass das inkohärente Zugriffsproblem zu erwarten ist, wenn zufällige Offsets für die Quad-Ecken aus einer Puffertextur gezogen werden, die kleiner als a ist Problem.
Dies macht die Idee, konstante Daten (wie Quad-Größen) aus einer Puffertextur zu ziehen, attraktiver. Eine hypothetische Implementierung könnte daher PCIe- und Speicherübertragungen sowie GPU-Speicher mit einem Ansatz wie diesem auf ein Minimum reduzieren:
gl_VertexID
weitergibt, und verstärken Sie diesen auf 4 Punkte im Geometrie-Shader, wobei der Zeichenindex und die Scheitelpunkt-ID (dies) weiterhin vorhanden sind wird "gl_primitiveID im Vertex-Shader zur Verfügung gestellt") als einziges Attribut und erfasst dies über Transformations-Feedback.Auf diese Weise könnte man die erforderliche Scheitelpunktbandbreite idealerweise um 75% reduzieren (amortisiert), obwohl nur eine einzige Linie gerendert werden könnte. Wenn man in der Lage sein möchte, mehrere Linien in einem Zeichenaufruf zu rendern, müsste man die Grundlinie zur Puffertextur hinzufügen, anstatt eine Uniform zu verwenden (wodurch die Bandbreitengewinne kleiner werden).
Selbst unter der Annahme einer Reduzierung um 75% - da die Scheitelpunktdaten zur Anzeige "angemessener" Textmengen nur etwa 50 bis 100 kB betragen (was praktisch Null ist)an eine GPU oder einen PCIe-Bus) - Ich bezweifle immer noch, dass die zusätzliche Komplexität und der Verlust der Abwärtskompatibilität die Mühe wirklich wert sind. Die Reduzierung von Null um 75% ist immer noch nur Null. Ich habe den oben genannten Ansatz zugegebenermaßen nicht ausprobiert, und es wären weitere Untersuchungen erforderlich, um eine wirklich qualifizierte Aussage zu treffen. Aber wenn nicht jemand einen wirklich erstaunlichen Leistungsunterschied nachweisen kann (mit "normalen" Textmengen, nicht mit Milliarden von Zeichen!), Bleibt mein Standpunkt, dass für die Scheitelpunktdaten ein einfacher, einfacher alter Scheitelpunktpuffer zu Recht gut genug ist als Teil einer "Lösung auf dem neuesten Stand der Technik" zu betrachten. Es ist einfach und unkompliziert, es funktioniert und es funktioniert gut.
Nachdem oben bereits auf " OpenGL Insights " verwiesen wurde , ist auch auf das Kapitel "2D-Formwiedergabe nach Entfernungsfeldern" von Stefan Gustavson hinzuweisen, in dem die Darstellung von Entfernungsfeldern ausführlich erläutert wird.
Update 2016:
Mittlerweile gibt es mehrere zusätzliche Techniken, die darauf abzielen, die bei extremen Vergrößerungen störenden Eckrundungsartefakte zu entfernen.
Ein Ansatz verwendet einfach Pseudo-Distanzfelder anstelle von Distanzfeldern (der Unterschied besteht darin, dass der Abstand der kürzeste Abstand nicht zum tatsächlichen Umriss, sondern zum Umriss oder einer imaginären Linie ist, die über die Kante hinausragt). Dies ist etwas besser und läuft mit der gleichen Geschwindigkeit (identischer Shader) und der gleichen Menge an Texturspeicher.
Ein anderer Ansatz verwendet den Median-of-Three in einer dreikanaligen Textur, die bei github verfügbar ist . Dies soll eine Verbesserung gegenüber den und / oder Hacks darstellen, die zuvor zur Behebung des Problems verwendet wurden. Gute Qualität, leicht, fast nicht merklich, langsamer, verbraucht aber dreimal so viel Texturspeicher. Außerdem sind zusätzliche Effekte (z. B. Glühen) schwieriger zu erzielen.
Schließlich ist das Speichern der tatsächlichen Bezierkurven, aus denen Zeichen bestehen, und das Auswerten in einem Fragment-Shader praktisch geworden , mit etwas schlechterer Leistung (aber nicht so sehr, dass es ein Problem darstellt) und atemberaubenden Ergebnissen selbst bei höchsten Vergrößerungen.
Eine WebGL-Demo zum Rendern eines großen PDF-Dokuments mit dieser Technik in Echtzeit finden Sie hier .
quelle
clip(...)
Zeile durchif (text.a < 0.5) {discard;}
(odertext.a < threshold
) ersetzen . HTH.http://code.google.com/p/glyphy/
Der Nachteil ist, dass der Code für iOS mit OpenGL ES ist. Ich werde wahrscheinlich einen Windows / Linux OpenGL 4.x-Port erstellen (hoffentlich fügt der Autor jedoch eine echte Dokumentation hinzu).
quelle
Die am weitesten verbreitete Technik sind immer noch strukturierte Quads. Im Jahr 2005 entwickelte LORIA jedoch sogenannte Vektortexturen, dh das Rendern von Vektorgrafiken als Texturen auf Grundelementen. Wenn man damit TrueType- oder OpenType-Schriftarten in eine Vektortextur konvertiert, erhält man Folgendes:
http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005
quelle
Ich bin überrascht, dass Mark Kilgards Baby NV_path_rendering (NVpr) von keinem der oben genannten erwähnt wurde. Obwohl seine Ziele allgemeiner sind als das Rendern von Schriftarten, kann es auch Text aus Schriftarten und mit Kerning rendern. Es erfordert nicht einmal OpenGL 4.1, ist aber derzeit eine Nur-Hersteller- / Nvidia-Erweiterung. Grundsätzlich werden Schriftarten in Pfade umgewandelt,
glPathGlyphsNV
die von der freetype2-Bibliothek abhängen, um die Metriken usw. abzurufen. Anschließend können Sie auch mitglGetPathSpacingNV
den allgemeinen Pfadwiedergabemechanismen von NVpr auf die Kerning-Informationen zugreifen und Text aus den pfad- "konvertierten" Schriftarten anzeigen. (Ich habe das in Anführungszeichen gesetzt, da es keine echte Konvertierung gibt, werden die Kurven unverändert verwendet.)Die aufgezeichnete Demo für die Schriftarten von NVpr ist leider nicht besonders beeindruckend. (Vielleicht sollte jemand eine nach dem Vorbild der viel schickeren SDF-Demo machen , die man auf den Intertubes findet ...)
Der Vortrag zur NVpr-API-Präsentation 2011 für den Schriftarten-Teil beginnt hier und wird im nächsten Teil fortgesetzt . Es ist ein bisschen bedauerlich, wie diese Präsentation aufgeteilt ist.
Allgemeinere Materialien zu NVpr:
Und da das Wort "Schablone" vor meiner Antwort keine Treffer auf dieser Seite hervorgebracht hat, scheint es, dass die Untergruppe der SO-Community, die an dieser Seite teilgenommen hat, insofern, als sie ziemlich zahlreich war, keine Kenntnis von tessellationsfreiem Schablonenpuffer hatte. basierte Methoden für das Rendern von Pfaden / Schriftarten im Allgemeinen. Kilgard hat einen FAQ-ähnlichen Beitrag im opengl-Forum, der möglicherweise beleuchtet, wie sich die tessellationsfreien Pfadwiedergabemethoden von Standard-3D-Grafiken unterscheiden, obwohl sie immer noch eine [GP] -GPU verwenden. (NVpr benötigt einen CUDA-fähigen Chip.)
Aus historischer Sicht ist Kilgard auch Autor des Klassikers "Eine einfache OpenGL-basierte API für texturabgebildeten Text", SGI, 1997 , der nicht mit dem schablonenbasierten NVpr verwechselt werden sollte, der 2011 debütierte.
Die meisten, wenn nicht alle neueren Methoden, die auf dieser Seite behandelt werden, einschließlich schablonenbasierter Methoden wie NVpr oder SDF-basierter Methoden wie GLyphy (auf die ich hier nicht weiter eingehen werde, da andere Antworten dies bereits behandeln), haben jedoch eine Einschränkung: Sie sind es Geeignet für die Anzeige großer Texte auf herkömmlichen Monitoren (~ 100 DPI) ohne Zacken auf jeder Skalierungsstufe, und sie sehen auch bei kleinen Abmessungen auf Retina-ähnlichen Displays mit hoher DPI gut aus. Sie bieten jedoch nicht vollständig das, was Microsoft Direct2D + DirectWrite Ihnen bietet, nämlich Hinweise auf kleine Glyphen auf Mainstream-Displays. (Eine visuelle Übersicht über Hinweise im Allgemeinen finden Sie beispielsweise auf dieser Typothek-Seite . Eine ausführlichere Ressource finden Sie auf antigrain.com .)
Mir sind keine offenen und produzierten OpenGL-basierten Dinge bekannt, die das tun können, was Microsoft im Moment mit Hinweisen kann. (Ich gebe zu, dass ich Apples OS X GL / Quartz-Interna nicht kenne, da Apple nach meinem besten Wissen nicht veröffentlicht hat, wie sie GL-basiertes Rendering von Schriftarten / Pfaden ausführen. Es scheint, dass OS X dies im Gegensatz zu MacOS 9 nicht tut überhaupt Hinweise geben, was manche Leute nervt .) Wie auch immer, es gibt ein Forschungspapier aus dem Jahr 2013, das sich mit Hinweisen über OpenGL-Shader befasst, die von Nicolas P. Rougier von INRIA geschrieben wurden. Es lohnt sich wahrscheinlich zu lesen, wenn Sie Hinweise von OpenGL benötigen. Während es den Anschein haben mag, dass eine Bibliothek wie freetype bereits die ganze Arbeit erledigt, wenn es um Hinweise geht, ist dies aus folgendem Grund, den ich aus dem Artikel zitiere, nicht der Fall:
Die Lösung ist nicht gerade trivial, daher werde ich hier nicht versuchen, sie zu erklären. (Das Papier ist offen zugänglich.)
Eine andere Sache, die ich aus Rougiers Artikel gelernt habe (und die Kilgard anscheinend nicht berücksichtigt hat), ist, dass die vorhandenen Schriftfähigkeiten (Microsoft + Adobe) nicht nur eine, sondern zwei Kerning-Spezifikationsmethoden erstellt haben. Die alte basiert auf einer sogenannten Kern- Tabelle und wird vom Freetype unterstützt. Das neue heißt GPOS und wird nur von neueren Schriftbibliotheken wie HarfBuzz oder pango in der Welt der freien Software unterstützt. Da NVpr keine dieser Bibliotheken zu unterstützen scheint, funktioniert das Kerning mit NVpr für einige neue Schriftarten möglicherweise nicht sofort. Laut dieser Forumsdiskussion gibt es einige von denen, die anscheinend in freier Wildbahn leben .
Wenn Sie ein komplexes Textlayout (CTL) durchführen müssen , scheinen Sie derzeit mit OpenGL kein Glück zu haben, da dafür keine OpenGL-basierte Bibliothek zu existieren scheint. (DirectWrite hingegen kann CTL verarbeiten.) Es gibt Open-Source-Bibliotheken wie HarfBuzz, die CTL rendern können, aber ich weiß nicht, wie Sie sie dazu bringen würden, gut zu funktionieren (wie bei der Verwendung schablonenbasierter Methoden) OpenGL. Sie müssten wahrscheinlich den Klebercode schreiben, um die neu geformten Umrisse zu extrahieren und sie als Pfade in NVpr- oder SDF-basierte Lösungen einzuspeisen.
quelle
Ich denke, Ihre beste Wahl wäre es, Kairo-Grafiken mit OpenGL-Backend zu untersuchen.
Das einzige Problem, das ich bei der Entwicklung eines Prototyps mit 3.3-Kern hatte, war die veraltete Funktionsnutzung im OpenGL-Backend. Es war vor 1-2 Jahren, also könnte sich die Situation verbessert haben ...
Wie auch immer, ich hoffe, dass OpenGG-Grafiktreiber in Zukunft OpenVG implementieren werden.
quelle