Elegir entre las cuatro técnicas de texto
La tabla comparativa completa y el árbol de decisión que lleva de los requisitos reales a una de las cuatro opciones, sin pasar por la intuición.
Las cuatro técnicas no compiten: cada una gana en un eje distinto y pierde en los demás. Elegir bien no es cuestión de gusto sino de saber qué eje domina en tu caso, y en la mayoría de proyectos reales la respuesta correcta es combinar dos. Esta lección cierra el nivel con la comparativa punto por punto y con el árbol que la resume.
- Comparar las cuatro técnicas en los ocho ejes que de verdad deciden.
- Recorrer el árbol de decisión desde un requisito concreto hasta una técnica.
- Reconocer las tres combinaciones que aparecen una y otra vez en producción.
- Justificar la elección ante alguien que proponga otra.
La comparativa, eje por eje
| Eje | TextGeometry | Sprite de canvas | troika con SDF | CSS2D o CSS3D |
|---|---|---|---|---|
| Nitidez al acercarse | perfecta | se pixela | perfecta | perfecta |
| Draw calls por etiqueta | una | una | una | ninguna en WebGL |
| Texturas en VRAM | ninguna | una por etiqueta | un atlas compartido | ninguna |
| Coste de cambiar el texto | reconstruir la malla | redibujar el canvas | un sync en worker |
asignar textContent |
| Escrituras complejas | no | sí, el motor del navegador | parcial | sí, el motor del navegador |
| Texto seleccionable y accesible | no | no | no | sí |
| Se ocluye con la geometría | sí | sí | sí | no, hay que programarlo |
| Recibe luz y proyecta sombra | sí | no | sí, con material propio | no |
| Participa del post-procesado | sí | sí | sí | no |
Merece la pena detenerse en tres filas.
La de texturas en VRAM es la que hunde a los sprites de canvas cuando hay muchos: cada etiqueta arrastra su propia imagen, y cincuenta etiquetas legibles rondan los cuarenta megas. Troika comparte un único atlas para toda la tipografía.
La de oclusión es la única en la que el HTML pierde de forma estructural, no por falta de implementación. El compositor del navegador y el búfer de profundidad de WebGL viven en universos separados.
La de luz y sombra es la que salva a TextGeometry de la irrelevancia. Un rótulo metálico en el que un reflejo especular recorre el canto de la letra al girar la cámara solo se consigue con geometría real. Un cuadrado con SDF puede tener material PBR, pero es plano: no hay canto que recorrer.
El árbol
flowchart TB
A[necesito texto en una escena 3D] --> B{tiene que ser accesible o seleccionable}
B -->|si| C[CSS2DRenderer con DOM real]
B -->|no| D{tiene que tener volumen fisico o proyectar sombra}
D -->|si| E[TextGeometry]
D -->|no| F{cambia el contenido en tiempo real}
F -->|si, cada cuadro| G[Sprite de canvas con textura reutilizada]
F -->|no o rara vez| H{hay muchas etiquetas o el usuario puede acercarse mucho}
H -->|si| I[troika con SDF]
H -->|no| J{necesito escritura arabe india o tailandesa}
J -->|si| G
J -->|no| I
style A fill:#89b4fa,color:#11111b
style B fill:#cba6f7,color:#11111b
style D fill:#cba6f7,color:#11111b
style F fill:#cba6f7,color:#11111b
style H fill:#cba6f7,color:#11111b
style J fill:#cba6f7,color:#11111b
style C fill:#a6e3a1,color:#11111b
style E fill:#f9e2af,color:#11111b
style G fill:#a6e3a1,color:#11111b
style I fill:#a6e3a1,color:#11111bLas dos preguntas de arriba son eliminatorias y por eso van primero. La accesibilidad no admite sustituto: si el texto tiene que llegar a un lector de pantalla o al buscador de la página, ninguna de las tres técnicas que rasterizan sirve. Y el volumen físico tampoco: no hay forma de simular con un cuadrado el bisel de una letra recibiendo luz rasante.
La tercera pregunta separa lo que cambia de lo que no. Un contador de fotogramas que se actualiza sesenta veces por segundo con TextGeometry reconstruye decenas de miles de triángulos por cuadro; con troika lanza un sync por cuadro que satura el worker; con un canvas reutilizado es un fillText y un needsUpdate, que es lo que esa técnica hace mejor que nadie.
Las tres combinaciones que aparecen siempre
Troika para el mundo, CSS2D para la interfaz. El texto que forma parte de la escena —nombres de calles sobre un mapa, etiquetas de piezas dentro de un modelo— va en troika, porque se ocluye correctamente y aguanta el zoom. El texto con el que el usuario interactúa —un panel de información, un menú contextual— va en CSS2D, porque necesita eventos, foco y accesibilidad. Cada uno hace lo que el otro no puede.
TextGeometry para el titular, troika para el resto. Una portada con tres palabras en relieve metálico y todo el texto secundario en SDF. Las tres palabras cuestan lo que cuestan pero son tres, y el resto no paga.
Canvas para lo que cambia, troika para lo que no. Un panel de telemetría donde las etiquetas son fijas y los valores cambian diez veces por segundo: las etiquetas en troika con un solo sync al arrancar, los valores en un canvas que se redibuja. El truco está en no destruir la textura del canvas: se reutiliza el mismo CanvasTexture limpiando y repintando, con textura.needsUpdate = true.
// Un valor numerico que cambia sin reconstruir nada
const canvas = document.createElement( 'canvas' );
canvas.width = 256;
canvas.height = 64;
const ctx = canvas.getContext( '2d' );
const textura = new THREE.CanvasTexture( canvas );
textura.colorSpace = THREE.SRGBColorSpace;
const sprite = new THREE.Sprite(
new THREE.SpriteMaterial( { map: textura, transparent: true } )
);
sprite.scale.set( 1.0, 0.25, 1 );
function actualizarValor( v ) {
ctx.clearRect( 0, 0, 256, 64 );
ctx.font = '600 40px system-ui, sans-serif';
ctx.fillStyle = '#a6e3a1';
ctx.textBaseline = 'middle';
ctx.fillText( v.toFixed( 1 ) + ' rpm', 8, 32 );
textura.needsUpdate = true; // el unico coste es una subida de 64 KB
}
Esa subida de textura por cambio es el precio, y es lineal en el número de píxeles del canvas, no en la longitud del texto. Un canvas de 256 por 64 son 64 KB por actualización; a diez actualizaciones por segundo son 640 KB por segundo, perfectamente asumible. El mismo canvas a 2048 por 512 serían 40 MB por segundo, que no lo es.
Antes de recorrer el árbol conviene hacerse una pregunta que lo cortocircuita: este texto, cuya legibilidad me importa, tiene alguna razón para estar dentro del espacio 3D. Muchísimas veces la respuesta honesta es que no. Un título, un panel de ayuda, un contador de puntuación, un menú: todo eso vive mejor en HTML plano posicionado con CSS encima del canvas, sin ningún renderer adicional, sin proyecciones, sin oclusión que resolver y con accesibilidad y responsividad gratis. Las cuatro técnicas de este nivel existen para el caso en que el texto tiene que compartir el espacio con la geometría: porque está anclado a un punto que se mueve, porque debe quedar oculto tras un objeto, porque forma parte del material de una superficie o porque el usuario va a orbitar alrededor de él. Si ninguna de esas cuatro cosas es cierta, cualquier técnica de texto en 3D es un coste que estás pagando por decoración. El error opuesto es igual de caro pero mucho menos frecuente: meter en HTML una etiqueta que tenía que estar anclada a un objeto móvil, y acabar reimplementando a mano la proyección que CSS2DRenderer ya te daba hecha.