2012-07-13 26 views
32

Estoy usando three.js.¿Cómo detectar colisión en three.js?

Tengo dos geometrías de malla en mi escena.

Si estas geometrías se intersecan (o se cruzan con si se traducen) Quiero detectar esto como una colisión.

¿Cómo hago para realizar la detección de colisión con three.js? Si three.js no tiene instalaciones de detección de colisiones, ¿hay otras bibliotecas que pueda utilizar en conjunción con three.js?

+2

Una pregunta de un trazador sobre cómo hacer algo tan amplio como la detección de colisiones no es realmente una pregunta, sino un tema de aprendizaje. Google es tu amigo. – Nate

+2

Lo busqué en google, pero solo encontré colisión de rayos. – eqiproo

+4

Creo que la colisión de rayos es el camino a seguir ... los archivos CollisionUtils.js y Collisions.js a los que Adnan (presumiblemente) hace referencia están desactualizados y no son parte de los tres más recientes (v49 al momento de escribir). js versión. –

Respuesta

85

En Three.js, la utilidad enlaces CollisionUtils.js y Collisions.js ya no parecen ser compatibles, y mrdoob (creador de three.js) mismo recomienda actualizar a la versión más reciente de three.js y utilizar la clase Ray para este fin en su lugar. Lo que sigue es una forma de hacerlo.

La idea es esta: digamos que queremos comprobar si una malla determinada, llamada "Reproductor", interseca las mallas contenidas en una matriz llamada "collidableMeshList". Lo que podemos hacer es crear un conjunto de rayos que empiecen en las coordenadas de la malla del jugador (Player.position), y se extiendan hacia cada vértice en la geometría de la malla del jugador. Cada rayo tiene un método llamado "intersectObjetos" que devuelve una matriz de objetos con los que se cruzó el rayo, y la distancia a cada uno de estos objetos (medida desde el origen del rayo). Si la distancia a una intersección es menor que la distancia entre la posición del jugador y el vértice de la geometría, entonces la colisión ocurrió en el interior de la malla del jugador, lo que probablemente llamaríamos una colisión "real".

He publicado un ejemplo de trabajo en:

http://stemkoski.github.io/Three.js/Collision-Detection.html

Puede mover el cubo de alambre rojo con las teclas de flecha y girarlo con W/A/S/D. Cuando se cruza con uno de los cubos azules, la palabra "Hit" aparecerá en la parte superior de la pantalla una vez para cada intersección como se describe arriba. La parte importante del código está debajo.

for (var vertexIndex = 0; vertexIndex < Player.geometry.vertices.length; vertexIndex++) 
{  
    var localVertex = Player.geometry.vertices[vertexIndex].clone(); 
    var globalVertex = Player.matrix.multiplyVector3(localVertex); 
    var directionVector = globalVertex.subSelf(Player.position); 

    var ray = new THREE.Ray(Player.position, directionVector.clone().normalize()); 
    var collisionResults = ray.intersectObjects(collidableMeshList); 
    if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) 
    { 
     // a collision occurred... do something... 
    } 
} 

Existen dos posibles problemas con este enfoque particular.

(1) Cuando el origen del rayo está dentro de una malla M, no se generarán resultados de colisión entre el rayo y M.

(2) Es posible que un objeto que es pequeño (en relación con la malla del reproductor) se "deslice" entre los diversos rayos y por lo tanto no se registrará ninguna colisión. Dos posibles enfoques para reducir las posibilidades de este problema son escribir código para que los objetos pequeños creen los rayos y realizar el esfuerzo de detección de colisiones desde su perspectiva, o incluir más vértices en la malla (por ejemplo, utilizando CubeGeometry (100, 100, 100, 20, 20, 20) en lugar de CubeGeometry (100, 100, 100, 1, 1, 1).) El último enfoque probablemente causará un golpe de rendimiento, por lo que recomiendo usarlo con moderación.

Espero que otros contribuyan a esta pregunta con sus soluciones a esta pregunta. Luché con él durante bastante tiempo antes de desarrollar la solución que se describe aquí.

+4

¡Gracias por esta explicación detallada! También estoy luchando por encontrar una solución decente para mi juego con objetos en 3D y terreno, y tu respuesta me dio algunas nuevas ideas. – Nick

+3

Si bien este método parece probar si cualquier vértice se cruza desde el centro del objeto, sería el doble de lento pero 100% (?) Preciso para probar todos los bordes (vértices conectados). Entonces, para elaborar, necesitaría recorrer cada cara, y tomar el vértice [n] y el vértice [(n + 1)% len] para obtener todos los bordes. Si abracé a alguien, se cruzan con el centro de mi posición y mi mano, pero no se cruzan con mi piel, como haría una verificación de borde. – Funkodebat

+0

¡Es una buena idea! Para una precisión del 100% (?), Creo que necesitaría probar los bordes en cada una de las dos mallas, y debería probarlas yendo en ambas direcciones, ya que las colisiones solo se detectan en una dirección, cuando el rayo pasa de el exterior hacia el interior de la malla. Claro que podría ser un poco más lento, pero podría acelerarlo con una verificación preliminar del radio de esfera límite. Pero lo más importante, creo que puede estar en lo cierto con una precisión del 100% ... –

6

Esto realmente es demasiado amplia de un tema a cubrir en una pregunta SO, pero en aras de la lubricación del SEO del sitio un poco, aquí hay un par de puntos de partida simples:

Si quieres realmente detección de colisión simple y no un completo en el motor de física a continuación, echa un vistazo a Three.js: Simple Collision Detection

Si, por el contrario te quieren algún tipo de respuesta de colisión, no sólo "hicieron a y B chocan?", echar un vistazo a Physijs, que es una envoltura Ammo.js super fácil de usar construida alrededor de Three.js

+3

La demostración que ha vinculado es colisión de rayos – eqiproo