web-dev-qa-db-fra.com

Comment dessiner du texte en utilisant uniquement des méthodes OpenGL?

Je n'ai pas la possibilité d'utiliser mais les méthodes OpenGL (c'est-à-dire les méthodes glxxx()). J'ai besoin de dessiner du texte en utilisant uniquement les méthodes gl. Après avoir lu le livre rouge, je comprends que cela n'est possible que par la méthode glBitmap(). Si c'est le seul moyen possible, alors quelqu'un peut-il m'aider avec les informations du tableau de pixels pour tous les personnages. Existe-t-il une autre façon de dessiner du texte?

36
sathish v

Théorie

Pourquoi c'est difficile

Les formats de police populaires comme TrueType et OpenType sont des formats vectoriels: ils utilisent courbes de Bézier pour définir la limite de la lettre.

Source d'image .

La transformation de ces formats en tableaux de pixels (rastérisation) est trop spécifique et hors de portée d'OpenGL, spécialement parce que OpenGl n'a pas de primitives non droites (par exemple, voir Pourquoi n'y a-t-il pas de primitive de cercle ou d'ellipse dans OpenGL? )

L'approche la plus simple consiste à commencer par raster les polices nous-mêmes sur le processeur, puis à donner le tableau de pixels à OpenGL sous forme de texture.

OpenGL sait alors très bien gérer les tableaux de pixels à travers les textures.

Atlas de textures

Nous pourrions raster des caractères pour chaque image et recréer les textures, mais ce n'est pas très efficace, surtout si les caractères ont une taille fixe.

L'approche la plus efficace consiste à tramer tous les personnages que vous prévoyez d'utiliser et à les entasser sur une seule texture.

Ensuite, transférez cela au GPU une fois et utilisez-le texture avec des coordonnées uv personnalisées pour choisir le bon caractère.

Cette approche est appelée atlas de texture et elle peut être utilisée non seulement pour les textures, mais aussi pour d'autres textures utilisées à plusieurs reprises, comme les tuiles dans un jeu 2D ou les icônes de l'interface utilisateur Web.

L'image Wikipedia de la texture complète, elle-même tirée de freetype-gl, illustre bien cela:

Je soupçonne que l'optimisation du placement des caractères pour le plus petit problème de texture est un problème NP-difficile, voir: Quel algorithme peut être utilisé pour emballer des rectangles de différentes tailles dans le plus petit rectangle possible d'une manière assez optimale?

La même technique est utilisée dans le développement Web pour transmettre plusieurs petites images (comme des icônes) à la fois, mais là on l'appelle "CSS Sprites": https://css-tricks.com/css-sprites/ = et sont utilisés pour masquer la latence du réseau au lieu de celle de la communication CPU/GPU.

Méthodes raster non-CPU

Il existe également des méthodes qui n'utilisent pas le raster CPU pour les textures.

Le rastering du processeur est simple car il utilise le moins possible le GPU, mais nous commençons également à penser s'il serait possible d'utiliser davantage l'efficacité du GPU.

Cette vidéo FOSDEM 2014 explique d'autres techniques existantes:

Polices à l'intérieur de la géométrie 3D avec perspective

Le rendu des polices à l'intérieur de la géométrie 3D avec perspective (par rapport à un HUD orthogonal) est beaucoup plus compliqué, car la perspective pourrait rendre une partie du personnage beaucoup plus proche de l'écran et plus grande que l'autre, créant ainsi une discrétisation uniforme du processeur (par exemple raster, tesselation) semblent mauvais sur la partie proche. Il s'agit en fait d'un sujet de recherche actif:

enter image description here

Champs de distance sont maintenant l'une des techniques les plus utilisées.

Implémentations

Les exemples qui suivent ont tous été testés sur Ubuntu 15.10.

Parce que c'est un problème complexe comme discuté précédemment, la plupart des exemples sont grands et feraient exploser la limite de 30k caractères de cette réponse, il suffit donc de cloner les référentiels Git respectifs à compiler.

Cependant, ils sont tous entièrement open source, vous pouvez donc simplement RTFS.

Solutions FreeType

FreeType ressemble à la bibliothèque de rastérisation de polices open source dominante, elle nous permettrait donc d'utiliser les polices TrueType et OpenType, ce qui en fait la solution la plus élégante.

Exemples/tutoriels:

Autres tramages de polices

Ceux-ci semblent moins bons que FreeType, mais peuvent être plus légers:

Tutoriels OpenGL 4 d'Anton, exemple 26 "Polices Bitmap"

La police a été créée manuellement par l'auteur et stockée dans un seul .png fichier. Les lettres sont stockées sous forme de tableau à l'intérieur de l'image.

Cette méthode n'est bien sûr pas très générale et vous auriez des difficultés avec l'internationalisation.

Construisez avec:

make -f Makefile.linux64

Aperçu de sortie:

enter image description here

Opengl-Tutorial Chapter 11 "Polices 2D"

Les textures sont générées à partir de fichiers DDS .

Le didacticiel explique comment les fichiers DDS ont été créés, à l'aide de CBFG et Paint.Net .

Aperçu de sortie:

enter image description here

Pour une raison quelconque, Suzanne manque pour moi, mais le compteur de temps fonctionne bien: https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

GLUT a glutStrokeCharacter et FreeGLUT est open source ... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

OpenGLText

https://github.com/tlorach/OpenGLText

Trame TrueType. Par un employé de NVIDIA. Vise à être réutilisable. Je ne l'ai pas encore essayé.

Exemple de SDK ARM Mali GLES

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ semble coder tous les caractères sur un PNG et les couper à partir de là.

SDL_ttf

enter image description here

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

Vit dans une arborescence distincte de SDL et s'intègre facilement.

Cependant, ne fournit pas d'implémentation d'atlas de texture, donc les performances seront limitées: Comment rendre efficacement les polices et le texte avec SDL2?

Sujets associés

Dessiner du texte en clair OpenGL n'est pas une tâche directe. Vous devriez probablement jeter un œil aux bibliothèques pour ce faire (soit en utilisant une bibliothèque soit comme exemple d'implémentation).

Certains bons points de départ pourraient être GLFont , OpenGL Font Survey et NeHe Tutorial for Bitmap Fonts (Windows) .

Notez que les bitmaps ne sont pas le seul moyen d'obtenir du texte dans OpenGL comme mentionné dans l'enquête sur les polices.

8
larsmoa

enter image description here

Utilisez glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString).

Un exemple: UN DÉMARREUR STAR WARS.

#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
Software_Designer

Cet article décrit comment rendre du texte dans OpenGL en utilisant diverses techniques.

En utilisant uniquement opengl, il existe plusieurs façons:

  • en utilisant glBitmap
  • en utilisant des textures
  • à l'aide de listes d'affichage
6
BЈовић

Chargez une image avec des caractères comme texture et dessinez la partie de cette texture en fonction du caractère que vous souhaitez. Vous pouvez créer cette texture à l'aide d'un programme Paint, la coder en dur ou utiliser un composant de fenêtre pour dessiner sur une image et récupérer cette image pour une copie exacte des polices système.

Pas besoin d'utiliser Glut ou toute autre extension, juste l'opérabilité OpenGL de base. Il fait le travail, sans oublier que cela a été fait comme ça pendant des décennies par des programmeurs professionnels dans des jeux très réussis et d'autres applications.

2
RolanDecoy

Je pense que la meilleure solution pour dessiner du texte en OpenGL est les polices de texture, je travaille avec elles depuis longtemps. Ils sont flexibles, rapides et agréables (à quelques exceptions près). J'utilise un programme spécial pour convertir des fichiers de polices (.ttf par exemple) en texture, qui est enregistré dans un fichier de format "police" interne (j'ai développé un format et un programme basés sur http: //content.gpwiki .org/index.php/OpenGL: Tutoriels: Font_System bien que ma version soit assez loin de l'Unicode de support d'origine et ainsi de suite). Lors du démarrage de l'application principale, les polices sont chargées à partir de ce format "interne". Regardez le lien ci-dessus pour plus d'informations.

Avec une telle approche, l'application principale n'utilise pas de bibliothèques spéciales comme FreeType, ce qui n'est pas souhaitable pour moi également. Le texte est dessiné à l'aide des fonctions OpenGL standard.

1
Yury