web-dev-qa-db-fra.com

Comment faire le rendu de texte OpenGL en direct pour une interface graphique?

J'implémente une interface graphique basée sur OpenGL. Je suis arrivé au problème que chaque interface graphique aura - le rendu du texte. Je connais plusieurs méthodes de rendu de texte en OpenGL, cependant, je me demande laquelle d'entre elles serait la mieux adaptée à une interface graphique.

Généralement, dans une interface graphique, nous avons deux types de texte - statique et en direct. La statique est assez facile - nous pouvons rendre un TTF à une texture et l'oublier. C'est le texte "en direct" qui me dérange le plus - imaginez une console ou un chat en direct dans un jeu multi-joueurs.

J'ai pensé à plusieurs options:

  • pas de cas particulier - restituez et chargez une texture à chaque fois que le texte change, en gardant à l'esprit de le restituer uniquement lorsque du nouveau texte apparaît, et en essayant de diviser le texte plus grand en petites parties (comme par ligne de discussion). Cependant, cela nous laisserait toujours suspendus dans des cas comme une ligne de partition qui change tout le temps ou un texte d'introduction qui s'affiche "par caractère" (style de machine à écrire vu dans certains jeux de science-fiction)
  • quadruple par caractère - cela semble également une solution populaire, vous préparez une texture avec la table ASCII et rendez un caractère quadruple texturé. Cependant, j'ai de sérieux doutes quant à l'efficacité d'une telle solution Des conseils sur la façon d'accélérer cela seraient également les bienvenus.
  • solutions hybrides - mais je n'ai aucune idée de comment implémenter cela proprement

La question est donc - comment rendre le texte dans OpenGL efficacement?

Si cela aide, je code en C++ STL/Boost-heavy et vise les cartes graphiques GForce 6 et ultérieures.

41
Kornel Kisielewicz

EDIT2: Sean Barrett vient de sortir polices bitmap pour les programmeurs C/C++ 3D .

EDIT: un autre joyau de code qui vaut le détour est Stash de police qui s'appuie sur Sean Barrett stb_truetype.h .


Vous pouvez créer une texture dans laquelle vous rendez tous les caractères de votre police. Ensuite, vous dessinez simplement des quads texturés avec une projection orthographique et des coordonnées de texture appropriées: cette approche fonctionne lorsque votre texte est dans une langue qui ne contient pas beaucoup de symboles: comme l'anglais. La texture de la police est créée une fois au début de l'application, puis le rendu des quads est très rapide.

C'est ce que j'utilise et je pense que c'est le moyen le plus rapide de rendre du texte en OpenGL. Au début, j'ai utilisé l'outil Angelcode's Bitmap Font Generator puis j'ai intégré FreeType directement et construit une grande texture contenant tous les glyphes au lancement de l'application. Quant aux astuces pour améliorer la vitesse de rendu des quads, je viens d'utiliser le VBO comme pour le reste de la géométrie dans mon application.

Je suis surpris que vous ayez des doutes sur le rendu quadruple alors que vous ne semblez pas vous soucier des performances de génération d'une texture sur le processeur, puis de la télécharger, puis de la lier pour finalement rendre un rectangle avec elle, cela pour chaque image. Changer les états d'OpenGL est le goulot d'étranglement, pas les 500 à 1000 quads que vous utiliserez pour le texte.

Jetez également un œil à des bibliothèques comme la bibliothèque FTGL qui convertit toute la police en polygones (polices géométriques).

30
Gregory Pakosz

Essayez de lire ceci: http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1 .

L'approche décrite est la méthode typique pour le rendu de texte avec des API graphiques. Un caractère par quadruple et toutes les données d'image pour le texte dans une seule texture. Si vous pouvez adapter l'ensemble de votre jeu de caractères dans une seule texture (en fait, selon la taille de la texture, vous pourrez peut-être en ajuster plusieurs), le rendu est extrêmement rapide.

La clé est que la liaison de texture est l'opération que vous devez minimiser. Si vous pouvez rendre tout votre texte avec une seule texture, peu importe la quantité de texte que vous devez mettre à l'écran. Même si vous devez changer de texture plusieurs fois (différentes polices, différents attributs de police [gras, souligné, etc.]), les performances devraient toujours être bonnes. Les performances du texte peuvent être plus critiques pour un HUD, mais elles sont moins importantes dans l'interface graphique.

9
luke

Vous pouvez rendre le texte sous forme de faces triangulées et éviter d'utiliser une texture. De cette façon, vous évitez les bords flous lorsque le texte est zoomé. J'ai créé une police low poly ASCII open source et disponible sur mon github .

Une autre façon d'avoir des arêtes vives sur votre texte est rendu de police SDF , mais cela souffre de certains artefacts.

5
Bram

pourrait simplement utiliser ces deux fonctions:

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]);
}

puis, lorsque vous effectuez le rendu de texte 2D, n'oubliez pas de réinitialiser à la fois la vue du modèle et les matrices de projection.

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

// Render text and quads

glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

Vous n'avez pas besoin de faire un rendu sur un quad à l'aide de ces fonctions, car ces fonctions sont rendues directement sur le framebuffer.

Et si cela ne fonctionne pas pour vous, vérifiez cela. http://www.opengl.org/resources/faq/technical/fonts.htm

Il parle du rendu du texte à l'aide de glBitmap, glDrawPixels et du mélange alpha.

1
Ned Bingham

Par quadruple caractère traité, une liste d'affichage (mise à jour uniquement lorsque le texte change) est suffisante pour la plupart des cas.

Je l'ai utilisé avec des polices X11 en utilisant XLoadQueryFont, glGenLists, glXUseXFont, glCallLists vous avez un tableau de listes d'affichage décrivant chaque caractère.

la fonction glCallLists accepte un argument char * pour votre texte et il peut être incorporé dans une liste d'affichage.

Vous vous retrouvez donc avec un seul appel pour afficher le texte des blocs.

La texture de police suggérée par G. Pakosz est similaire, mais vous calculez vos propres listes d'affichage "par caractère".

Vos premières options seront assez lentes car elles nécessiteront un rendu basé sur le processeur à chaque changement de texte.

1
fa.

C'est délicat à faire, surtout si vous souhaitez utiliser des techniques de rendu de police sous-pixel. Jetez un œil au ClanLib SDK . Il utilise un moteur de rendu par lots pour restituer un écran entier de texte en un seul appel OpenGL. Puisqu'il a une licence basée sur zlib, vous pouvez extraire son code si vous ne souhaitez pas utiliser le SDK lui-même

1
rombust