Ya hay una serie de preguntas sobre la representación de texto en OpenGL, como:
Pero sobre todo lo que se discute es renderizar quads texturizados utilizando la tubería de función fija. Seguramente los sombreadores deben hacer una mejor manera.
No estoy realmente preocupado por la internacionalización, la mayoría de mis cadenas serán etiquetas de marca de trama (fecha y hora o puramente numéricas). Pero los gráficos se volverán a representar a la frecuencia de actualización de la pantalla y podría haber bastante texto (no más de unos pocos miles de glifos en la pantalla, pero suficiente para que el diseño acelerado por hardware sería bueno).
¿Cuál es el enfoque recomendado para la representación de texto usando OpenGL moderno? (Citar el software existente usando el enfoque es una buena evidencia de que funciona bien)
- Sombreadores de geometría que aceptan, por ejemplo, posición y orientación y una secuencia de caracteres y emiten quads texturizados
- Sombreadores de geometría que representan fuentes vectoriales
- Como arriba, pero usando sombreadores de teselación en su lugar
- Un sombreador de cómputo para hacer rasterización de fuentes
Respuestas:
La representación de contornos, a menos que represente solo una docena de caracteres en total, sigue siendo un "no ir" debido a la cantidad de vértices necesarios por carácter para aproximar la curvatura. Aunque en su lugar ha habido enfoques para evaluar curvas bezier en el sombreador de píxeles, estos sufren de no ser fácilmente suavizados, lo cual es trivial usando un quad con textura de mapa de distancia, y evaluar curvas en el sombreador aún es computacionalmente mucho más costoso de lo necesario.
La mejor compensación entre "rápido" y "calidad" sigue siendo quads texturizados con una textura de campo de distancia firmada. Es un poco más lento que usar un quad con textura normal, pero no tanto. La calidad, por otro lado, está en un estadio completamente diferente. Los resultados son realmente sorprendentes, es lo más rápido posible, y los efectos como el brillo también son trivialmente fáciles de agregar. Además, la técnica se puede degradar muy bien a hardware antiguo, si es necesario.
Vea el famoso documento de Valve para la técnica.
La técnica es conceptualmente similar a cómo funcionan las superficies implícitas (metabolas y demás), aunque no genera polígonos. Se ejecuta completamente en el sombreador de píxeles y toma la distancia muestreada de la textura como una función de distancia. Todo lo que está por encima de un umbral elegido (generalmente 0.5) está "dentro", todo lo demás está "fuera". En el caso más simple, en hardware de 10 años sin capacidad de sombreado, establecer el umbral de prueba alfa en 0.5 hará exactamente eso (aunque sin efectos especiales y antialiasing).
Si uno quiere agregar un poco más de peso a la fuente (falso en negrita), un umbral un poco más pequeño hará el truco sin modificar una sola línea de código (solo cambie su uniforme "font_weight"). Para un efecto de brillo, uno simplemente considera todo lo que está por encima de un umbral como "dentro" y todo lo que está por encima de otro umbral (más pequeño) como "fuera, pero en brillo", y los LERP entre los dos. Antialiasing funciona de manera similar.
Al usar un valor de distancia con signo de 8 bits en lugar de un solo bit, esta técnica aumenta la resolución efectiva de su mapa de textura 16 veces en cada dimensión (en lugar de blanco y negro, se utilizan todos los tonos posibles, por lo tanto tenemos 256 veces el información utilizando el mismo almacenamiento). Pero incluso si amplía mucho más allá de 16x, el resultado todavía parece bastante aceptable. Las líneas rectas largas eventualmente se volverán un poco onduladas, pero no habrá artefactos de muestreo típicos "en bloque".
Puede usar un sombreador de geometría para generar los quads a partir de puntos (reducir el ancho de banda del bus), pero sinceramente, las ganancias son bastante marginales. Lo mismo es cierto para la representación de caracteres instanciada como se describe en GPG8. La sobrecarga de la instancia solo se amortiza si tiene mucho texto para dibujar. Las ganancias, en mi opinión, no guardan relación con la complejidad añadida y la no degradabilidad. Además, está limitado por la cantidad de registros constantes o tiene que leer desde un objeto de búfer de textura, que no es óptimo para la coherencia de la caché (¡y la intención era optimizar para empezar!).
Un búfer de vértices simple y simple es igual de rápido (posiblemente más rápido) si programa la carga con un poco de anticipación y se ejecutará en cada hardware construido durante los últimos 15 años. Y no se limita a un número particular de caracteres en su fuente, ni a un número particular de caracteres para representar.
Si está seguro de que no tiene más de 256 caracteres en su fuente, vale la pena considerar las matrices de texturas para quitar el ancho de banda del bus de una manera similar a la generación de quads desde puntos en el sombreador de geometría. Cuando se usa una textura array, las coordenadas de textura de todos los quads tienen idéntico, constante
s
yt
coordenadas y sólo difieren en lar
coordenada, que es igual al índice de carácter para render.Pero al igual que con las otras técnicas, las ganancias esperadas son marginales a costa de ser incompatibles con el hardware de la generación anterior.
Hay una herramienta útil de Jonathan Dummer para generar texturas de distancia: página de descripción
Actualización:
como se señaló más recientemente en la extracción programable de vértices (D. Rákos, "OpenGL Insights", págs. 239), no existe una latencia o sobrecarga adicional significativa asociada con la extracción programática de datos de vértices desde el sombreador en las generaciones más recientes de GPU, en comparación con hacer lo mismo con la función fija estándar.
Además, las últimas generaciones de GPU tienen más y más cachés L2 de propósito general de tamaño razonable (por ejemplo, 1536 kB en nvidia Kepler), por lo que uno puede esperar que el problema de acceso incoherente al extraer compensaciones aleatorias para las esquinas cuádruples de una textura de búfer sea menos problema.
Esto hace que la idea de extraer datos constantes (como los tamaños de quad) de una textura de búfer sea más atractiva. Una implementación hipotética podría reducir las transferencias de memoria y PCIe, así como la memoria de la GPU, al mínimo con un enfoque como este:
gl_VertexID
, y amplifíquelo a 4 puntos en el sombreador de geometría, aún teniendo el índice de caracteres y la identificación del vértice (esto será "gl_primitiveID disponible en el sombreador de vértices") como los únicos atributos, y capturará esto a través de la retroalimentación de transformación.De esta forma, lo ideal sería reducir el ancho de banda de vértice requerido en un 75% (amortizado), aunque solo sería capaz de representar una sola línea. Si uno quisiera poder renderizar varias líneas en una llamada de dibujo, necesitaría agregar la línea base a la textura del búfer, en lugar de usar un uniforme (haciendo que el ancho de banda aumente más pequeño).
Sin embargo, incluso suponiendo una reducción del 75%, ya que los datos de vértice para mostrar cantidades de texto "razonables" solo están en algún lugar alrededor de 50-100 kB (que es prácticamente cero)a una GPU o un bus PCIe) - Todavía dudo que la complejidad añadida y la pérdida de compatibilidad con versiones anteriores realmente valga la pena. La reducción de cero en un 75% sigue siendo solo cero. Es cierto que no he probado el enfoque anterior, y se necesitaría más investigación para hacer una declaración verdaderamente calificada. Pero aún así, a menos que alguien pueda demostrar una diferencia de rendimiento realmente sorprendente (¡usando cantidades de texto "normales", no miles de millones de caracteres!), Mi punto de vista sigue siendo que para los datos de vértice, un búfer de vértice simple y simple es justificadamente suficiente ser considerado parte de una "solución de vanguardia". Es simple y directo, funciona y funciona bien.
Después de hacer referencia a " OpenGL Insights " arriba, vale la pena señalar también el capítulo "Representación de formas 2D por campos de distancia" de Stefan Gustavson que explica la representación de campos de distancia con gran detalle.
Actualización 2016:
Mientras tanto, existen varias técnicas adicionales que tienen como objetivo eliminar los artefactos de redondeo de esquinas que se vuelven perturbadores con aumentos extremos.
Un enfoque simplemente usa campos de pseudodistancia en lugar de campos de distancia (la diferencia es que la distancia es la distancia más corta, no al contorno real, sino al contorno o una línea imaginaria que sobresale sobre el borde). Esto es algo mejor, y funciona a la misma velocidad (sombreador idéntico), usando la misma cantidad de memoria de textura.
Otro enfoque utiliza la mediana de tres en una textura de tres canales, detalles e implementación disponibles en github . Esto tiene como objetivo ser una mejora sobre los hacks utilizados anteriormente para abordar el problema. Buena calidad, ligeramente, casi no notablemente, más lenta, pero utiliza tres veces más memoria de textura. Además, los efectos adicionales (p. Ej., Resplandor) son más difíciles de acertar.
Por último, almacenar las curvas reales de Bezier que componen los personajes y evaluarlos en un sombreador de fragmentos se ha vuelto práctico , con un rendimiento ligeramente inferior (pero no tanto como un problema) y resultados sorprendentes incluso con los aumentos más altos.
Demostración de WebGL que muestra un PDF grande con esta técnica en tiempo real disponible aquí .
fuente
clip(...)
línea conif (text.a < 0.5) {discard;}
(otext.a < threshold
). HTHhttp://code.google.com/p/glyphy/
La desventaja es que el código es para iOS con OpenGL ES. Probablemente voy a hacer un puerto Windows / Linux OpenGL 4.x (aunque espero que el autor agregue documentación real).
fuente
La técnica más extendida sigue siendo los quads texturizados. Sin embargo, en 2005 LORIA desarrolló algo llamado texturas vectoriales, es decir, renderizando gráficos vectoriales como texturas en primitivas. Si uno usa esto para convertir fuentes TrueType u OpenType en una textura vectorial, obtendrá esto:
http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005
fuente
Me sorprende que el bebé de Mark Kilgard, NV_path_rendering (NVpr), no haya sido mencionado por ninguno de los anteriores. Aunque sus objetivos son más generales que la representación de fuentes, también puede representar texto de fuentes y con interletraje. Ni siquiera requiere OpenGL 4.1, pero en este momento es una extensión solo para proveedores / Nvidia. Básicamente, convierte las fuentes en rutas
glPathGlyphsNV
que dependen de la biblioteca freetype2 para obtener las métricas, etc. Luego, también puede acceder a la información de interletrajeglGetPathSpacingNV
y utilizar el mecanismo de representación de ruta general de NVpr para mostrar el texto usando las fuentes "convertidas" de ruta. (Lo pongo entre comillas, porque no hay una conversión real, las curvas se usan como están).los demostración grabada de las capacidades de fuente de NVpr desafortunadamente no es particularmente impresionante. (Tal vez alguien debería hacer uno en la línea de la demostración SDF mucho más elegante que uno puede encontrar en los intertubos ...)
La charla de presentación de la API NVpr 2011 para la parte de fuentes comienza aquí y continúa en la siguiente parte ; es un poco desafortunado cómo se divide esa presentación.
Materiales más generales sobre NVpr:
Y dado que la palabra "plantilla" no produjo ningún resultado en esta página antes de mi respuesta, parece que el subconjunto de la comunidad SO que participó en esta página en la medida en que, a pesar de ser bastante numerosa, no estaba al tanto de la libre de teselación, el búfer de plantilla métodos basados para la representación de ruta / fuente en general. Kilgard tiene una publicación de preguntas frecuentes en el foro opengl que puede iluminar cómo los métodos de representación de ruta sin teselación difieren de los gráficos 3D estándar, aunque todavía están usando una GPU [GP]. (NVpr necesita un chip compatible con CUDA).
Para la perspectiva histórica, Kilgard es también el autor del clásico. "Una API simple basada en OpenGL para Text Mapped Text", SGI, 1997 , que no debe confundirse con el NVpr basado en stencil que debutó en 2011.
La mayoría, si no todos los métodos recientes discutidos en esta página, incluidos los métodos basados en plantillas como NVpr o los métodos basados en SDF como GLyphy (que no discuto aquí más porque otras respuestas ya lo cubren) tienen sin embargo una limitación: son Adecuado para la visualización de texto grande en monitores convencionales (~ 100 DPI) sin irregularidades en cualquier nivel de escala, y también se ven bien, incluso a tamaño pequeño, en pantallas de alta resolución tipo retina. Sin embargo, no proporcionan completamente lo que Direct2D + DirectWrite de Microsoft le brinda, es decir, insinuación de pequeños glifos en las pantallas principales. (Para una encuesta visual de sugerencias en general, vea esta página de la tipoteca, por ejemplo. Un recurso más detallado está en antigrain.com ).
No estoy al tanto de ninguna cosa abierta y productiva basada en OpenGL que pueda hacer lo que Microsoft puede hacer con sugerencias en este momento. (Admito ignorancia a los componentes internos OS X GL / Quartz de Apple, porque que yo sepa, Apple no ha publicado cómo hacen las fuentes basadas en GL / renderización de rutas. Parece que OS X, a diferencia de MacOS 9, no hacer insinuaciones, lo que molesta a algunas personas .) De todos modos, hay un artículo de investigación de 2013 que aborda las insinuaciones a través de sombreadores OpenGL escritos por Nicolas P. Rougier de INRIA; Probablemente valga la pena leerlo si necesita hacer sugerencias desde OpenGL. Si bien puede parecer que una biblioteca como freetype ya hace todo el trabajo cuando se trata de insinuar, en realidad no es así por la siguiente razón, que estoy citando en el documento:
La solución no es exactamente trivial, por lo que no voy a tratar de explicarlo aquí. (El documento es de acceso abierto).
Otra cosa que aprendí del artículo de Rougier (y que Kilgard no parece haber considerado) es que los poderes de fuente que existen (Microsoft + Adobe) han creado no uno sino dos métodos de especificación de interletraje. El viejo se basa en el llamado núcleo de condensación mesa y se apoya en freetype. El nuevo se llama GPOS y solo es compatible con bibliotecas de fuentes más nuevas como HarfBuzz o pango en el mundo del software libre. Dado que NVpr no parece admitir ninguna de esas bibliotecas, el kerning podría no funcionar de forma inmediata con NVpr para algunas fuentes nuevas; hay algunos de los que aparentemente están en la naturaleza, de acuerdo con esta discusión del foro .
Finalmente, si necesita hacer un diseño de texto complejo (CTL) , parece que actualmente no tiene suerte con OpenGL ya que parece que no existe una biblioteca basada en OpenGL para eso. (DirectWrite, por otro lado, puede manejar CTL). Hay bibliotecas de código abierto como HarfBuzz que pueden procesar CTL, pero no sé cómo podría hacer que funcionen bien (como al usar los métodos basados en stencil) a través de OpenGL. Probablemente tenga que escribir el código de pegamento para extraer los contornos reformados y alimentarlos como soluciones basadas en NVpr o SDF.
fuente
Creo que su mejor opción sería mirar en gráficos de El Cairo con el backend de OpenGL.
El único problema que tuve al desarrollar un prototipo con 3.3 núcleos fue el uso de funciones obsoletas en el backend de OpenGL. Fue hace 1-2 años, por lo que la situación podría haber mejorado ...
De todos modos, espero que en el futuro los controladores de gráficos de escritorio opengl implementen OpenVG.
fuente