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?
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.
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:
- tessellation: convertissez la police en petits triangles. Le GPU est alors vraiment bon à dessiner des triangles. Inconvénient:
- génère un tas de triangles
- O(N log n) CPU calcul des triangles
- calculez les courbes sur les shaders. Un article de Blinn-Loop de 2005 a mis cette méthode sur la carte. Inconvénients: complexes. Voir: cubic bezier indépendant de résolution sur GPU (Blinn / Loop)
- implémentations matérielles directes comme OpenVG https://en.wikipedia.org/wiki/OpenVG . Inconvénient: pas très largement mis en œuvre pour une raison quelconque. Voir:
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:
- Quel est l'état de la technique pour le rendu de textes en OpenGL à partir de la version 4.1?
- http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
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.
-
https://github.com/rougier/freetype-gl
était un ensemble D'exemples D'OpenGL et freetype, mais évolue plus ou moins vers une bibliothèque qui le fait et expose une API décente.
dans tous les cas, il devrait déjà être possible de l'intégrer sur votre projet en copiant du code source.
il fournit à la fois l'atlas de texture et les techniques de champ de distance hors de la boîte.
Démos sous: https://github.com/rougier/freetype-gl/tree/master/demos
n'a pas de paquet Debian, et c'est pénible de compiler sur Ubuntu 15.10: https://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527 (problèmes d'emballage, certains en amont), mais il s'est amélioré à partir de 16.10.
N'a pas une méthode d'installation agréable: https://github.com/rougier/freetype-gl/issues/115
génère de belles sorties comme cette démo:
-
libdgx https://github.com/libgdx/libgdx/tree/1.9.2/extensions/gdx-freetype
exemples / tutoriels:
- un NEHE tutoriel: http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001 /
- http://learnopengl.com/#!In-Practice / Text-Rendering le mentionne, mais je n'ai pas pu trouver de code source exécutable
- donc questions:
police de rasterizers
ceux-ci semblent moins bons que FreeType, mais peuvent être plus légers:
- https://github.com/nothings/stb/blob/master/stb_truetype.h
- http://www.angelcode.com/products/bmfont /
Anton's OpenGL 4 tutoriels exemple 26 "Bitmap fonts "
- tutorial: http://antongerdelan.net/opengl / )
- source: https://github.com/capnramses/antons_opengl_tutorials_book/blob/9a117a649ae4d21d68d2b75af5232021f5957aac/26_bitmap_fonts/main.cpp
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:
opengl-cours chapitre 11 "2D polices"
- tutoriel: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-11-2d-text /
- source: https://github.com/opengl-tutorials/ogl/blob/71cad106cefef671907ba7791b28b19fa2cc034d/tutorial11_2d_fonts/tutorial11.cpp
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:
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
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
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;
}
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.
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
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.
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.