Construir un mundo abierto en el navegador, parte 8: Integración sin perder nuestra base de referencia
Por Oleg Sidorkin, CTO y cofundador de Cinevva
¿Es tu primera vez aquí? Consulta la guía de la serie. Explica qué es un spike y contiene enlaces a todas las partes.
La integración es el momento en que los proyectos se vuelven caóticos. Tienes piezas que funcionan de forma aislada. Las conectas y, de repente, parece que cada error podría estar en cualquier parte.
Los spikes 13 y 14 fueron nuestra respuesta a esa trampa. El spike 13 estableció una base limpia de Three.js con WebGPU. Solo un renderizador, una escena, una cámara y una malla sencilla. Sin terreno, sin cómputo y sin efectos. Confirmamos que el backend WebGPU de Three.js se inicializaba correctamente, que el bucle de renderizado era estable y que los materiales de nodos de TSL (Three.js Shading Language) funcionaban como esperábamos. Solo después de superar ese punto de control empezamos a añadir capas.
Abrir el spike 13 en una pestaña nueva ↗ · Ver el código fuente
El spike 14 consistió en un refuerzo incremental. Añadimos una capacidad cada vez: primero los controles de cámara, después la iluminación, luego la malla generada por cómputo mediante el pipeline de marching cubes y, por último, las conexiones de búfer necesarias para enviar la salida de la GPU directamente a los atributos de geometría de Three.js. Después de cada incorporación, verificamos que la capa anterior siguiera comportándose correctamente.
Abrir el spike 14 en una pestaña nueva ↗ · Ver el código fuente
Eso suena lento. Lo fue durante exactamente un día, y poco después nos ahorró varios días cuando la lógica de costuras y el cambio de políticas se complicaron.
La categoría concreta de error que justificó esta disciplina fueron los artefactos finísimos. Eran fragmentos delgados que parecían indicar una geometría dañada, pero que en realidad se debían a datos obsoletos. El shader de cómputo escribía N vértices en un búfer, pero la llamada de dibujado seguía configurada para renderizar N+M vértices del fotograma anterior. Esos vértices adicionales contenían basura de la ejecución anterior. El resultado visual eran triángulos parpadeantes y finos como cuchillas que aparecían y desaparecían de forma impredecible.
Ese tipo de error no se vence con intuición. Se vence mediante cambios controlados que permiten saber exactamente qué ha cambiado entre el último estado funcional y el estado actual con errores.
La integración de WebGPU también nos enseñó mucho sobre el ciclo de vida de los búferes. Los búferes de GPU en WebGPU son inmutables una vez asignados para un uso específico. Si necesitas cambiar el tamaño de un búfer de vértices porque ha crecido la salida de marching cubes, tienes que crear uno nuevo y actualizar el enlace. No existe realloc. Gestionar correctamente ese ciclo de vida y destruir los búferes antiguos sin entrar en conflicto con el trabajo de la GPU aún en curso requirió una gestión explícita de fences que no existe en WebGL.
En la parte 9 pasamos al trabajo con costuras de Transvoxel. Ese capítulo comienza deliberadamente con un armazón básico. Para entonces ya habíamos interiorizado por completo la lección: precipitar la integración genera misterios, mientras que una preparación controlada genera problemas que se pueden depurar.
Tecnología mencionada en este capítulo
WebGPU. El sucesor de WebGL, que ofrece acceso de bajo nivel a la GPU desde el navegador mediante shaders de cómputo y renderizado indirecto. Las dos funciones esenciales de WebGPU para los mundos abiertos son las siguientes: los shaders de cómputo permiten generar terreno, colocar vegetación y realizar el descarte desde la GPU; el renderizado indirecto permite que la GPU decida qué dibujar a partir de la salida del cómputo, eliminando los cuellos de botella de la CPU en escenas densas. Está disponible en Chrome, Edge y Firefox para equipos de escritorio. Consulta WebGPU como clave para mejorar el rendimiento.
Three.js Shading Language (TSL). El sistema de shaders basado en nodos de Three.js, que sustituye el código GLSL/WGSL sin procesar por expresiones de JavaScript componibles. Los nodos de TSL como texture(), positionWorld, smoothstep() y fog() crean en tiempo de ejecución un grafo de shaders que se compila para el backend correspondiente (GLSL de WebGL o WGSL de WebGPU). TSL permite escribir una vez la lógica de los materiales y utilizarla con ambos renderizadores. El grafo de nodos se evalúa en cada fotograma, por lo que los uniformes dinámicos y las bifurcaciones condicionales funcionan de manera natural.
Ciclo de vida de los búferes de GPU en WebGPU. Los búferes de WebGPU se crean con indicadores de uso específicos (VERTEX, STORAGE, COPY_DST, etc.) y no se puede cambiar su tamaño después de crearlos. Si una ejecución de marching cubes produce más vértices de los que caben en el búfer, debes crear uno nuevo, actualizar el enlace y destruir el anterior. Destruir un búfer al que todavía hace referencia un comando de GPU en curso provoca errores. La gestión explícita de fences (mediante device.queue.onSubmittedWorkDone()) garantiza que el búfer antiguo no se destruya hasta que la GPU haya terminado de utilizarlo. Esta disciplina del ciclo de vida no existe en WebGL, donde el controlador gestiona la memoria de forma implícita.
Refuerzo incremental. Una disciplina de integración que consiste en establecer una base de referencia cuyo correcto funcionamiento esté confirmado, añadir una capacidad cada vez y verificar que la capa anterior siga funcionando después de cada incorporación. Este enfoque es más lento durante un día, pero ahorra días en la depuración posterior, porque cada regresión puede rastrearse hasta un cambio concreto y controlado. El patrón de establecer primero una base y después avanzar de forma incremental es habitual en el desarrollo de mundos abiertos AAA, donde los sistemas se integran en un orden específico para gestionar el riesgo.
Parte 8 de 12.
Anterior: Parte 7: Marching cubes y las primeras cuevas reales
Siguiente: Parte 9: Transvoxel comenzó con un armazón básico
Guía de la serie: /es/blog/2026-02-25-open-world-browser-series-guide