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
y t
coordenadas y sólo difieren en la r
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:
- Cargue solo un índice de caracteres (uno por carácter que se mostrará) como la única entrada a un sombreador de vértices que pasa este índice y
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.
- Esto será rápido, porque solo hay dos atributos de salida (cuello de botella principal en GS), y está cerca de "no-op" de lo contrario en ambas etapas.
- Ate una textura de búfer que contenga, para cada carácter en la fuente, las posiciones de vértice del quad texturizado en relación con el punto base (estas son básicamente las "métricas de fuente"). Estos datos se pueden comprimir a 4 números por quad almacenando solo el desplazamiento del vértice inferior izquierdo y codificando el ancho y la altura del cuadro alineado al eje (suponiendo que los medios flotadores, serán 8 bytes de buffer constante por carácter - una fuente típica de 256 caracteres podría caber completamente en 2 KB de caché L1).
- Establecer un uniforme para la línea de base
- Enlace una textura de amortiguación con desplazamientos horizontales. Estos podrían probablemente incluso se calcularán sobre la GPU, pero es mucho más fácil y más eficiente para ese tipo de cosas en la CPU, ya que es una operación estrictamente secuencial y no es en absoluto trivial (piense en el ajuste entre caracteres). Además, necesitaría otro pase de retroalimentación, que sería otro punto de sincronización.
- Renderice los datos generados previamente desde el búfer de retroalimentación, el sombreador de vértices extrae el desplazamiento horizontal del punto base y los desplazamientos de los vértices de las esquinas de los objetos del búfer (usando la identificación primitiva y el índice de caracteres). La ID de vértice original de los vértices enviados ahora es nuestra "ID primitiva" (recuerde que el GS convirtió los vértices en quads).
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í .