52 votes

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

Je n'ai pas la possibilité d'utiliser uniquement les méthodes OpenGL (c'est-à-dire 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 le biais de la méthode glBitmap() méthode. Si c'est la seule méthode possible, quelqu'un peut-il m'aider à obtenir les informations sur les tableaux de pixels pour tous les caractères ? Existe-t-il une autre façon de dessiner du texte ?

100voto

Ciro Santilli Points 3341

Théorie

Pourquoi c'est difficile

Les formats de polices les plus courants, tels que TrueType y OpenType sont des formats vectoriels : ils utilisent Courbes de Bézier pour définir la limite de la lettre.

Source de l'image .

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

L'approche la plus simple est de commencer par tramer les polices nous-mêmes sur le processeur, puis de donner le tableau de pixels à OpenGL en tant que texture.

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

Atlas des textures

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

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

Ensuite, on transfère le tout au GPU une fois, et on utilise la texture avec des coordonnées uv personnalisées pour choisir le bon personnage.

Cette approche est appelée atlas des textures et il peut être utilisé non seulement pour les textures, mais aussi pour d'autres textures utilisées de manière répétée, comme les tuiles d'un jeu en 2D ou les icônes d'une interface web.

L'image Wikipédia de la texture complète, qui est elle-même tirée de freetype-gl, l'illustre bien :

Je soupçonne que l'optimisation du placement des personnages pour obtenir la plus petite texture possible est un problème NP-hard, voir : Quel algorithme permet de placer des rectangles de différentes tailles dans le plus petit rectangle possible de manière relativement optimale ?

La même technique est utilisée dans le développement web pour transmettre plusieurs petites images (comme des icônes) en une seule fois, mais elle est appelée "CSS Sprites" : https://css-tricks.com/css-sprites/ et sont utilisés pour masquer la latence du réseau plutôt que celle de la communication entre le CPU et le GPU.

Méthodes raster non-CPU

Il existe également des méthodes qui n'utilisent pas la trame de l'unité centrale pour les textures.

Le tramage par CPU est simple car il utilise le GPU le moins possible, mais nous commençons à nous demander s'il serait possible d'utiliser davantage l'efficacité du GPU.

Cette vidéo du FOSDEM 2014 explique les 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 la perspective (par rapport à un HUD orthogonal) est beaucoup plus compliqué, parce que la perspective peut rendre une partie du personnage beaucoup plus proche de l'écran et plus grande que l'autre, ce qui fait qu'une discrétisation uniforme du CPU (par exemple, raster, tesselation) semble mauvaise sur la partie la plus proche. Il s'agit d'un sujet de recherche actif :

enter image description here

Champs de distance sont l'une des techniques les plus répandues aujourd'hui.

Mise en œuvre

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

Comme il s'agit d'un problème complexe, la plupart des exemples sont volumineux et dépasseraient la limite de 30 000 caractères de cette réponse, il suffit donc de cloner les dépôts Git respectifs pour compiler.

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

Solutions FreeType

FreeType semble être la bibliothèque de tramage de polices open source dominante, ce qui nous permettrait d'utiliser des polices TrueType et OpenType, ce qui en fait la solution la plus élégante.

Exemples / tutoriels :

Autres rastériseurs de polices

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

Anton's OpenGL 4 Tutorials exemple 26 "Polices bitmap"

La police de caractères a été créée manuellement par l'auteur et stockée dans un fichier unique. .png dossier. 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 rencontrerez des difficultés avec l'internationalisation.

Construire avec :

make -f Makefile.linux64

Aperçu de la sortie :

enter image description here

opengl-tutorial chapitre 11 "Polices 2D"

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

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

Aperçu de la sortie :

enter image description here

Pour une raison quelconque, Suzanne n'apparaît pas dans mon cas, mais le compteur de temps fonctionne correctement : https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

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

OpenGLText

https://github.com/tlorach/OpenGLText

TrueType raster. Par un employé de NVIDIA. Vise la réutilisation. Je ne l'ai pas encore essayé.

Exemple de SDK ARM Mali GLES

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

SDL_ttf

enter image description here

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

Il vit dans une arborescence distincte de celle de SDL et s'intègre facilement.

Cependant, il ne fournit pas d'atlas de texture, ce qui limite les performances : Comment rendre efficacement les polices et le texte avec SDL2 ?

Filets apparentés

9voto

larsm Points 5337

Dessiner du texte en OpenGL n'est pas une tâche facile. Vous devriez probablement jeter un coup d'oeil aux bibliothèques qui permettent de le faire (soit en utilisant une bibliothèque, soit en utilisant un exemple d'implémentation).

Voici quelques bons points de départ GLFont , Enquête sur les polices OpenGL y Tutoriel NeHe pour les polices bitmap (Windows) .

Notez que les bitmaps ne sont pas le seul moyen d'obtenir du texte en OpenGL, comme le mentionne l'étude sur les polices.

8voto

BЈовић Points 28674

Cet article décrit comment rendre un texte en OpenGL en utilisant différentes techniques.

En utilisant uniquement opengl, il y a plusieurs façons de procéder :

  • en utilisant glBitmap
  • l'utilisation de textures
  • l'utilisation des listes d'affichage

8voto

Software_Developer Points 3082

enter image description here

Utilisation glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString) .

Un exemple : UN ROULEAU DE LA GUERRE DES ÉTOILES.

#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;
}

51 votes

GlutStrokeCharacter n'est pas une fonction opengl

19 votes

Il correspond à l'exigence de l'OP glxxx() :)

1 votes

Voici le code modifié pour fonctionner sur Ubuntu (glutInit, includes) : gist.github.com/tgandor/3963f112324030a2c833

4voto

RolanDecoy Points 29

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

Il n'est pas nécessaire d'utiliser Glut ou toute autre extension, il suffit d'utiliser les fonctions de base d'OpenGL. C'est ce qu'il faut faire, sans oublier que cela fait des décennies que des programmeurs professionnels le font ainsi, dans des jeux et autres applications qui ont beaucoup de succès.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X