texto letras c++ c opengl graphics

c++ - letras - ¿Cómo dibujar texto usando solo métodos OpenGL?



opengl text (6)

Teoría

Por qué es difícil

Los formatos de fuentes populares como TrueType y OpenType son formatos de contorno vectorial: usan curvas de Bezier para definir el límite de la letra.

Fuente de la imagen

La transformación de esos formatos en matrices de píxeles (rasterización) es demasiado específica y está fuera del alcance de OpenGL, especialmente porque OpenGl no tiene primitivas no rectas (por ejemplo, vea ¿Por qué no hay círculo o primitiva de elipse en OpenGL? )

El enfoque más sencillo es utilizar las primeras fuentes de ráster en la CPU y luego asignar la matriz de píxeles a OpenGL como textura.

OpenGL entonces sabe cómo manejar arreglos de píxeles a través de texturas muy bien.

Atlas de textura

Podríamos trazar caracteres en cada cuadro y volver a crear las texturas, pero eso no es muy eficiente, especialmente si los caracteres tienen un tamaño fijo.

El enfoque más eficiente es rastrear todos los caracteres que planea usar y meterlos en una sola textura.

Y luego transfiéralo a la GPU una vez, y utilícelo texturas con coordenadas uv personalizadas para elegir el personaje correcto.

Este enfoque se llama https://en.wikipedia.org/wiki/Texture_atlas y se puede utilizar no solo para texturas sino también para otras texturas usadas repetidamente, como mosaicos en un juego 2D o íconos de interfaz de usuario web.

La imagen de Wikipedia de la textura completa, que en sí misma está tomada de freetype-gl, ilustra esto bien:

Sospecho que la optimización de la colocación de caracteres para el problema de textura más pequeño es un problema NP-hard, consulte: ¿Qué algoritmo se puede utilizar para empaquetar rectángulos de diferentes tamaños en el rectángulo más pequeño posible de una manera bastante óptima?

La misma técnica se usa en el desarrollo web para transmitir varias imágenes pequeñas (como iconos) a la vez, pero allí se llama "CSS Sprites": https://css-tricks.com/css-sprites/ y se utilizan para ocultar el latencia de la red en lugar de la comunicación CPU / GPU.

Métodos ráster sin CPU

También existen métodos que no usan el ráster de la CPU para texturas.

El raspado de la CPU es simple porque usa la GPU lo menos posible, pero también comenzamos a pensar si sería posible usar aún más la eficiencia de la GPU.

Este video de FOSDEM 2014 https://youtu.be/LZis03DXWjE?t=886 explica otras técnicas existentes:

Fuentes dentro de la geometría 3D con perspectiva

Renderizar fuentes dentro de la geometría 3D con perspectiva (en comparación con un HUD ortogonal) es mucho más complicado, porque la perspectiva podría hacer que una parte del personaje esté mucho más cerca de la pantalla y más grande que la otra, haciendo una discretización uniforme de la CPU (por ejemplo, raster tesselación) se ven mal en la parte más cercana. Este es en realidad un tema de investigación activo:

Los campos de distancia son una de las técnicas populares ahora.

Implementaciones

Los ejemplos que siguen fueron todos probados en Ubuntu 15.10.

Debido a que este es un problema complejo como se discutió anteriormente, la mayoría de los ejemplos son grandes, y explotarían el límite de 30k de esta respuesta, así que solo clone los repositorios Git respectivos para compilar.

Sin embargo, todos son de código abierto, por lo que solo puede RTFS.

Soluciones FreeType

FreeType parece a la biblioteca de rasterización de fuentes de código abierto dominante, por lo que nos permitiría usar fuentes TrueType y OpenType, por lo que es la solución más elegante.

Ejemplos / tutoriales:

Otros rasterizadores de fuentes

Esos parecen menos buenos que FreeType, pero pueden ser más livianos:

Ejemplos de tutoriales de OpenGL 4 de Anton 26 "Fuentes de mapa de bits"

La fuente fue creada por el autor de forma manual y almacenada en un solo archivo .png . Las letras se almacenan en forma de matriz dentro de la imagen.

Este método, por supuesto, no es muy general, y tendría dificultades con la internacionalización.

Construir con:

make -f Makefile.linux64

Vista previa de salida:

opengl-tutorial capítulo 11 "Fuentes 2D"

Las texturas se generan a partir de archivos DDS .

El tutorial explica cómo se crearon los archivos DDS, utilizando CBFG y Paint.Net .

Vista previa de salida:

Por alguna razón, Suzanne me falta, pero el contador de tiempo funciona bien: https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

GLUT tiene glutStrokeCharacter y FreeGLUT es de código abierto ... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

OpenGLText

https://github.com/tlorach/OpenGLText

Ráster TrueType. Por empleado de NVIDIA. Tiene como objetivo la reutilización. No lo he intentado todavía

Muestra de ARM Mali GLES SDK

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ parece codificar todos los caracteres en un PNG, y cortarlos desde allí.

SDL_ttf

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

Vive en un árbol separado para SDL, y se integra fácilmente.

Sin embargo, no proporciona una implementación de atlas de texturas, por lo que el rendimiento será limitado: ¿cómo renderizar fuentes y texto con SDL2 de manera eficiente?

Temas relacionados

No tengo la opción de usar, pero los métodos OpenGL (es glxxx() métodos glxxx() ). Necesito dibujar texto usando solo métodos gl. Después de leer el libro rojo, entiendo que solo es posible a través del método glBitmap() . Si esta es la única forma posible, entonces ¿alguien me puede ayudar con la información de la matriz de píxeles para todos los personajes? ¿Hay alguna otra forma de dibujar texto?


Cargue una imagen con caracteres como textura y dibuje la parte de esa textura según el carácter que desee. Puede crear esa textura usando un programa de pintura, codificarlo o usar un componente de ventana para dibujar una imagen y recuperar esa imagen para obtener una copia exacta de las fuentes del sistema.

No es necesario utilizar Glut o cualquier otra extensión, solo la operatividad básica de OpenGL. Hace el trabajo, sin mencionar que ha sido hecho así durante décadas por programadores profesionales en juegos exitosos y otras aplicaciones.


Creo que la mejor solución para dibujar texto en OpenGL son las fuentes de textura. Trabajo con ellas durante mucho tiempo. Son flexibles, rápidos y bonitos (con algunas excepciones posteriores). Utilizo un programa especial para convertir archivos de fuentes (.ttf, por ejemplo) en texturas, que se guardan en archivos de algún formato interno de "fuente" (he desarrollado formatos y programas basados ​​en http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System aunque mi versión fue bastante lejos de la original de Unicode, y así sucesivamente). Al iniciar la aplicación principal, las fuentes se cargan desde este formato "interno". Mire el enlace de arriba para más información.

Con ese enfoque, la aplicación principal no usa ninguna biblioteca especial como FreeType, lo que tampoco me conviene. El texto se dibuja utilizando las funciones estándar de OpenGL.


Dibujar texto en OpenGL no es una tarea directa. Probablemente debería echar un vistazo a las bibliotecas para hacer esto (ya sea mediante el uso de una biblioteca o como una implementación de ejemplo).

Algunos buenos puntos de partida podrían ser GLFont , OpenGL Font Survey y NeHe Tutorial para Bitmap Fonts (Windows) .

Tenga en cuenta que los mapas de bits no son la única forma de lograr texto en OpenGL como se menciona en la encuesta de fuente.


Este artículo describe cómo renderizar texto en OpenGL usando varias técnicas.

Con solo usar OpenGL, hay varias formas:

  • usando glBitmap
  • usando texturas
  • usando listas de visualización

Usa glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString) .

Un ejemplo: un STAR WARS SCROLLER.

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