Comment dessiner du texte en utilisant seulement les méthodes OpenGL?

Je n'ai pas le choix d'utiliser les méthodes OpenGL (c'est-à-dire les méthodes glxxx() ). Je dois dessiner du texte en utilisant seulement 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 la seule façon possible, alors quelqu'un peut m'aider avec les informations du tableau de pixels pour tous les caractères. Est-il un autre moyen pour dessiner du texte?

30
demandé sur Alexis Wilke 2012-01-13 12:44:07

6 réponses

théorie

pourquoi c'est dur

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

Image source .

Transformer ces formats en tableaux de pixels (rastérisation) est trop spécifique et hors de la portée D'OpenGL, d'autant plus Qu'OpenGl n'a pas de primitives non-droites (voir par exemple pourquoi N'y a-t-il pas de primitives cercle ou ellipse dans OpenGL? )

l'approche la plus simple est d'abord de créer des polices raster nous-mêmes sur le CPU, puis de donner le tableau de pixels à OpenGL comme texture.

OpenGL sait alors comment traiter les tableaux de pixels à travers les textures très bien.

Texture atlas

nous pourrions assembler 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 est de rassembler tous les caractères que vous prévoyez d'utiliser et de les coller sur une seule texture.

, puis transférer sur le GPU une fois, et utiliser la texture avec coordonnées uv personnalisées pour choisir le bon caractère.

cette approche est appelée https://en.wikipedia.org/wiki/Texture_atlas et il peut être utilisé non seulement pour les textures, mais aussi d'autres textures utilisées à plusieurs reprises, comme des tuiles dans un jeu 2D ou des icônes Web UI.

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

je soupçonne que l'optimisation de l'emplacement des caractères au plus petit problème de texture est un problème NP-hard, voir: quel algorithme peut être utilisé pour l'emballage 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à il est appelé "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.

Non-CPU méthodes matricielles

il existe aussi des méthodes qui n'utilisent pas la trame CPU pour les textures.

CPU râclage est simple parce qu'il utilise le GPU le moins possible, mais nous commençons également à penser si il serait possible d'utiliser l'efficacité du GPU plus.

cette vidéo de FOSDEM 2014 https://youtu.be/LZis03DXWjE?t=886 explique d'autres techniques existantes:

Polices à l'intérieur de la géométrie 3D avec le point de vue

rendre les polices à l'intérieur de la géométrie 3D avec perspective (par rapport à un HUD orthogonal) est beaucoup plus compliqué, parce que la perspective pourrait rendre une partie du caractère beaucoup plus proche de l'écran et plus grand que l'autre, ce qui rend un uniforme La discrétisation CPU (par exemple raster, tesselation) semble Mauvaise sur la partie proche. Il s'agit en fait d'un sujet de recherche actif:

enter image description here

les champs de Distance sont l'une des techniques populaires maintenant.

implémentations

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

parce qu'il s'agit d'un problème complexe comme discuté précédemment, la plupart des exemples sont de grande taille, et feraient exploser la limite de char 30k de cette réponse, donc il suffit de cloner les dépôts Git respectifs pour compiler.

ils sont tous entièrement open source cependant, de sorte que vous pouvez juste RTFS.

FreeType solutions

FreeType ressemble à la bibliothèque de rastérization de police open source dominante, de sorte qu'il nous permettrait d'utiliser des polices TrueType et OpenType, ce qui en fait la solution la plus élégante.

exemples / tutoriels:

police de rasterizers

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

Anton's OpenGL 4 tutoriels exemple 26 "Bitmap fonts "

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

Cette méthode n'est évidemment pas très générales, et vous avez des difficultés avec l'internationalisation.

Construire avec:

make -f Makefile.linux64

aperçu de sortie:

enter image description here

opengl-cours chapitre 11 "2D polices"

les Textures sont générés à partir de DDS fichiers .

le tutoriel explique comment les fichiers DDS étaient créé, en utilisant CBFG et Paint.Net .

aperçu de sortie:

enter image description here

pour une raison quelconque, Suzanne a disparu pour moi, mais le compteur fonctionne très 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

TrueType raster. Par un employé de NVIDIA. Objectifs de réutilisabilité. N'ai pas encore essayé.

ARM Mali GLES SDK Sample

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

SDL_ttf

enter image description here

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

vit dans un arbre séparé de SDL, et s'intègre facilement.

ne fournit pas une implémentation d'atlas de texture, cependant, donc la performance sera limitée: comment rendre les polices et le texte avec SDL2 efficacement?

"151960920 Connexes" threads

42

enter image description here

utiliser glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString) .

un exemple: un rouleau compresseur 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
répondu Software_Designer 2015-05-23 12:20:44

dessiner du texte en clair OpenGL n'est pas une tâche facile. Vous devriez probablement jeter un oeil aux bibliothèques pour faire cela (en utilisant une bibliothèque ou comme exemple d'implémentation).

quelques 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 en OpenGL comme mentionné dans le sondage sur les polices.

7
répondu larsmoa 2012-01-13 08:51:53

cet article décrit comment rendre le texte en OpenGL en utilisant diverses techniques.

avec seulement l'utilisation d'opengl, il y a plusieurs façons:

  • utilisant glBitmap
  • à l'aide de textures
  • à l'aide de l'affichage de listes
5
répondu BЈовић 2012-01-13 08:49:08

chargez une image avec des caractères comme texture et dessinez la partie de cette texture en fonction du caractère que vous voulez. Vous pouvez créer cette texture en utilisant un programme de peinture, en la codant ou en utilisant un composant de fenêtre pour dessiner 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, pour ne pas mentionner qu'il a été fait comme ça pendant des décennies par les professionnels programmeurs dans des jeux très réussis et d'autres applications.

2
répondu RolanDecoy 2014-07-15 21:29:26

je pense que la meilleure solution pour dessiner du texte dans OpenGL est les polices de texture, je travaille avec eux depuis longtemps. Ils sont souples, rapides et beaux (avec quelques exceptions à l'arrière). J'utilise un programme spécial pour convertir des fichiers de police (.ttf par exemple) à la texture, qui est enregistrée dans un fichier d'un certain format interne "font" (j'ai développé un format et un programme basé sur http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System bien que ma version soit allée assez loin de L'Unicode de soutien d'origine et ainsi de suite). Lors du démarrage de l'application principale, les polices sont chargés à partir de cette "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 aussi. Le texte est dessiné à L'aide des fonctions OpenGL standard.

1
répondu Yury 2012-01-13 09:05:59