Solución:
No utilice three.js Raycaster.
Considere Ray.js que ofrece function intersectTriangle(a, b, c, backfaceCulling, target)
Optimizaciones sugeridas:
-
Si el jugador comienza desde algunas posiciones conocidas ⇒ debe conocer su altura inicial, – no es necesario hacer Raycast (o simplemente hacer una intersección lenta de malla completa una vez)
-
si el jugador se mueve con pasos pequeños ⇒ el próximo raycast más probable intersecan la misma cara que antes.
Optimización n. ° 1 – recuerda la cara anterior y haz un raycast primero.
- si el jugador no salta ⇒ el próximo raycast lo hará más probable intersecar la cara adyacente a la cara donde el jugador estaba antes.
Optimización # 2 – crear un caché, de modo que, dado un idx de rostro, pueda recuperar rostros adyacentes en O (1) tiempo.
Este caché se puede cargar desde el archivo, si su planeta no se genera en tiempo real.
Entonces, con mi enfoque en cada movimiento, haces O (1) operación de lectura desde el caché y raycast 1-6 caras.
¡Ganar!
Para un objeto complejo, lleva una eternidad. Se necesitan ~ 200ms para un objeto con ~ 1m polys (caras) (esfera de 1024 x 512 segmentos). ¿Raycasting se lanza contra todos y cada uno de los rostros?
Fuera de la caja THREE.js lo hace compruebe todos los triángulos al realizar un raycast contra una malla y no hay estructuras de aceleración integradas en TRES.
Sin embargo, he trabajado con otros en el paquete three-mesh-bvh (github, npm) para ayudar a abordar este problema, lo que puede ayudarlo a alcanzar las velocidades que busca. Así es como puede usarlo:
import * as THREE from 'three';
import { MeshBVH, acceleratedRaycast } from 'three-mesh-bvh';
THREE.Mesh.prototype.raycast = acceleratedRaycast;
// ... initialize the scene...
globeMesh.geometry.boundsTree = new MeshBVH(globeMesh.geometry);
// ... initialize raycaster...
// Optional. Improves the performance of the raycast
// if you only need the first collision
raycaster.firstHitOnly = true;
const intersects = raycaster.intersectObject(globeMesh, true);
// do something with the intersections
Hay algunas advertencias mencionadas en el archivo README, así que téngalas en cuenta (el índice de malla se modifica, solo se admite BufferGeometry no animado, etc.). Y todavía hay algo de optimización de la memoria que se podría hacer, pero hay algunas opciones modificables para ayudar a ajustar eso.
¡Me interesará saber cómo funciona esto para ti! No dude en dejar comentarios sobre los problemas sobre cómo mejorar el paquete. ¡Espero que ayude!
Creo que deberías renderizar previamente el mapa de altura de su globo en una textura, asumiendo que su terreno no es dinámico. Lea todo en una matriz escrita, y luego, cada vez que su jugador se mueva, solo necesita retroproyectar sus coordenadas en esa textura, consultarla, compensarla y multiplicarla y debería obtener lo que necesita en O (1) tiempo.
Depende de usted cómo generar ese mapa de altura. En realidad, si tiene un globo lleno de baches, entonces probablemente debería comenzar con el mapa de altura en primer lugar y usarlo en su sombreador de vértices para representar el globo (con la esfera de entrada perfectamente suave). Entonces puedes usar el mismo mapa de altura para consultar el Z.