Estoy haciendo yo solo un simulador de vuelo espacial que corre en el navegador, con todo a su distancia real. Sales de la Tierra, pasas por los planetas en la posición que tienen hoy, vuelas entre estrellas cercanas y terminas fuera de la Vía Láctea y en Andrómeda. Es gratis y no pide registro.
https://howsmallarewe.com/es/?utm_source=devto_es
Está hecho con three.js 0.170 y Vite. En la misma escena tiene que verse Saturno desde 3.494 km de altura y Andrómeda a unos 2,5 millones de años luz, y eso rompió varias cosas.
Origen flotante y scaled space
En los shaders se trabaja con float32, así que las posiciones reales viven en la CPU como números de JavaScript (double), en kilómetros. En cada fotograma le resto la posición de la cámara a todo, la cámara queda siempre en el origen y a la GPU solo le llegan coordenadas relativas.
Aun así, los polígonos a más de unos 1e15 km se dibujaban mal. Todo lo que está más lejos de 2e10 km (más allá de la órbita de Neptuno) lo acerco a esa distancia sobre la misma dirección y lo escalo por el mismo factor. Ocupa el mismo ángulo en pantalla y la GPU trabaja con números manejables.
Planetas que desaparecían enteros
Uso logarithmicDepthBuffer: true. Con esta relación near/far, en la proyección estándar el z de clip queda casi igual a w, y en GPUs reales, por redondeo, z a veces superaba a w por muy poco. El vértice quedaba "más allá del plano lejano" y el planeta entero se recortaba.
Con el depth buffer logarítmico, three.js escribe la profundidad aparte en el fragment shader (gl_FragDepth), así que el z de clip ya no hace falta para la profundidad. Lo dejo siempre en 0 parcheando el chunk en un módulo que importo en la primera línea del archivo principal:
const CHUNK = THREE.ShaderChunk.logdepthbuf_vertex; if (!CHUNK.includes('gl_Position.z = 0.0')) { THREE.ShaderChunk.logdepthbuf_vertex = `${CHUNK} #ifdef USE_LOGDEPTHBUF gl_Position.z = 0.0; #endif`; } Los vértices detrás de la cámara (w < 0) se siguen recortando por la comprobación de rango de x, y, z. Si tienen ShaderMaterial propios, hay que meter los #include de logdepthbuf en el vertex y en el fragment. En mi caso eran las ~110.000 estrellas del catálogo HYG, que son un THREE.Points con shader propio y calculan su brillo según la distancia real a la cámara.
Cielo en ultravioleta
Con la tecla V todo el cielo cambia al nuevo mapa ultravioleta de todo el cielo de Brice Ménard (presentado con Anthropic, hecho con Claude Science). Según su autor, cerca de un tercio del mapa, sobre todo el plano galáctico, es predicción a partir de otras longitudes de onda. La Vía Láctea vista desde fuera es un modelo, no una foto.
Lo que me gustaría saber
- Parchear
THREE.ShaderChunkde forma global funciona, pero temo que se rompa con alguna actualización de three.js. ¿Alguien resolvió escalas así de otra manera, por ejemplo con reversed-Z o dividiendo la escena en varias pasadas por distancia? - Cómo va la tasa de fotogramas en su equipo, sobre todo en portátiles y teléfonos (los teléfonos cargan texturas 4K en lugar de 8K).
- Cualquier cosa que se vea mal en los cambios de escala, como estrellas que aparecen de golpe o parpadeo de profundidad.
El código no está publicado, pero si a alguien le sirve puedo pegar más fragmentos en los comentarios.
Créditos: mapa UV de Ménard (CC BY 4.0), texturas de planetas de Solar System Scope (CC BY 4.0), HYG Database v3.5.1 (CC BY-SA 2.5), posiciones de Astronomy Engine (MIT).




