2010-01-15 31 views
37

Estoy implementando una GUI construida sobre OpenGL. Llegué al problema que tendrá cada GUI: representación de texto. Sé de varios métodos para renderizar texto en OpenGL, sin embargo, me pregunto cuál de ellos sería el más adecuado para una GUI.¿Cómo hacer el renderizado de texto en vivo de OpenGL para una GUI?

Generalmente en una GUI tenemos dos tipos de texto: estático y en vivo. La estática es bastante fácil: podemos convertir un TTF en una textura y olvidarnos de ella. Es el texto "en vivo" el que me molesta más: imagine una consola o un chat en vivo en un juego multijugador.

pensé en varias opciones:

  • no hay casos especiales - procesamiento y cargar una textura cada vez que cambia de texto, teniendo en cuenta sólo para reRender cuando aparece realmente nuevo texto, y tratando de dividir el texto más grande en partes pequeñas (como por línea de chat). Sin embargo, esto todavía nos dejaría pendientes en casos como una línea de puntuación que cambia todo el tiempo, o un texto de introducción que representa "por personaje" (estilo de máquina de escribir visto en algunos juegos de ciencia ficción)
  • quad-per character - this también parece una solución popular, se prepara una textura con la tabla ASCII y se renderiza un cuarteto texturizado. Sin embargo, tengo serias dudas sobre la eficacia de tal solución. Consejos para hacer eso más rápido también serían bienvenidos.
  • soluciones híbridas - sin embargo, no tienen idea de cómo poner en práctica que limpiamente

La pregunta es, por tanto, - la forma de representar el texto en OpenGL eficiente?

Si esto ayuda, estoy codificando en C++ STL/Boost-heavy y apuntando a las tarjetas gráficas GForce 6 y posteriores.

+1

no construyen grandes texturas con todos los glifos posibles en ellos. Si bien es fácil y "sensato" para las fuentes occidentales, si intenta internacionalizar su aplicación rápidamente se dará cuenta de que este enfoque es insostenible con las fuentes orientales. La única solución escalable es generar el texto dinámico, cuando sea necesario. –

+1

Si intenta renderizar glifos individuales usted mismo, está ignorando todo lo que sabe el sistema operativo sobre el interletraje, los acentos y la combinación de caracteres, los guiones de derecha a izquierda y algunas otras peculiaridades del diseño de tipo que me olvido en este momento . Probablemente esté bien tener una hoja de texto con 0-9a-zA-Z con puntuación para cubrir algunos casos muy comunes, pero la mayoría de las veces obtienes un tipo más bonito cuando le pides al procesador de letras toda la línea o párrafo. – codewarrior

Respuesta

29

EDIT2: Sean Barrett acaba de publicar Bitmap fonts for C/C++ 3D programmers.

EDITAR: otra joya de código que vale la pena mirar es Font Stash que aprovecha el stb_truetype.h de Sean Barrett.


Puede crear una textura en la que represente todos los caracteres de su fuente. Luego, simplemente dibuja quads con textura con proyección ortográfica y coordenadas de textura apropiadas: este enfoque funciona cuando el texto está en un idioma que no contiene muchos símbolos: como inglés. La textura de la fuente se crea una vez al comienzo de la aplicación y luego la representación de los cuádriceps es realmente rápida.

Eso es lo que estoy usando y creo que es la manera más rápida de procesar texto en OpenGL. Al principio, utilicé la herramienta Angelcode's Bitmap Font Generator y luego integé directamente FreeType y construí una textura grande que contenía todos los glifos en el lanzamiento de la aplicación. En cuanto a los consejos para mejorar la velocidad de renderizado de los cuádriceps, acabo de utilizar VBO como para el resto de la geometría en mi aplicación.

Me sorprende que tengas dudas sobre el renderizado cuádruple mientras que no pareces preocuparte por el rendimiento de generar una textura en la CPU, luego subirlo, luego unirlo para finalmente renderizar un rectángulo con él, que para cada cuadro. Cambiar los estados de OpenGL es el cuello de botella, no los 500 - 1000 quads que usará para el texto.

Además, eche un vistazo a bibliotecas como la biblioteca FTGL que convierte toda la fuente en polígonos (fuentes geométricas).

+0

um, eso es lo que escribí en la pregunta O.o. Estoy preguntando sobre los problemas relativos de rendimiento. –

+0

lo siento clic en enviar antes de terminar de escribir –

+0

+1: me pregunto sobre el rendimiento de la "solución estándar". Cambiar la textura sería solo "en el cambio" mientras que los quads para el texto se harían por cuadro, es por eso que me pregunté. –

8

Intente leer esto: http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1.

El enfoque descrito es el método típico para la representación de texto con API de gráficos. Un personaje por quad y todos los datos de imagen para texto en una sola textura. Si puede ajustar todo su conjunto de caracteres en una textura (de hecho, dependiendo del tamaño de la textura, puede ser que pueda caber en varias), la representación es extremadamente rápida.

La clave es que el enlace de textura es la operación que necesita minimizar. Si puede renderizar todo su texto con una sola textura, no importará la cantidad de texto que necesite poner en la pantalla. Incluso si tiene que cambiar texturas varias veces (fuentes diferentes, diferentes atributos de fuente [negrita, subrayado, etc.]), el rendimiento debería ser bueno. El rendimiento del texto puede ser más crítico para un HUD, pero es menos importante en la GUI.

+0

+1: ¡Este es un enlace muy interesante! El cambio de textura podría desaparecer si puedo adaptar todas las fuentes en una sola textura. Actualmente los tamaños de las texturas permitidas son bastante grandes, así que creo que es bastante alcanzable. –

+5

Inventé [un espejo de ese tutorial de DMedia] (http://fsrv.dyndns.org/mirrors/dmedia-tutorials-textrendering1/index.html). – genpfault

0

Por caracteres quad manejados pensó que una lista de visualización (actualizada solo cuando el texto cambia) es suficiente para la mayoría de los casos.

Lo utilicé con fuentes X11 usando el XLoadQueryFont, glGenLists, glXUseXFont, glCallLists que tiene una serie de listas de visualización que describen cada personaje.

la función glCallLists acepta un argumento char * para su texto y se puede incrustar dentro de una lista de visualización.

Así que terminas con una sola llamada para mostrar el texto de bloques.

La textura de fuente sugerida por G. Pakosz es similar, pero calcula sus propias listas de visualización "por carácter".

Sus primeras opciones serán bastante más lentas, ya que requerirá procesamiento basado en procesador en cada cambio de texto.

+0

Este es el método del "libro de texto", lo sé. –

1

simplemente podría utilizar estas dos funciones:

void renderstring2d(char string[], float r, float g, float b, float x, float y) 
{ 
    glColor3f(r, g, b); 

    glRasterPos2f(x, y); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
} 

void renderstring3d(char string[], float r, float g, float b, float x, float y, float z) 
{ 
    glDisable(GL_LIGHTING); 
    glColor3f(r, g, b); 

    glRasterPos3f(x, y, z); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
}

entonces cuando representar el texto en 2D, no se olvide de restablecer tanto el modelview y matrices de proyección.

glMatrixMode(GL_MODELVIEW); 
glPushMatrix(); 
glLoadIdentity(); 
glMatrixMode(GL_PROJECTION); 
glPushMatrix(); 
glLoadIdentity(); 

// Render text and quads 

glPopMatrix(); 
glMatrixMode(GL_MODELVIEW); 
glPopMatrix();

No necesita renderizar en un quad usando estas funciones, porque estas funciones se procesan directamente en el framebuffer.

Y si eso no funciona para usted, mire esto. http://www.opengl.org/resources/faq/technical/fonts.htm

Habla de renderizar texto usando glBitmap, glDrawPixels y alfa blending.

+1

No, gracias, no quiero tal desaceleración;). Claro, se procesa directamente en el framebuffer, pero tómese un momento para pensar en la cantidad de datos que transfiere cada fotograma entre la tarjeta y la memoria local. Sin mencionar que esta solución no admite fuentes personalizadas. –

+0

Bueno, he utilizado estas funciones para mi propia interfaz gráfica de usuario en un motor de juegos en 3D, y no hay un cambio notable en la velocidad de fotogramas cuando enciendo o apago la interfaz gráfica de usuario. Además, el mapa de bits que está pasando solo tiene 135 píxeles para cada personaje, lo que implica mucho menos tiempo que crear una textura y pasar esa textura completa a la tarjeta gráfica cada vez que desea representar un personaje. –

+0

@Ned ¿Cómo puedo hacer esto si uso SDL en lugar de GLUT? – Ben

1

Es complicado de hacer, especialmente si desea utilizar técnicas de representación de fuente subpixel. Eche un vistazo al ClanLib SDK. Utiliza un procesador de proceso por lotes para representar una pantalla completa de texto en una sola llamada OpenGL. Como tiene una licencia basada en zlib, puede extraer su código si no desea usar el SDK en sí

4

Puede representar el texto como caras triangulares y evitar el uso de una textura. De esta forma evitará los bordes desteñidos cuando se amplía el texto. Escribí una fuente ASCII de baja poli que está abierta y disponible en my github.

Otra forma de tener bordes afilados en el texto es SDF font rendering, pero este sufre de algunos artefactos.

3
Cuestiones relacionadas