Pixi.js: Propuesta: mejora de la representación del texto

Creado en 5 abr. 2020  ·  27Comentarios  ·  Fuente: pixijs/pixi.js

La comunidad lo ha dicho: el rendimiento de la representación de texto de Pixi debe mejorar. Este número está dedicado a cómo podemos mejorar y cuál creo que será la mejor manera de lograrlo:

  • Campos de distancia firmados: esta técnica convierte el texto en una textura (utilizando la API de Canvas 2D) y aplica una transformación de distancia. En términos simples, la transformación de distancia establecerá el valor de cada píxel en la textura de salida a la distancia de ese píxel al contorno más cercano del texto en la textura de entrada. pixi-sdf-text es un ejemplo: https://github.com/PixelsCommander/pixi-sdf-text

  • VTM: los mapas de texturas vectoriales codifican discontinuidades de curvas a nivel de píxel en texturas.

  • Representación exacta de la curva Bézier: esto representa la fuente "tal cual" al teselar todo excepto las curvas. Las curvas se renderizan utilizando un sombreador de fragmentos especial (no se realiza ningún muestreo de la curva, se renderiza exactamente en la GPU con antialiasing): https://www.microsoft.com/en-us/research/wp-content/uploads /2005/01/p1000-loop.pdf. Creé una demostración para la curva de Bézier cuadrática: https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

@bigtimebuddy y yo discutimos estos métodos y pensamos que el tercer enfoque es el mejor porque:

  • Las SDF requieren atlas generados previamente. Generar SDF multicanal es muy complicado (si queremos hacerlo en tiempo de ejecución).

  • Los VTM son demasiado complicados para usar solo fuentes.

  • Las curvas Bézier exactas solo requieren que represente la fuente como una ruta como todo lo demás en Gráficos.

Comentario más útil

@eXponenta por favor deja de ser tan hostil. Estamos explorando enfoques, todavía no hay nada sólido. Sea constructivo y no use insultos.

Todos 27 comentarios

No debe estar en el núcleo.
Es un paquete pesado y DEBE implementarse fuera del paquete principal, el equipo central no debe preocuparse por su implementación.

Pixi SDF es un buen ejemplo.

Por favor, no intentes hacer Phaser de PIXI

Me gustaría dar un poco más de contexto. Le he pedido a @SukantPal que investigue enfoques alternativos de Texto / BitmapText que tengan diferentes compensaciones. En particular, si podemos encontrar algo que funcione mejor que Text y se vea genial.

Creo que hay varios enfoques aquí. Algunos pueden ser apropiados como complementos de tercera parte, algunos pueden estar en el repositorio pero no incluidos, y algunos pueden reemplazar / aumentar la API actual. Averigüemos cuál es el enfoque de representación de texto más fructífero que optimiza el rendimiento pero con menos compensaciones con BitmapText.

Hay algunos criterios que usaría para juzgar un buen objeto de visualización de texto:

  • Buen rendimiento en tiempo de ejecución : la representación y el cambio de texto son económicos
  • Baja memoria : el uso de RAM es bajo
  • Pequeñas dependencias : el tamaño del archivo de la huella de dependencia es pequeño
  • Gran fidelidad : funciona bien con diferentes resoluciones
  • Estilo flexible : compatibilidad con trazos, sombras paralelas, degradados
  • Admite idiomas de glifos grandes : p. Ej., Chino, japonés, coreano
  • Compatible con versiones anteriores : funciona con Context2D

| | Perf | Memoria | Dependencias | Fidelidad | Estilismo | CJK | Context2d |
| - | - | - | - | - | - | - | - |
| Texto | 👎 | 👎 | 👍 | 👍 | 👍 | 👍 | 👍 | 👍 |
| BitmapText | 👍 | 👎 | 👍 | 👎 | 👎 | 👎 | 👍 |

Está bien.
Describe fragment interpolation y toda la implementación no nativa:

  1. Necesita sombreador adicional y datos adicionales, eso evitará el procesamiento por lotes.
  2. Necesita reconstruir la geometría cuando se cambia (p.3).
  3. Requiere una tabla de glifos para todos los glifos existentes en el lenguaje, que requieren cargar TTF específico en la memoria por completo, porque ot no puede admitir la transmisión, y luego analizarlo. Parece SWF.
    Debido a que no podemos cargar la fuente del sistema como forma, no podemos usarla.
  4. Las reglas específicas del idioma se están moviendo al equipo lib desde el equipo del navegador, que implementan reglas de renderizado: ltr / rtl, reglas de concatenación de glifos hindi / árabes, etc ... lo mismo que mover el 10% del navegador a lib. Unity no lo implementó bien todavía.
  5. Sombreador pesado con argumentos adicionales para estilos de soporte. Eso aumenta el costo de renderizado, porque deberíamos renderizarlo en tiempo real.
    Y, por supuesto, deberíamos almacenarlo en caché como textura.

@eXponenta

  • El texto se puede agrupar, aunque no con otras cosas como gráficos.

  • La implementación de texto actual almacena en caché cada glifo varias veces (si una letra se usa varias veces en varios PIXI.Texts). Tener una geometría por glifo es mejor. Además, no es necesario almacenar en caché en diferentes tamaños de fuente.

  • La geometría no necesita ser reconstruida por decir, si las letras en el texto cambian, debe buscar nuevamente desde la tabla de geometría de glifos. Si la transformación cambia, solo necesita cambiar un uniforme.

  • Podemos usar una biblioteca para analizar fuentes. La conversión a la geometría es trivial.

  • No sé qué son las reglas de concatenación de glifos. ¿Podrías explicar?

  • De izquierda a derecha o de derecha a izquierda: si desea invertir las letras, puede hacerlo. Si desea una imagen reflejada, configure scale.x=-1 internamente.

  • El estilo de texto no agregará más argumentos al sombreador. Cambiará la geometría. Ahora, almacenar el glifo como una geometría requiere menos memoria que almacenarlo en caché en una textura.

  • Los archivos de fuentes obtenidos de las API deben almacenarse en caché en la máquina del usuario.

U muy ingenuo:

  1. Debe ser un batcher externo, porque los glifos requieren atributos adicionales, como anclajes Bézier, valores de sombra, anclajes de degradado ..., o todos deben pasarse como uniformes: adiós, agrupación por lotes.
  2. de derecha a izquierda y de izquierda a derecha, y su combinación es un problema muy complejo.
    Problemas abiertos en la biblioteca de renderizado de PDF:
    https://github.com/asciidoctor/asciidoctor-pdf/issues/175
  3. Problema de hindi (y lenguaje similar)
    https://docs.microsoft.com/en-us/typography/opentype/spec/gsub

No podemos usar dependencias externas, porque será el mismo problema que isMobile o resource-loader .
El núcleo debe estar limpio. Dependencias externas mínimas.

@eXponenta

  • El diseño mixto (ltr y rtl combinados) es menos prioritario que el alto rendimiento. Siempre puede recurrir al algoritmo actual. Similar para Devanagari. Las características especiales, como las paradas de gradiente, también necesitarán un respaldo.

  • El procesamiento por lotes puede funcionar aquí porque será más fácil sin texturas. Puede crear un complemento como CanvasGraphicsRenderer .

Está bien. Tu ganas. Hazlo. Pero fuera del núcleo, entonces lo miraremos y decidiremos qué debemos hacer.
Pero sin grandes dependencias.

@eXponenta por favor deja de ser tan hostil. Estamos explorando enfoques, todavía no hay nada sólido. Sea constructivo y no use insultos.

@eXponenta ¿Estás seguro de que

Otro enfoque que estamos pensando es renderizar cada glifo usando lienzo 2D (igual que ahora) por separado y almacenarlos en un atlas. El atlas se puede reutilizar globalmente para todas las instancias PIXI.Text . Cada combinación de glifo + tamaño de fuente + estilo de fuente se almacenará en caché por separado.

¿Qué piensas sobre aceptar eso en el núcleo?

Hola amigos, es realmente emocionante escuchar estos nuevos enfoques sobre la mesa. @eXponenta , haciéndose eco de @bigtimebuddy , seamos constructivos, por favor. Es evidente que tiene una buena idea del nuevo enfoque propuesto, pero apuntemos a ver si podemos mitigar los problemas planteados y mantenerlo amigable :)

En el mensaje de texto, aquí están mis 2 centavos (¿peniques?) ..

Personalmente, creo que el enfoque más valioso es ganar la velocidad y el rendimiento del texto de mapa de bits, pero sin la necesidad de crear una fuente de mapa de bits de antemano. ¡Construcción dinámica de texturas de mapa de bits, por así decirlo!

Fuentes dinámicas de mapa de bits

pros

  • ¡Las herramientas para crear fuentes de mapa de bits son pocas y distantes entre sí! Me encantaría eliminar esa barrera.
  • podríamos crear varios tamaños de texturas de tamaño de texto.
  • Funciona con Canvas
  • Rendimiento, ya que cada glifo se puede agrupar
  • muchos efectos geniales!
  • API solo necesitaría un ligero ajuste:
const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green'
});


const bitmapFont = new BitmapFont(textStyle);

contras

  • todos los demás inconvenientes de las fuentes de mapa de bits actuales de mapa de bits: P
  • ¿Se ralentizaría la actualización dinámica del atlas de texturas?

    • Aunque esto se estabilizaría después de un tiempo, ¿y tal vez podría almacenarse en caché entre sesiones?

    • El texto actual también tiene que cargar una textura cada vez que cambia de marco, ¿este enfoque lo haría menos?

ideas

  • ¿Podría almacenar en caché la textura generada en un almacenamiento local? para visitas posteriores?
  • Solo agregue los caracteres que se utilizan, para que las texturas sean tan grandes como deben ser. Actualice sobre la marcha
  • hornee en filtros a esta textura para efectos extra geniales (contorno, sombra, etc.)
  • ¿Podemos explorar la reducción de la memoria de la fuente de mapa de bits al no convertir cada glifo en un sprite?

SDF
¿Puede el SDF ser una extensión del enfoque anterior? ¿Qué tan complicado sería generar dinámicamente esa textura? ¿Sería super chiflado? ¿Estamos hablando de aumentar mucho la base del código?

La mayoría de la gente no tiene idea de qué es eso, por lo que idealmente debería estar oculto. Si necesitamos generar externamente los campos SDF o el código requerido para generar es demasiado grande o complejo, entonces esto sería mejor en casa como un complemento seguro:

const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green',
    sdf:true, <----- how sweet would this be, maybe rename to more user friendly like 'cleanEdges'
});

const sdfFont = new BitmapFont(textStyle);

Representación exacta de la curva de Bézier

¡Este es un enfoque interesante sin duda! Había investigado esto en el pasado y decidí que los interruptores de sombreado introducidos en el ciclo de renderizado y la teselación adicional requerida tendrían una gran sobrecarga. @SukantPal , estás más cerca de esta idea que yo en este momento, ¡así que me gustaría conocer tu opinión sobre mis preocupaciones!

Habiendo dicho eso, tal vez valga la pena construir un prototipo que podamos probar y criticar un poco para validar nuestro pensamiento.

Tiempos emocionantes para el texto: D

¿Puede el SDF ser una extensión del enfoque anterior? ¿Qué tan complicado sería generar dinámicamente esa textura? ¿Sería super chiflado? ¿Estamos hablando de aumentar mucho la base del código?

La generación de SDF es costosa y hay un tiempo de empaquetado (cuando buscamos empaquetar diferentes fuentes en una clase), pero se puede almacenar en caché en el cliente (como todas las demás variantes).
Hay una implementación de lienzo (jeje):
https://github.com/mapbox/tiny-sdf
Pero la compilación SDF no es completamente correcta (cambio de glifo al aumentar / disminuir el tamaño de fuente)
Parece útil, pero para MSDF deberíamos ejecutarlo 3 veces (por canal).

oh wow, eso es un poquito de código! ¡Parece maduro para un sombreador también!

@GoodBoyDigital El paquete tiny-sdf genera un campo de distancia de un solo canal. No produce esquinas nítidas cuando almacena en caché el texto con tamaños de fuente más pequeños. Eso se puede mitigar almacenando en caché con el mismo tamaño de fuente que se está procesando.

La generación de SDF de un solo canal no debería ser tan mala. El SDF multicanal es superior, excepto que es demasiado complicado. No podía entender cómo Chumskly codificaba las esquinas.

Ahora, todo lo que estamos considerando no admitirá el diseño rtl y Ltr combinado (como @eXponenta señaló correctamente). Pero tampoco creo que lo estemos apoyando oficialmente en este momento.

El enfoque exacto tiene dos beneficios: tamaño de caché pequeño (está almacenando en caché los vértices, no todos los píxeles), antialiasing incluso cuando la configuración "antialiasing" está desactivada (creo que se espera que el texto esté suavizado siempre. La implementación actual lo hace mediante el uso de lienzo 2D).

En cuanto a la demostración, ¿viste mi demostración de curva de Bézier cuadrática? https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

——
Otra cosa que yo y @bigtimebuddy discutimos como la solución más simple fue seguir usando el lienzo 2D y almacenar en caché los glifos en una textura. Los glifos se pueden representar como un cuadrante. El atlas de caché se puede reutilizar entre textos. Por supuesto, esto significa que el texto grande se almacena en caché con el mismo tamaño y, por lo tanto, se usa una gran cantidad de memoria cuando se procesa una gran cantidad de texto, pero solo una parte (como la página actual en PDF) es visible.

Bonito,

Sí, no se preocupe por rtl o ltr, que siempre estarán disponibles a través del método actual y es un problema que todas las técnicas de representación de texto personalizadas deberán resolverse en una fecha posterior.
Estas decisiones. Idealmente, debería centrarse en el consumo de memoria y el rendimiento en tiempo de ejecución.

La demostración de Bezier es genial, pero no creo que sea suficiente para comprender las verdaderas complejidades que pueden esconderse si representamos una oración completa.

Lo que escribí anteriormente sobre las fuentes de mapa de bits dinámicas es más o menos exactamente lo que mencionaste sobre el almacenamiento en caché de glifos. ¡Creo que definitivamente es una ruta útil para bajar!

En resumen:

Las soluciones de la curva de Bezier: esta podría ser una buena ruta, pero creo que esto requiere más I + D para descubrir cómo encaja en los casos de uso de producción real.

Bitmapfonts dinámicos de fuentes normales: esto definitivamente deberíamos explorar, ya que sabemos que dará un buen rendimiento y, al mismo tiempo, mantendrá la API simple. Mi favorito: D

SDF de un solo canal Aprecio que no va a ser tan bueno SDF multicanal, ¡pero la demostración me pareció bastante buena! Si el texto se puede escalar bien y podemos tener una textura por fuente, ¡entonces creo que también vale la pena investigar esta ruta!

@GoodBoyDigital Creo que la demostración tiene un texto bastante bueno. Pero hay diferencias visibles si intenta buscar detalles:

Screen Shot 2020-04-06 at 1 34 29 PM

Screen Shot 2020-04-06 at 1 34 35 PM

El texto de la parte superior no es nítido, los bordes tienen ondulaciones. Es posible que cada combinación de fuente + (~ 12-15 píxeles de diferencia en el tamaño de fuente) deba almacenarse en caché por separado.

Estoy totalmente de acuerdo con usar SDF si esos movimientos no son importantes o si podemos optar por el almacenamiento en caché en varios tamaños de fuente.


La solución más simple también está bien para mí 💯tbh!

Oigan todos.

Soy un experto en todo lo relacionado con Pixi, pero soy un usuario de GDevelop, que usa Pixi como su backend, y he estado investigando esto durante un tiempo para la implementación de PixiJS y la representación de texto de GDevelop. De hecho, es impactante para un juego en el que estoy trabajando y que tiene mucho texto. (Puede ver mi investigación / ejemplos en el problema que publiqué en GDevelop: https://github.com/4ian/GDevelop/issues/1449)

Una de las opciones que encontré se centró en ignorar por completo los problemas de escala con el texto y eliminarlos por completo dejando siempre la escala de texto al 100%, pero ¿escalando el tamaño de fuente del texto en su lugar? Esto es independiente de la fuente y parece funcionar en todos los tamaños.

Aquí hay un ejemplo de código en el que se está haciendo con Pixi: https://codepen.io/Tazy/pen/wJVExB
Lo encontré en este hilo: https://www.html5gamedevs.com/topic/29576-scalable-text-for-pixijs/

De hecho, tengo una recompensa por este problema, ya que esperaba que alguien pudiera modificar la extensión de Pixi Text para GDevelop, pero (siendo el lego que soy) no me di cuenta de que este era un problema mucho mayor con Pixi en sí.

No tengo idea de si hay problemas potenciales con este método, pero parece que evita todos los problemas de rendimiento de sdf / msdf / etc.

@ Silver-Streak Si te refieres a aumentar el tamaño de fuente en la escala aplicada en el objeto de visualización de texto, ¿cómo sería eso mejor en términos de rendimiento? El material SDF ayuda al rendimiento porque no vuelve a renderizar con tamaños de fuente más grandes.

@ Silver-Streak Por supuesto, su propuesta mejorará la _calidad_ pero no veo cómo mejorará el rendimiento.

@ Silver-Streak Por supuesto, su propuesta mejorará la _calidad_ pero no veo cómo mejorará el rendimiento.

A menos que no haya entendido bien, ¿cambiar el tamaño de la fuente no consumiría menos recursos que escalar todo el objeto o cargar en otro renderizador? Una vez más, soy un lego en lo que respecta a cómo funciona realmente la escala de Pixi, simplemente tenía sentido para mí que dejar la fuente en resolución nativa pero simplemente cambiar el tamaño del texto sería más rápido que escalarla. Si eso es incorrecto, disculpe la distracción.

@ Silver-Streak Scaling se implementa como una transformación. Tiene una matriz de transformación, y cambiar la escala en esa matriz es una operación trivial.

A partir de ahora, el texto se renderiza usando Canvas 2D API en un lienzo. Luego se copia en la pantalla. Cambiar la escala solo cambiará las coordenadas de la pantalla a las que se asigna el texto en el lienzo.

Ahh, eso tiene sentido. Eso es desafortunado, aunque para ser justos, mi problema es más con la representación gráfica de las fuentes que se vuelven borrosas después de ser escaladas, pero pensé que también sería un mejor rendimiento.

Si bien estaría emocionado de que alguien lo implemente para solucionar los problemas generales de calidad del texto, puedo entender totalmente que también desee mejorar el rendimiento.

Gracias por hablar conmigo.

@ Silver-Streak No hay problema. Sin embargo, implementar un texto que priorice la calidad tampoco debería ser difícil en WebGL. Algunas aplicaciones están implementando texto creando una malla por sí mismas. Puede analizar el archivo de fuente, hacer una lista de vértices y teselarlo. Esos vértices se pueden renderizar a través de una malla.

A escalas altas, esto puede causar ligeros "bordes", porque en última instancia, está renderizando el texto como triángulos. Para una calidad aún mayor, puede usar el sombreador de "curva Bézier exacta" del que estaba hablando en este hilo: representará las curvas como curvas y no como triángulos.

Si necesitan ayuda con la calidad del texto, puedo ayudarlos :)

@SukantPal Definitivamente no soy un colaborador de GDevelop, (ni tú querrías que lo fuera. Soy predominantemente un analista de sistemas comerciales / DevOps en la vida, no un desarrollador 😄), aunque me encanta ese proyecto y soy activo en la comunidad. . También sé que hay otros miembros de la comunidad a los que les encantaría ver una solución para la calidad del texto a escala.

Sin embargo, si desea ver el problema en la publicación, también tengo una recompensa por ello en Bountysource y también está abierta a todos. Sin embargo, no quiero ocupar más espacio mental aquí, ya que es obvio que hay una conversación mucho más profunda en torno a Pixi en general, y mi sugerencia no fue tan acertada como pensé.

@ Silver-Streak Podría echar un vistazo, ya que no tengo nada mejor que hacer en la temporada de corona

Sé que este es un hilo cerrado, pero estoy seguro de que todos siguen buscando la mejor manera de mejorar la representación del texto. Me di cuenta de que alguien tenía una implementación de msdf que funcionaba con Pixi v5. https://github.com/cjsjy123/pixi-msdf-text-v5 Pensé que se lo mencionaría a los interesados.

Este hilo definitivamente debe volver a abrirse y mantenerse vivo, o al menos tener algún tipo de actualización de vez en cuando, ya que este es uno de los problemas más buscados.

¿Fue útil esta página
0 / 5 - 0 calificaciones