2010-01-15 4 views
37

Ich implementiere eine GUI, die auf OpenGL basiert. Ich kam zu dem Problem, dass jede GUI haben wird - Text-Rendering. Ich kenne mehrere Methoden, um Text in OpenGL zu rendern, aber ich frage mich, welche davon am besten für eine GUI geeignet wäre.Wie funktioniert OpenGL Live-Text-Rendering für eine GUI?

Im Allgemeinen in einer GUI haben wir zwei Arten von Text - statisch und live. Statisch ist einfach genug - wir können ein TTF zu einer Textur rendern und es vergessen. Es ist der "Live" -Text, der mich mehr stört - stell dir eine Konsole oder einen Live-Chat in einem Multiplayer-Spiel vor.

Ich dachte an mehrere Möglichkeiten:

  • keine besonderen Fälle - machen und eine Textur jedes Mal, wenn die Textänderungen laden, nur im Auge behalten, es rerender wenn tatsächlich neuer Text erscheint, und zu versuchen, das spalten größerer Text in kleine Teile (wie pro Chatlinie). Das würde uns aber immer noch in Fällen hängen lassen, in denen sich eine Kerblinie ständig ändert, oder in einem Intro-Text, der "pro Charakter" rendert (Schreibmaschinen-Stil in einigen Science-Fiction-Spielen)
  • Quad-per-Zeichen - das Auch scheint eine beliebte Lösung zu sein, Sie bereiten eine Textur mit der ASCII-Tabelle vor und rendern ein texturiertes Quad-Zeichen. Ich habe jedoch ernsthafte Zweifel an der Effizienz einer solchen Lösung. Tipps, wie man das schneller macht, wären auch willkommen.
  • Hybridlösungen - aber ich habe keine Ahnung, wie zu implementieren, dass sauber

Die Frage ist daher - wie Text in OpenGL effizienter zu machen?

Wenn das hilft, ich kodiere in STL/Boost-schwere C++ und mit dem Ziel GForce 6 und später Grafikkarten.

+1

große Texturen mit allen möglichen Glyphen auf nicht bauen Sie. Während es für westliche Schriften einfach und "vernünftig" ist, erkennen Sie schnell, wenn Sie versuchen, Ihre Anwendung zu internationalisieren, dass dieser Ansatz mit östlichen Schriftarten nicht nachhaltig ist. Die einzige skalierbare Lösung besteht darin, den dynamischen Text bei Bedarf zu generieren. –

+1

Wenn Sie versuchen, einzelne Glyphen selbst zu rendern, ignorieren Sie alles, was das Betriebssystem über Unterschneidung, Akzentzeichen und Kombinieren von Zeichen, Rechts-nach-Links-Skripten und ein paar andere Macken des Typlayouts weiß, die ich gerade vergesse . Es ist wahrscheinlich in Ordnung, ein Textblatt mit 0-9a-zA-Z mit Interpunktion zu haben, um einige wirklich häufige Fälle abzudecken, aber meistens bekommt man einen schöneren Typ, wenn man den Font-Renderer nach der ganzen Zeile oder dem ganzen Absatz fragt. – codewarrior

Antwort

29

EDIT2: Sean Barrett gerade veröffentlicht Bitmap fonts for C/C++ 3D programmers.

EDIT: ein weiterer Code-Edelstein, der einen Blick wert ist, ist Font Stash, die Sean Barretts stb_truetype.h nutzt.


Sie können eine Textur erstellen, in der Sie alle Zeichen Ihrer Schriftart rendern. Dann zeichnen Sie einfach texturierte Quadrate mit orthographischer Projektion und geeigneten Texturkoordinaten: Dieser Ansatz funktioniert, wenn Ihr Text in einer Sprache ist, die nicht viele Symbole enthält: wie Englisch. Die Schrifttextur wird einmal am Anfang der Anwendung erstellt und das Rendern von Quads ist sehr schnell.

Das ist, was ich verwende, und ich glaube, es ist der schnellste Weg, Text in OpenGL zu rendern. Zuerst verwendete ich Angelcode's Bitmap Font Generator Werkzeug und dann integrierte ich FreeType direkt und baute eine große Textur, die alle Glyphen beim Start der Anwendung enthält. Als Tipps zur Verbesserung der Geschwindigkeit der Quads-Rendering habe ich nur VBO für den Rest der Geometrie in meiner Anwendung verwendet.

Ich bin überrascht, dass Sie Zweifel über Quad-Rendering haben, während Sie nicht über die Leistung der Generierung einer Textur auf der CPU zu kümmern scheinen, dann hochladen, dann binden, um schließlich ein Rechteck damit, dass für jeder Rahmen. Wechselnde OpenGL-Zustände sind der Engpass, nicht die 500 - 1000 Quads, die Sie für Text verwenden.

Werfen Sie auch einen Blick auf Bibliotheken wie die FTGL Bibliothek, die die gesamte Schriftart in Polygone (geometrische Schriften) konvertiert.

+0

um, das habe ich in der Frage O.o. Ich frage nach relativen Leistungsproblemen. –

+0

Entschuldigung geklickt Senden vor dem Schreiben –

+0

+1: Ich frage mich nur über die Leistung der "Standard-Lösung". Das Ändern der Textur würde nur "bei Änderung" sein, während die Quads für den Text pro Frame ausgeführt würden, deshalb habe ich mich gefragt. –

8

Versuchen Sie, dies zu lesen: http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1.

Der beschriebene Ansatz ist die typische Methode für das Text-Rendering mit Grafik-APIs. Ein Zeichen pro Quad und alle Bilddaten für Text in einer einzelnen Textur. Wenn Sie Ihren gesamten Zeichensatz in eine Textur einfügen können (abhängig von der Größe der Textur können Sie möglicherweise mehrere anpassen), ist das Rendering extrem schnell.

Der Schlüssel ist, dass Texturbindung die Operation ist, die Sie minimieren müssen. Wenn Sie Ihren gesamten Text mit einer einzigen Textur rendern können, spielt es keine Rolle, wie viel Text Sie auf den Bildschirm legen müssen. Auch wenn Sie die Texturen einige Male wechseln müssen (verschiedene Schriftarten, verschiedene Schriftattribute [fett, unterstrichen usw.]), sollte die Leistung immer noch gut sein. Die Textleistung ist für ein HUD möglicherweise kritischer, in der GUI jedoch weniger wichtig.

+0

+1: Dies ist ein sehr interessanter Link! Texture Switching könnte entfernt werden, wenn ich alle Schriften in einer einzigen Textur anpassen kann. Momentan sind die erlaubten Texturen sehr groß, was meiner Meinung nach ziemlich gut ist. –

+5

Ich habe [einen Spiegel dieses DMedia Tutorial] (http://fsrv.dyndns.org/mirrors/dmedia-tutorials-textrendering1/index.html) übergeben. – genpfault

0

Pro Quad-Zeichen behandelt dachte eine Display-Liste (nur aktualisiert, wenn Text ändert) ist genug für die meisten Fälle.

habe ich es mit X11-Schriften die XLoadQueryFont verwenden, glGenLists, glXUseXFont, glCallLists Sie eine Reihe von Anzeigelisten haben jedes Zeichen zu beschreiben.

Die Funktion glCallLists akzeptiert ein Argument char * für Ihren Text und kann in eine Anzeigeliste eingebettet werden.

Sie enden mit einem einzelnen Anruf, um Blocktext anzuzeigen.

Die von G. Pakosz vorgeschlagene Schriftart ist ähnlich, aber Sie berechnen Ihre eigenen "by character" Anzeigelisten.

Die ersten Optionen sind etwas langsamer, da bei jeder Textänderung ein prozessorbasiertes Rendering erforderlich ist.

+0

Dies ist die "Schulbuch" -Methode, die ich kenne. –

1

könnte gerade diese zwei Funktionen nutzen:

void renderstring2d(char string[], float r, float g, float b, float x, float y) 
{ 
    glColor3f(r, g, b); 

    glRasterPos2f(x, y); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
} 

void renderstring3d(char string[], float r, float g, float b, float x, float y, float z) 
{ 
    glDisable(GL_LIGHTING); 
    glColor3f(r, g, b); 

    glRasterPos3f(x, y, z); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
}

dann, wenn Sie 2D-Text machen, vergessen Sie nicht, sowohl die Model-View und Projektionsmatrizen zurückzustellen.

Sie müssen mit diesen Funktionen nicht zu einem Quadrupus rendern, da diese Funktionen direkt auf den Framebuffer rendern.

Und wenn das für Sie nicht funktioniert, überprüfen Sie dies. http://www.opengl.org/resources/faq/technical/fonts.htm

Es geht um das Rendern von Text mit glBitmap, glDrawPixels und Alpha-Blending.

+1

Nein danke, ich will so eine Verlangsamung nicht;). Sicher, es wird direkt auf den Framebuffer gerendert, aber nehmen Sie sich einen Moment Zeit, um zu überlegen, wie viele Daten Sie jeden Frame zwischen der Karte und dem lokalen Speicher übertragen. Nicht zu vergessen, dass diese Lösung keine benutzerdefinierten Schriftarten unterstützt. –

+0

Nun, ich habe diese Funktionen für meine eigene GUI in einer 3D-Game-Engine verwendet, und es gibt keine merkliche Änderung der Framerate, wenn ich die GUI an- oder ausschalte. Die Bitmap, die übergeben wird, beträgt für jedes Zeichen nur 135 Pixel. Dies ist viel weniger Zeit als das Erstellen einer Textur und das Übergeben der gesamten Textur an die Grafikkarte jedes Mal, wenn Sie ein Zeichen rendern möchten. –

+0

@Ned Wie kann ich das tun, wenn ich SDL anstelle von GLUT verwende? – Ben

1

Es ist schwierig zu tun, vor allem, wenn Sie Subpixel-Font-Rendering-Techniken verwenden möchten. Schauen Sie sich die ClanLib SDK an. Es verwendet einen Batch-Renderer, um einen ganzen Bildschirm mit Text in einem einzelnen OpenGL-Aufruf zu rendern. Da es eine zlib-basierte Lizenz hat, können Sie seinen Code extrahieren, wenn Sie das SDK nicht selbst verwenden möchten.

4

Sie können den Text als triangulierte Flächen rendern und die Verwendung einer Textur vermeiden. Auf diese Weise vermeiden Sie unscharfe Kanten, wenn der Text gezoomt wird. Ich habe eine Low-Poly-ASCII-Schriftart erstellt, die unter der Nummer my github verfügbar ist.

Eine andere Möglichkeit, scharfe Kanten in Ihrem Text zu haben, ist , aber das leidet unter einigen Artefakten.

3