Troika: Característica: agregue atributos de índice de carácter/palabra/línea a la geometría del texto

Creado en 11 feb. 2021  ·  18Comentarios  ·  Fuente: protectwise/troika

Los sombreadores personalizados aplicados a las instancias de texto podrían habilitar algunos efectos de animación realmente agradables. Para muchos de estos, querrá tratar cada carácter/glifo de forma independiente, y para eso necesita algo en el sombreador que le indique qué carácter se está representando actualmente.

Teóricamente gl_InstanceID podría usarse para esto, ya que usamos instancias para los cuadrantes de glifos. Y esto funciona un poco: https://codesandbox.io/s/zealous-water-m8lzq?file=/src/index.js -- pero gl_InstanceID solo está disponible en WebGL2, y parece romperse en las implementaciones de ANGLE cuando se usa dentro de funciones que no sean void main . Por lo tanto, no es realmente utilizable para esto en este momento.

En su lugar, podríamos agregar nuestro propio atributo de instancia, algo así como attribute float charIndex; , que solo contiene un índice de carácter incremental. Los sombreadores personalizados podrían hacer uso de eso.

Probablemente me gustaría convertirlo en una función opcional, algo así como textmesh.includeCharIndexInShader = true , solo para evitar crear esa matriz de atributos adicional si no es necesaria.

Comentario más útil

Tengo mucha limpieza que hacer, pero tengo un POC inicial de los recuentos anteriores. Aquí hay ejemplos que usan los diversos pares de índice/total para cambiar el color en un sombreador de fragmentos:

charIndex / totalChars:
Screen Shot 2021-02-18 at 7 18 56 PM

charInWordIndex / totalCharsInWord:
Screen Shot 2021-02-18 at 7 19 01 PM

charInLineIndex / totalCharsInLine:
Screen Shot 2021-02-18 at 7 19 08 PM

wordIndex / totalWords: (se ve muy similar a charIndex/totalChars en este ejemplo pero hay una sutil diferencia)
Screen Shot 2021-02-18 at 7 19 16 PM

índicePalabrasEnLínea / totalPalabrasEnLínea:
Screen Shot 2021-02-18 at 7 19 22 PM

índice de línea / líneas totales:
Screen Shot 2021-02-18 at 7 19 29 PM

Logré obtener todos los datos en un máximo de 3 uniformes + 2 atributos, lo cual es bastante bueno. Todavía quiero que sean opcionales.

Todos 18 comentarios

También tal vez: wordIndex , lineIndex ...?

palabra y línea se habilitarían por línea y animación por palabra, muy parecido a https://greensock.com/splittext/ (que podemos considerar un buen ejemplo de lo que permitiría este cambio)

¿Tengo razón al suponer que esto también permitiría cambios por token (carácter, palabra, línea) en el sombreador de fragmentos?

¿Tengo razón al suponer que esto también permitiría cambios por token (carácter, palabra, línea) en el sombreador de fragmentos?

Tendrías que pasarlo de vértice a fragmento como variable, pero sí. :)

Por la madriguera del conejo vamos...

Puedo pensar en usos para todos los siguientes índices, además de un recuento total para cada uno:

  • índicechar, caracteres totales
  • ÍndicePalabras, TotalPalabras
  • índice de línea, líneas totales
  • charInWordIndex, totalCharsInWord
  • charInLineIndex, totalCharsInLine
  • palabraEnLíneaÍndice, totalPalabrasEnLínea

Querríamos hacer todas estas opciones y hacer un empaque inteligente para minimizar la cantidad de nuevos atributos glsl que estamos introduciendo. Tendré que pensar más en la API para esto.

podríamos dejar que los usuarios los elijan TODOS con banderas, por lo que

{
división: {palabras: verdadero, caracteres: verdadero, líneas: verdadero}
}

hacer un poco de embalaje inteligente

¿Te importa expandirte en esto? Tengo curiosidad 👐

Me gusta la idea de permitir que los usuarios elijan las divisiones.

Al empaquetar solo quiero decir que no queremos agregar 12 nuevas declaraciones attribute float foo o llegaremos al límite (creo que son 16 atributos en total en webgl), pero podríamos empaquetarlas en un máximo de 3 nuevas attribute vec4 foo declaraciones, y luego desempáquelas en variables float más atractivas dentro del shader.

Ah, sí, tiene mucho sentido, ¡gracias!

¿Debería charIndex incluir espacios en blanco en su incremento? ¿O simplemente incrementar para glifos visibles? Me inclino por glifos solo visibles.

Contar espacios en blanco crearía escalones extraños al animar por índice, por lo que también me inclino por visible

Tengo mucha limpieza que hacer, pero tengo un POC inicial de los recuentos anteriores. Aquí hay ejemplos que usan los diversos pares de índice/total para cambiar el color en un sombreador de fragmentos:

charIndex / totalChars:
Screen Shot 2021-02-18 at 7 18 56 PM

charInWordIndex / totalCharsInWord:
Screen Shot 2021-02-18 at 7 19 01 PM

charInLineIndex / totalCharsInLine:
Screen Shot 2021-02-18 at 7 19 08 PM

wordIndex / totalWords: (se ve muy similar a charIndex/totalChars en este ejemplo pero hay una sutil diferencia)
Screen Shot 2021-02-18 at 7 19 16 PM

índicePalabrasEnLínea / totalPalabrasEnLínea:
Screen Shot 2021-02-18 at 7 19 22 PM

índice de línea / líneas totales:
Screen Shot 2021-02-18 at 7 19 29 PM

Logré obtener todos los datos en un máximo de 3 uniformes + 2 atributos, lo cual es bastante bueno. Todavía quiero que sean opcionales.

¡Asombroso! Avísame cuando tengas una versión de prueba lista 😄

Estaba buscando hacer una característica que esto podría abordar. Tengo un montón de etiquetas de 3 letras para poner alrededor de una esfera. Los hago mirar siempre hacia el espectador y hago ajustes para que en la pantalla siempre tengan el mismo tamaño, sin importar la escala aplicada en la matriz de vista o matriz de modelado.
En este momento, creo un objeto Text por etiqueta y aplico una transformación.
Estaba pensando que podría obtener un rendimiento mucho mejor empaquetando todas las etiquetas en un solo texto y tener un atributo para tener la posición en la esfera de cada etiqueta para hacer las transformaciones correctas en el sombreador de vértices.
@lojjic , ​​¿puedes documentar cómo crear sombreadores personalizados? Creo que agregar el atributo no debería ser difícil, ya que debería hacerlo el método existente setAttribute de BufferGeometry .

La otra opción que estaba considerando sería el renderizado instanciado, ya que todas mis etiquetas tienen 3 letras. Pero eso requeriría WebGL 2 con seguridad y podría ser demasiado complejo para valer la pena, al menos al principio.

@FunMiles Creo que tienes razón, esto puede facilitar ese tipo de cosas. Si lo entiendo correctamente, la optimización podría involucrar dos partes:

  1. Mover la lógica de rotación/escalado de JS del lado de la CPU a la lógica de sombreado de vértices del lado de la GPU
  2. Eso _más_ combinar múltiples piezas de texto en una sola llamada de sorteo

Para 1, eche un vistazo a este comentario , que en realidad ya puede ser suficiente para sus necesidades. Esa también es una buena demostración de cómo aplicar un sombreado personalizado, básicamente asignándolo como material . Utilicé la utilidad createDerivedMaterial de Troika allí, pero de manera similar podría pasar cualquier ShaderMaterial o un material con sus propias modificaciones onBeforeCompile .

Para 2, creo que tiene razón, podría representar un solo texto y luego usar _some_ atributo para desplazar caracteres individuales alrededor de su esfera. Los nuevos atributos de índice char/word descritos en este número pueden ser de alguna ayuda, pero no estoy seguro de que sean necesarios. Probablemente podría simplemente codificar esos desplazamientos en un nuevo InstancedBufferAttribute, donde cada uno de sus vectores contiene el desplazamiento de un carácter (la geometría del texto es un cuádruple simple que se instancia para cada glifo, por lo que InstancedBufferAttributes adicionales se recorrerán para cada glifo).

¡Estoy interesado en ver si tienes suerte haciendo esto!

@lojjic Lo entendiste correctamente. Y el código que vinculaste hace el 90% de lo que necesito para (1). Su demostración coincide inquietantemente con mi caso de uso.
Si puedo pedirle que corrija mi comprensión, así es como veo lo que está haciendo:

  • mvPosition se inicializa con la posición del punto de referencia en el espacio de vista del modelo. Supongo que ese punto de referencia es el punto de anclaje. ¿Está bien?
  • position es el desplazamiento desde ese punto de referencia y supongo que solo tiene coordenadas x e y distintas de cero. (¿lo que me hace pensar que puede omitir el cálculo del componente z de la escala?) (PD: mirando el código de sombreado de vértice de representación instanciado, parece que uno puede rotar el texto, en cuyo caso el componente z no será cero)
  • La escala en cada dirección se recupera asumiendo que el bloque 3x3 solo contiene una composición de escalado y rotaciones.
  • Se agrega position escalado, y si el componente z es cero, esta contribución mantiene la posición en un plano paralelo al plano de proyección.

Los cambios para mí en este código por solo hacer (1) serían principalmente en la escala y un ligero cambio de coordenadas para que el texto permanezca fuera de la esfera que tengo.

Usted entendió 2 también. Sin embargo, estoy un poco confundido al leer el código. No me había dado cuenta de que la representación de texto ya es una representación de instancia. Lo que me confunde es que tienes GlyphsGeometry derivados de InstancedBufferAttribute y, sin embargo Text es una subclase de Mesh y no de InstancedMesh . Supongo que tengo que profundizar más en Three.js.
De lo contrario, dado que cada carácter es una instancia, necesitaría solo un atributo con un vector para compensar position para cada instancia de glifo. ¿Está bien?

Tuve que alejarme un poco de esto, pero aquí hay una actualización de estado rápida:

El PR #109 se siente bastante sólido en términos de recopilar y exponer los distintos conteos. Quiero que opten por participar, pero por lo demás estoy contento con el lugar en el que se encuentra.

Sin embargo, tengo el fuerte presentimiento de que las animaciones basadas en sombreadores requerirán no solo estos nuevos recuentos, sino también el acceso a otros datos como:

  • Los límites cuádruples del glifo actual
  • Límites generales del bloque
  • Información métrica de fuente como línea de base/ascendente/descendente que no se puede inferir del cuádruple
  • ¿Otro?

Algunos de estos ya están técnicamente presentes en el sombreador, pero si los usuarios van a depender de ellos, deberán exponerse con nombres descriptivos y documentarse como un contrato confiable.

Si alguien tiene tiempo para jugar con esa rama de relaciones públicas e intentar implementar algunas animaciones de sombreado, y decirme qué información falta, sería de gran ayuda.

@lojjic Solo quiero expresar mi interés en esta función 😺

Resolví algunos conflictos de fusión con el último maestro aquí: https://github.com/canadaduane/troika/tree/char-indices

Todavía no he tenido la oportunidad de probarlo, pero tengo la intención de hacerlo en los próximos días.

He estado alejado de esta discusión durante mucho tiempo. Sin embargo, me acaban de recordar que quiero volver a mirarlo.
Al final de esta publicación hay un ejemplo de algo que hice usando createDerivedMaterial .
Sin embargo, en este momento, hay una malla por etiqueta y cuando la cantidad de etiquetas se vuelve muy grande, la representación se vuelve muy desigual en los teléfonos de gama baja. Supongo que se debe a las llamadas de la CPU para cada etiqueta. Para abordar eso, me gustaría reemplazar las mallas múltiples con una sola con toda la etiqueta y usar un sombreador de vértices mejorado para hacer el resto.

Creo que, como mencionó @lojjic , ​​necesitaría algunos límites en las palabras. O al menos, para mi uso, el centro de cada palabra.
¿Alguna otra sugerencia sobre cómo hacerlo de otra manera o sobre cómo obtener ese centro?

https://flightlog-beta.vercel.app/circles?route=BRU-HER-ATH-IST-AMM-CAI-TUN-CMN-RAK-MAD-LIS-ZRH-GVA-NCE-CDG-DUS-FRA- MUC-LHR-LCY-LGW-DUB-HBA-SYD-MEL-CNS-KTM-DEL-BLR-COK-MAA-CMB-MLE-HKG-HND-NRT-KIX-ICN-GMP-MNL-DPS-JOG- CGK-SIN-KUL-PEN-LGK-BKK-SGN-HAN-LPQ-CNX-DOH-AUH-DXB-JNB-CPT-LVI-ZNZ-JRO-DAR-SSH-BUD-OTP-IPC-SCL-PMC- GRU-EZE-GIG-BSB-LIM-LPB-BOG-PTY-SJO-SJU-CUN-ACA-MEX-MTY-JFK-BOS-PHL-DCA-IAD-BWI-CLT-ATL-MSP-MIA-DFW- DTW-ORD-IAH-COS-DEN-PHX-SAN-LAX-SJC-SFO-SEA-PDX-YVR-YYZ-YUL-LGA-EWR-ASP-BNE-AKL-CHC-ZQN-VIE-SJJ-VCE- MXP-FCO-BCN-PEK-PVG-HNL-OGG-KOA-HIJ-RGN-PBH-TIP-AMS-CPH-SLC-CVG-GSP-TPE-ULN-PNH-VTE-ABQ-BUF-MCO-HKT- MDL-

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

Temas relacionados

atlmtw picture atlmtw  ·  47Comentarios

arpu picture arpu  ·  43Comentarios

drcmda picture drcmda  ·  11Comentarios

stephencorwin picture stephencorwin  ·  39Comentarios

Ocelyn picture Ocelyn  ·  13Comentarios