web-dev-qa-db-de.com

Wie zeichnet man Text nur mit OpenGL-Methoden?

Ich habe nicht die Option zu verwenden, aber OpenGL-Methoden (das ist glxxx() Methoden). Ich muss Text nur mit gl-Methoden zeichnen. Nachdem ich das rote Buch gelesen habe, verstehe ich, dass dies nur durch die Methode glBitmap() möglich ist. Wenn dies der einzig mögliche Weg ist, kann mir jemand mit den Pixel-Array-Informationen für alle Zeichen helfen. Gibt es eine andere Möglichkeit, Text zu zeichnen?

36
sathish v

Theorie

Warum es schwer ist

Gängige Schriftformate wie TrueType und OpenType sind Vektor-Umrissformate: Sie definieren mit Bezier-Kurven die Begrenzung des Buchstabens.

Bildquelle .

Das Transformieren dieser Formate in Arrays von Pixeln (Rastern) ist zu spezifisch und gehört nicht zum Umfang von OpenGL, insbesondere weil OpenGl keine nicht geraden Grundelemente enthält (siehe z. B. Warum gibt es in OpenGL kein Kreis- oder Ellipsengrundelement? )

Am einfachsten ist es, zuerst die Schriften selbst auf der CPU zu rastern und dann OpenGL das Pixel-Array als Textur zuzuweisen.

OpenGL weiß dann sehr gut mit Arrays von Pixeln durch Texturen umzugehen.

Texturatlas

Wir könnten Zeichen für jeden Frame rastern und die Texturen neu erstellen, aber das ist nicht sehr effizient, besonders wenn Zeichen eine feste Größe haben.

Der effizientere Ansatz besteht darin, alle Zeichen, die Sie verwenden möchten, zu rastern und auf einer einzigen Textur zusammenzufassen.

Übertragen Sie das dann einmal auf die GPU und verwenden Sie die Textur mit benutzerdefinierten UV-Koordinaten, um das richtige Zeichen auszuwählen.

Dieser Ansatz wird als Texturatlas bezeichnet und kann nicht nur für Texturen verwendet werden, sondern auch für andere wiederholt verwendete Texturen, z. B. Kacheln in einem 2D-Spiel oder Web-UI-Symbole.

Das Wikipedia-Bild der vollständigen Textur, das selbst von freetype-gl stammt, veranschaulicht dies gut:

Ich vermute, dass die Optimierung der Zeichenplatzierung auf das kleinste Texturproblem ein NP-hartes Problem ist, siehe: Welcher Algorithmus kann verwendet werden, um Rechtecke unterschiedlicher Größe auf eine ziemlich optimale Weise in das kleinstmögliche Rechteck zu packen?

Dieselbe Technik wird in der Webentwicklung verwendet, um mehrere kleine Bilder (wie Symbole) gleichzeitig zu übertragen. Dort heißt sie jedoch "CSS-Sprites": https://css-tricks.com/css-sprites/ = und dienen dazu, die Latenz des Netzwerks anstelle der CPU/GPU-Kommunikation auszublenden.

Nicht-CPU-Rastermethoden

Es gibt auch Methoden, die das CPU-Raster nicht für Texturen verwenden.

Das CPU-Rastering ist einfach, da die GPU so wenig wie möglich verwendet wird. Wir überlegen jedoch auch, ob die GPU-Effizienz weiter genutzt werden kann.

Dieses FOSDEM 2014 Video erklärt andere existierende Techniken:

Schriften innerhalb der 3D-Geometrie mit Perspektive

Das Rendern von Schriftarten innerhalb der 3D-Geometrie mit Perspektive (im Vergleich zu einer orthogonalen Schwebepalette) ist viel komplizierter, da durch die Perspektive ein Teil des Zeichens viel näher am Bildschirm und größer als der andere Teil sein kann, wodurch eine einheitliche CPU-Diskretisierung (z. B. Raster, Tesselation) sehen auf den nahen Teil schlecht aus. Dies ist eigentlich ein aktives Forschungsthema:

enter image description here

Distanzfelder sind jetzt eine der beliebtesten Techniken.

Implementierungen

Die folgenden Beispiele wurden alle unter Ubuntu 15.10 getestet.

Da dies, wie bereits erwähnt, ein komplexes Problem ist, sind die meisten Beispiele sehr umfangreich und würden das 30-KB-Zeichen-Limit dieser Antwort sprengen. Klonen Sie einfach die entsprechenden Git-Repositorys, um sie zu kompilieren.

Sie sind jedoch alle vollständig Open Source, sodass Sie nur RTFS verwenden können.

FreeType-Lösungen

FreeType sieht aus wie die vorherrschende Open-Source-Rasterisierungsbibliothek für Schriftarten, sodass TrueType- und OpenType-Schriftarten verwendet werden können. Dies ist die eleganteste Lösung.

Beispiele/Tutorials:

Andere Font-Rasterizer

Diese scheinen weniger gut als FreeType zu sein, sind aber möglicherweise leichter:

Antons OpenGL 4 Tutorials Beispiel 26 "Bitmap-Schriften"

Die Schrift wurde vom Autor manuell erstellt und in einer einzigen .png - Datei gespeichert. Buchstaben werden in Form eines Arrays im Bild gespeichert.

Diese Methode ist natürlich nicht sehr allgemein und Sie hätten Schwierigkeiten mit der Internationalisierung.

Bauen mit:

make -f Makefile.linux64

Ausgabevorschau:

enter image description here

opengl-Tutorial Kapitel 11 "2D-Schriften"

Texturen werden aus DDS-Dateien generiert.

Das Tutorial erklärt, wie die DDS-Dateien mit CBFG und Paint.Net erstellt wurden.

Ausgabevorschau:

enter image description here

Aus irgendeinem Grund fehlt Suzanne für mich, aber der Zeitzähler funktioniert einwandfrei: https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

GLUT hat glutStrokeCharacter und FreeGLUT ist Open Source ... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

OpenGLText

https://github.com/tlorach/OpenGLText

TrueType-Raster. Von einem NVIDIA-Mitarbeiter. Strebt nach Wiederverwendbarkeit. Habe es noch nicht ausprobiert.

ARM Mali GLES SDK-Beispiel

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ scheint alle Zeichen in einem PNG zu kodieren und von dort auszuschneiden.

SDL_ttf

enter image description here

Quelle: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c

Lebt in einem separaten SDL-Baum und lässt sich problemlos integrieren.

Bietet jedoch keine Texturatlas-Implementierung, sodass die Leistung eingeschränkt ist: Wie können Schriftarten und Text mit SDL2 effizient gerendert werden?

Verwandte Themen

Das Zeichnen von Text in OpenGL ist keine einfache Aufgabe. Sie sollten sich dazu wahrscheinlich Bibliotheken ansehen (entweder anhand einer Bibliothek oder als Beispielimplementierung).

Einige gute Ausgangspunkte könnten GLFont , OpenGL Font Survey und NeHe Tutorial für Bitmap-Schriften (Windows) sein.

Beachten Sie, dass Bitmaps nicht die einzige Möglichkeit sind, Text in OpenGL zu erstellen, wie in der Schriftartumfrage erwähnt.

8
larsmoa

enter image description here

Verwenden Sie glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString).

Ein Beispiel: Ein STAR WARS SCROLLER.

#include <windows.h>
#include <string.h>
#include <GL\glut.h>
#include <iostream.h>
#include <fstream.h>

GLfloat UpwardsScrollVelocity = -10.0;
float view=20.0;

char quote[6][80];
int numberOfQuotes=0,i;

//*********************************************
//*  glutIdleFunc(timeTick);                  *
//*********************************************

void timeTick(void)
{
    if (UpwardsScrollVelocity< -600)
        view-=0.000011;
    if(view < 0) {view=20; UpwardsScrollVelocity = -10.0;}
    //  exit(0);
    UpwardsScrollVelocity -= 0.015;
  glutPostRedisplay();

}


//*********************************************
//* printToConsoleWindow()                *
//*********************************************

void printToConsoleWindow()
{
    int l,lenghOfQuote, i;

    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);

        for (i = 0; i < lenghOfQuote; i++)
        {
          //cout<<quote[l][i];
        }
          //out<<endl;
    }

}

//*********************************************
//* RenderToDisplay()                       *
//*********************************************

void RenderToDisplay()
{
    int l,lenghOfQuote, i;

    glTranslatef(0.0, -100, UpwardsScrollVelocity);
    glRotatef(-20, 1.0, 0.0, 0.0);
    glScalef(0.1, 0.1, 0.1);



    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);
        glPushMatrix();
        glTranslatef(-(lenghOfQuote*37), -(l*200), 0.0);
        for (i = 0; i < lenghOfQuote; i++)
        {
            glColor3f((UpwardsScrollVelocity/10)+300+(l*10),(UpwardsScrollVelocity/10)+300+(l*10),0.0);
            glutStrokeCharacter(GLUT_STROKE_ROMAN, quote[l][i]);
        }
        glPopMatrix();
    }

}
//*********************************************
//* glutDisplayFunc(myDisplayFunction);       *
//*********************************************

void myDisplayFunction(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  gluLookAt(0.0, 30.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  RenderToDisplay();
  glutSwapBuffers();
}
//*********************************************
//* glutReshapeFunc(reshape);               *
//*********************************************

void reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60, 1.0, 1.0, 3200);
  glMatrixMode(GL_MODELVIEW);
}

//*********************************************
//* int main()                                *
//*********************************************


int main()
{
    strcpy(quote[0],"Luke, I am your father!.");
    strcpy(quote[1],"Obi-Wan has taught you well. ");
    strcpy(quote[2],"The force is strong with this one. ");
    strcpy(quote[3],"Alert all commands. Calculate every possible destination along their last known trajectory. ");
    strcpy(quote[4],"The force is with you, young Skywalker, but you are not a Jedi yet.");
    numberOfQuotes=5;

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 400);
    glutCreateWindow("StarWars scroller");
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glLineWidth(3);

    glutDisplayFunc(myDisplayFunction);
    glutReshapeFunc(reshape);
    glutIdleFunc(timeTick);
    glutMainLoop();

    return 0;
}
8

Dieser Artikel beschreibt das Rendern von Text in OpenGL mit verschiedenen Techniken.

Wenn Sie nur opengl verwenden, gibt es mehrere Möglichkeiten:

  • mit glBitmap
  • texturen verwenden
  • verwenden von Anzeigelisten
6
BЈовић

Laden Sie ein Bild mit Zeichen als Textur und zeichnen Sie den Teil dieser Textur abhängig von dem gewünschten Zeichen. Sie können diese Textur mit einem Paint-Programm erstellen, fest codieren oder eine Fensterkomponente verwenden, um ein Bild zu zeichnen und dieses Bild abzurufen, um eine genaue Kopie der Systemschriftarten zu erhalten.

Es ist nicht erforderlich, Glut oder eine andere Erweiterung zu verwenden, lediglich die grundlegende OpenGL-Bedienbarkeit. Es wird die Arbeit erledigt, ganz zu schweigen davon, dass es seit Jahrzehnten von professionellen Programmierern in sehr erfolgreichen Spielen und anderen Anwendungen so gemacht wird.

2
RolanDecoy

Ich denke, dass die beste Lösung zum Zeichnen von Text in OpenGL Texturen sind, ich arbeite lange mit ihnen. Sie sind flexibel, schnell und sehen gut aus (mit einigen hinteren Ausnahmen). Ich verwende ein spezielles Programm zum Konvertieren von Schriftdateien (zum Beispiel .ttf) in Texturen, die in einer Datei im internen "Schrift" -Format gespeichert werden (ich habe ein Format und ein Programm entwickelt, das auf http: //content.gpwiki) basiert .org/index.php/OpenGL: Tutorials: Font_System obwohl meine Version ziemlich weit von der ursprünglichen Unicode-Unterstützung entfernt war und so weiter. Beim Start der Haupt-App werden Schriften aus diesem "internen" Format geladen. Siehe Link oben für weitere Informationen.

Bei diesem Ansatz verwendet die Haupt-App keine speziellen Bibliotheken wie FreeType, was auch für mich unerwünscht ist. Text wird mit Standard-OpenGL-Funktionen gezeichnet.

1
Yury