Schriftumriss in OpenGL, FTGL

8

Ich verwende die FTGL-Bibliothek, um Schriftarten in meinem Spiel zu rendern, aber ich habe keine Ahnung, wie ich eine Gliederung um Text erstellen soll. Einen Schatten zu bekommen könnte einfach sein, weil ich es einfach so machen kann:

(Pseudocode)

font.render(Color::BLACK, position.x + 1, position.y + 1); // Shadow
font.render(Color::WHITE, position.x, position.y)          // Normal text

Aber wie erstellt man eine Gliederung? Leider habe ich über das Internet keine interessanten Lösungen dafür gefunden, was mir etwas seltsam erschien, weil ich dachte, dass es ein sehr beliebtes Problem ist.

Das Zeichnen von Umrissen mit nur einer größeren Schriftart ist nicht richtig, da Buchstaben, wie ich herausgefunden habe, in diesem Fall einfach nicht übereinstimmen:

Geben Sie hier die Bildbeschreibung ein

Gibt es eine einfache Möglichkeit, eine Gliederung für Schriftarten zu erstellen? Wie machen sie das in echten Spielen?

Vielen Dank im Voraus für jede Antwort

Piotr Chojnacki
quelle
1
Eine schmutzige Lösung könnte darin bestehen, denselben Text in eine Textur zu rendern und diese Textur dann beispielsweise x1,2-skaliert zu rendern.
Dan
2
@ Dan Das führt zu genau dem, was er in seinem Bild oben gezeigt hat. Selbst das Rendern eines Buchstabens auf diese Weise würde zu Problemen führen, da die äußeren Umrisse dicker wären als die inneren (die möglicherweise nicht vorhanden sind).
Ingenieur
1
Welche Art von Schriftart verwenden Sie? FTGL unterstützt sofort Outline-Schriftarten für Vektor-Schriftarten. Die OpenGL-Linienbreite kann zur Steuerung der Dicke verwendet werden.
Paul-Jan

Antworten:

7

Flexibel und genau: Filter

Verwenden Sie einen Texelfilter entweder auf der Textur auf der CPU-Seite oder, wenn Sie die programmierbare Pipeline OpenGL verwenden, direkt im Fragment-Shader.

Die Idee eines Filters ist einfach, dass Sie eine 2D-Schleife durchlaufen, um jedes Texel zu verarbeiten. Wenn es weiß ist, durchlaufen Sie eine innere 2D-Schleife für jedes der umgebenden Pixel in einem Radius und passen sie entsprechend an. Dies wird auch als Box-Filter bezeichnet. Wenn Sie jedoch die Radiusprüfung einbeziehen, handelt es sich tatsächlich um einen kreisförmigen Filter, der achsenähnliche Artefakte vermeidet.

Eine schnellere Möglichkeit, dies zu tun, besteht darin, den Satz von Offsets für jedes von Ihnen überprüfte zentrale Pixel vorab zu berechnen. Auf diese Weise müssen Sie nicht für jedes Pixel, das ein bestimmtes Pixel umgibt, eine Quadratwurzel erstellen. Sie möchten die Komplexität auf O (texWidth * texHeight) und nicht auf O (texWidth * texHeight * filterRadius * filterRadius) beschränken.

Einfach: Mehrere Renderings

Eine andere Möglichkeit, den Effekt zu erzielen, besteht darin, den Text nicht zu skalieren, sondern den roten Umriss in acht (oder mehr) Richtungen zu rendern, die in dieser Richtung jeweils geringfügig vom Original versetzt sind:

 \|/
--+--
 /|\

Wenn Sie jede der roten Versionen wie folgt versetzen, erhalten Sie eine ziemlich gleichmäßige Außenkante um Ihren Originaltext. Denken Sie daran, dass Sie beim diagonalen Verschieben dieselbe Vektorgröße verwenden sollten wie beim horizontalen oder vertikalen Verschieben, anstatt einfach um dieselben x- und y-Werte zu versetzen (was zu einer ungefähr 1,4-fachen weiteren Länge führt - Grundtrig).

Zu Ihrer Information

Diese Art von Effekt ist als Dilatation bekannt und wird manchmal über die Minkowski-Summierung durchgeführt , bei der es sich um den vektorbasierten (kontinuierlichen) Ansatz für das oben beschriebene pixelbasierte (quantisierte) Boxfilter handelt.

Ingenieur
quelle
6

Diese Funktion ist direkt in FTGL implementiert, jedoch nur in der ExtrudeFontKlasse verfügbar . Sie definieren einfach einen Anfang für die Schriftart:

font = new FTExtrudeFont(...);
font->FaceSize(80);
font->Depth(0);
font->Outset(0, 5);

Dann können Sie für die beiden Rendermodi eine andere Farbe verwenden:

glColor3f(1.0, 1.0, 1.0); /* White inside */
font->Render("Hello", FTPoint(), FTPoint(), FTGL::RENDER_FRONT);
glColor3f(1.0, 0.0, 0.0); /* Red outline */
font->Render("Hello", FTPoint(), FTPoint(), FTGL::RENDER_SIDE);

Hier ist das Ergebnis, bei dem das Antialiasing aus- und wieder eingeschaltet wird:

Ergebnisbild

Sam Hocevar
quelle
Danke Sam! Das wollte ich wirklich hören - dass FTGL tatsächlich so etwas hat. Noch einmal vielen Dank.
Piotr Chojnacki
2

Nicht mit FTGL verwandt, aber es gibt einen großartigen Artikel von Valve über das Rendern von Glyphen. Es bietet qualitativ hochwertiges Rendering mit geringem Speicherbedarf und Effekte wie Konturen oder Schatten können einfach implementiert werden.

Thelvyn
quelle
2
Es lohnt sich, das OP zu warnen, dass dieser Ansatz ein Verständnis der programmierbaren GPU-Pipeline, dh der Shader, erfordert.
Ingenieur