[OpenGL] Text rendern

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.

[OpenGL] Text rendern

Beitragvon Jonathan » 14.09.2014, 12:06

tl;dr : FreeTypeGl ist eine nette und einfach zu benutzende Bibliothek um Text mit OpenGL zu rendern.

Ich stand neulich mal wieder vor dem altbekannten Problem, Text rendern zu müssen. Da OpenGL ja nur eine reine Grafikbibliothek ist, bringt es von Haus aus keine Möglichkeiten dazu mit, also selbst wenn man die niedrigsten Ansprüche hat, die man sich vorstellen kann, kommt man nicht darum herum, sich eine eigene Lösung zu suchen (ich benutze übrigens OpenGl 4.3). Das habe ich also gemacht und habe eine Lösung gefunden, die mir recht gut gefallen hat, weswegen ich sie mit euch teilen möchte.
Letztendlich habe ich doch einiges selber programmiert, aber das ganze ist an einem freien Tag zu schaffen und auch nicht wirklich kompliziert.

Recherchiert man im Internet findet man schnell eine reihe an Bibliotheken, die Texte mit OpenGL rendern können. Ich wollte gerne etwas einfaches, was ich relativ schnell umsetzen kann und das nicht zu viele Abhängigkeiten hat. Nach einigem hin und her habe ich mich dann schließlich für FreeTypeGl entschieden:
Schöne Webseite: https://code.google.com/p/freetype-gl/
Aktuelle Webseite: https://github.com/rougier/freetype-gl

Wie man am Namen schon erkennt, setzt dieses Projekt auf die populäre FreeType Bibliothek auf: http://www.freetype.org/
Das ist Grundlage zu fast allem Font-Rendering und man braucht schon einen guten Grund, sich dagegen zu entscheiden.

Jetzt hat man natürlich schon zwei neue Abhängigkeiten, aber FreeType lässt sich sehr problemlos kompilieren und hat selber keine externen Abhängigkeiten und FreeTypeGl besteht nur aus einer handvoll Dateien, die man seinem Projekt hinzufügen kann. Der Aufwand hält sich also in Grenzen.

FreetypeGl kommt auch mit einer Reihe an Demoanwendungen und kann auch direkt rendern, da ich es aber in meinen Renderer integrieren wollte, Benutze ich nur die Funktionen um Bitmapfonts zu erzeugen und auf die Parameter zuzugreifen.
texture.png
(von der FreeTypeGL Webseite)

FtGl kann verschiedene Schriftarten mit verschiedenen Größen ziemlich effizient in eine Textur packen, wie man im Beispiel sieht.
Code: Ansicht erweitern :: Alles auswählen

m_Atlas = ftgl::texture_atlas_new(AtlasSize.x, AtlasSize.y, 1);
const auto CommonCharacters = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789äÄüÜöÖß?.,-#/\!\"%&()=' :;<>{}[]@€+-*";
auto NewFont = ftgl::texture_font_new_from_file(m_Atlas, Size, Filename.c_str());
ftgl::texture_font_load_glyphs(NewFont, CommonCharacters);
 

Man erstellt also einen Atlas und beliebig viele Font Objekte, die diesen Atlas benutzen. Die Font-Objekte kann man später benutzen um die einzelnen Glyphen (die grafische Repräsentation von Zeichen) zu rendern:
glyph.png
(von der FreeTypeGL Webseite)

FtGl gibt einen alle benötigten Parameter inklusive Kerning. Dadurch kann man mit ziemlich wenig Aufwand recht hübschen Text rendern:
Code: Ansicht erweitern :: Alles auswählen

        float LineHeight = m_Font->height;
        vec2 CursorPosition(0, LineHeight);
        for(auto i = 0u; i < wtext.length(); ++i)
        {
                auto c = wtext[i];
                if('\n' == c)
                {
                        CursorPosition.x = 0;
                        CursorPosition.y += LineHeight;
                        continue;
                }
                auto glyph = ftgl::texture_font_get_glyph(m_Font, c);

                //Kerning
                if(i > 0)
                        CursorPosition.x += ftgl::texture_glyph_get_kerning(glyph, wtext[i - 1]);

                //TP=TopLeft, BR=BottomRight

                //Position
                auto PosTL = CursorPosition + vec2(glyph->offset_x, -glyph->offset_y);
                auto PosBR = PosTL + vec2(glyph->width, glyph->height);

                //TexCoord
                auto TexTL = vec2(glyph->s0, glyph->t0);
                auto TexBR = vec2(glyph->s1, glyph->t1);

                //TODO: Vertexe erstellen:
}
 



Bei mir sieht es derzeit so aus, dass ich beim Starten alle benötigten ttf-Dateien lade und in einen großen Atlas packe. Ich habe eine eigene Text-Objekt Klasse, die einen Vertexbuffer erstellt und verwaltet. Gerendert wird alles über den Text-Manager der dann nur einmal den Shader und die Textur setzen muss und alle Vertexbuffer nacheinander rendern kann - es sollte also ziemlich performant sein, zumindest so schnell, das man bei normaler Benutzung keine Gedanken daran verschwenden muss.

Am Schluss noch der gesamt Code, so wie ich ihn derzeit verwende. Freigegeben als public domain, weil wirklich keine clevere Idee darin steckt. Er verwendet eine eigene Shader und Exception Klasse, die sich aber trivial ersetzen lassen sollte. glm ist auch drin, was ich bei OpenGL sehr empfehlen kann, ansonsten lässt sich die vec2-Klasse aber auch trivial ersetzen. Die Shader sind mit drin, man will vermutlich später noch ne Funktion einbauen um die Textfarbe zu ändern, etwa über eine Uniform.

So, ich hoffe das hilft eines Tages irgendjemanden der mal Texte rendern möchte :D
Dateianhänge
Text.cpp
(7.08 KiB) 149-mal heruntergeladen
Text.hpp
(1.91 KiB) 128-mal heruntergeladen
Lieber dumm fragen, als dumm bleiben!
Benutzeravatar
Jonathan
Establishment
 
Beiträge: 1153
Registriert: 04.08.2004, 20:06

Re: [OpenGL] Text rendern

Beitragvon Schrompf » 14.09.2014, 12:32

Schöne Zusammenstellung! Danke!
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3614
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu


Zurück zu Artikel, Tutorials und Materialien

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste