Eine bewährte Methode zum Rendern von Schriften ist die Rasterung auf der CPU, das Zwischenspeichern des Ergebnisses (von Glyphen, Glyphensequenzen, ganzen Wörtern oder bei einer anderen Granularität) in Bitmaps oder Texturen und das anschließende Rendern auf dem Bildschirm.

Rendern Schriften

Die FreeType-Bibliothek zum Parsen und Rastern von Schriften gibt es schon seit Langem, ebenso wie betriebssystemspezifische Möglichkeiten, Glyphen in Bitmaps zu rastern. Einige Teile des Verfahrens wurden patentiert, so dass die Schriften z.B. unter Linux nicht besonders ansprechend aussehen. Und auch das subpixeloptimierte Rendering wurde aus verschiedenen Gründen erschwert.

Zusätzlich zu FreeType sind diese Schriftbibliotheken einen Blick wert:

  • stb_truetype.h – Single File C Library von Sean Barrett.
  • Font-rs – schneller Font-Renderer von Raph Levien, geschrieben in Rust \o/ und ein Artikel, der einige Aspekte davon beschreibt.

Aber im Kern besteht die ganze Idee immer noch darin, Glyphen in Bitmaps mit einer bestimmten Punktgröße zu rastern und das Ergebnis irgendwie zwischenzuspeichern.

Das Caching von gerasterten Glyphen in Bitmaps funktionieren gut genug. Wenn Sie nicht viele verschiedene Schriftgrößen verwenden, sehr große Schriftgrößen oder eine große Menge an Glyphen in Verbindung mit unterschiedlichen/großen Schriftgrößen.

Eine Bitmap für unterschiedliche Größen? Vorzeichenbehaftete Abstandsfelder.

Ein Paper von Chris Green aus dem Jahr 2007, Improved Alpha-Tested Magnification for Vector Textures and Special Effects, führte die Spieleentwicklungswelt in das Konzept der „signed distance field textures for vector-like stuffs“ ein.

Das Paper handelte hauptsächlich von der Lösung des Problems „Zeichen und Markierungen in Spielen zu implementieren“ und die Idee dahinter ist ziemlich clever. Anstatt gerasterte Formen in einer Textur zu speichern, speichern Sie eine spezielle Textur, bei der jedes Pixel die Entfernung zur nächsten Formkante darstellt. Wenn Sie mit dieser Textur rendern, kann ein Pixel-Shader einfache Alpha-Verwerfungen oder komplexe Behandlungen des Entfernungswertes durchführen, um Anti-Aliasing, Konturen usw. zu erhalten. Die SDF-Textur kann sehr klein ausfallen und dennoch in der Lage sein, hochauflösende Linienkunst anständig darzustellen.

Dann wurde den Leuten natürlich klar, dass der gleiche Ansatz auch für das Rendern von Schriften funktionieren könnte. Plötzlich bedeutet das Rendern von glatten Glyphen in sehr großen Schriftgrößen nicht, dass gerade der gesamte (V)RAM für zwischengespeicherte Texturen verbraucht wurde, die zwischengespeicherten SDFs der Glyphen können ziemlich klein bleiben, während sie bei größeren Größen schöne Kanten bieten.

Natürlich ist der SDF-Ansatz nicht ohne Nachteile:

  • Die Berechnung des SDF ist nicht trivial billig. Während Sie für die meisten westlichen Sprachen alle möglichen Glyphen offline in einem SDF-Texturatlas zwischenspeichern können, ist das für andere Sprachen aufgrund der schieren Menge an möglichen Glyphen nicht sinnvoll.
  • Simple SDF hat Artefakte in der Nähe von komplexen Kreuzungen oder Ecken, da es nur einen einzigen Abstand zur nächsten Kante speichert.
  • SDF funktioniert aus einem ähnlichen Grund nicht ganz bei sehr kleinen Schriftgrößen. Dort ist es wahrscheinlich besser, die Glyphe einfach in eine normale Bitmap zu rastern.

Wie auch immer, SDFs sind eine gute Idee. Für einige Beispiele oder Implementierungen kann man sich libgdx oder TextMeshPro ansehen.

Das Original-Paper deutete auf die Idee hin, mehrere Entfernungen zu speichern, um das Problem der scharfen Ecken des SDF zu lösen und eine kürzlich erfolgte Umsetzung dieser Idee ist „Multi-Channel Distance Field“ von Viktor Chlumsky.

Das ist ziemlich gut. Jedoch können die „winzigen Schriftgrößen“ und „Kosten für die Berechnung des (M)SDF“ immer noch ein Problem sein.

Schriften direkt auf der GPU.

Eine offensichtliche Frage ist: „Warum wird dieses Caching überhaupt in Bitmaps durchgeführt? Kann der Grafikprozessor nicht einfach die Glyphen direkt rendern? Die Frage ist gut. Die Antwort ist jedoch nicht unbedingt einfach.

GPUs sind nicht ideal für das Vektor-Rendering geeignet. Sie sind meistens Rasterer, befassen sich meist mit Dreiecken etc. Selbst einfache Aufgaben wie eine dicke Linie zu zeichnen, ist schon recht kompliziert. Werfen Sie für ein aufwändigeres „Vektor-/Kurven-Rendering“ einen Blick auf die folgenden Inhalte:

Vektor Texturen.

Das GPU-Text-Rendering mit Vektortexturen von Will Dobbie – teilt den Glyphenbereich in Rechtecke auf, speichert, welche Kurven ihn schneiden und wertet die Abdeckung aus diesen Kurven in einem Pixel-Shader aus.

Ziemlich ordentlich. Es scheint jedoch nicht das Problem der „sehr kleinen Schriftgrößen“ zu lösen (Aliasing), hat eine Begrenzung der Glyphkomplexität (Anzahl der Kurvensegmente pro Zelle) und hat einige Robustheitsprobleme.

Glyphie.

Eine weitere ist Glyphie, von Behdad Esfahbod. Es existieren Videos und Folien von einem Gespräch darüber. Es scheint ganz so, dass es Bezier-Kurven mit Kreisbögen annähert, sie in Texturen setzt, Indizes einiger engster Bögen in einem Gitter speichert und den Abstand zu ihnen in einem Pixel-Shader auswertet. Eine Art Mischung aus SDF- und Vektortexturansatz. Scheint aber in einigen Fällen auch unter Robustheitsproblemen zu leiden.

Pathfinder.

Mit Pathfinder von Patrick Walton ist eine neue Rust-Bibliothek auf dem Markt.

Nachteilig zu bemerken ist die Abhängigkeit von GPU-Funktionen, die einige Plattformen (mobil….) möglicherweise nicht haben – Tesselierung / Geometrie-Shader / Rechen-Shader (kein Problem auf dem PC). Speicher für den Abdeckungspuffer und Geometriekomplexität in Abhängigkeit von der Komplexität der Schriftkurve.

Hinweise auf die Zukunft von Twitterverse.

Von Spieleentwicklern im Middleware-Bereich sieht es so aus, als würden Sean Barrett und Eric Lengyel unabhängig voneinander an einer Art GPU-basierter Font-/Glyph-Rasterisierungsansätze arbeiten, wie ihre Tweets (Sean`s und Eric`s) zeigen.

Vielen Dank für ihren Besuch.