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
und t
koordinierte Koordinaten und unterscheiden sich nur in der r
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:
- Laden Sie nur einen Zeichenindex (einen pro anzuzeigendem Zeichen) als einzige Eingabe in einen Scheitelpunkt-Shader hoch, der diesen Index
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.
- Dies ist schnell, da es nur zwei Ausgabeattribute gibt (Hauptengpass in GS) und es ansonsten in beiden Phasen nahe an "no-op" liegt.
- Binden Sie eine Puffertextur, die für jedes Zeichen in der Schriftart die Scheitelpunktpositionen des strukturierten Quad relativ zum Basispunkt enthält (dies sind im Grunde die "Schriftartmetriken"). Diese Daten können auf 4 Zahlen pro Quad komprimiert werden, indem nur der Versatz des unteren linken Scheitelpunkts gespeichert und die Breite und Höhe des achsenausgerichteten Felds codiert werden (unter der Annahme, dass die Hälfte schwebt, sind dies 8 Bytes konstanter Puffer pro Zeichen - Eine typische 256-Zeichen-Schriftart könnte vollständig in 2 KB L1-Cache passen.
- Legen Sie eine Uniform für die Grundlinie fest
- Binden Sie eine Puffertextur mit horizontalen Offsets. Diese könnten wahrscheinlich sogar auf der GPU berechnet werden, aber es ist viel einfacher und effizienter für solche Dinge auf der CPU, da es sich um eine streng sequentielle Operation handelt und überhaupt nicht trivial ist (denken Sie an Kerning). Außerdem würde ein weiterer Rückkopplungsdurchlauf erforderlich sein, der ein weiterer Synchronisationspunkt wäre.
- Beim Rendern der zuvor generierten Daten aus dem Rückkopplungspuffer zieht der Vertex-Shader den horizontalen Versatz des Basispunkts und die Offsets der Eckscheitelpunkte aus Pufferobjekten (unter Verwendung der primitiven ID und des Zeichenindex). Die ursprüngliche Scheitelpunkt-ID der übermittelten Scheitelpunkte ist jetzt unsere "primitive ID" (denken Sie daran, dass der GS die Scheitelpunkte in Quads umgewandelt hat).
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 .