web-dev-qa-db-fra.com

Comment détecter une collision dans Three.js?

J'utilise three.js.

J'ai deux géométries de maillage dans ma scène.

Si ces géométries sont intersectées (ou se croiseraient si elles sont traduites), je veux détecter cela comme une collision.

Comment procéder pour détecter les collisions avec three.js? Si three.js ne dispose pas de fonctionnalités de détection de collision, existe-t-il d'autres bibliothèques que je pourrais utiliser en conjonction avec three.js?

41
eqiproo

Dans Three.js, les utilitaires CollisionUtils.js et Collisions.js ne semblent plus être pris en charge, et mrdoob (créateur de three.js) lui-même recommande la mise à jour vers la version la plus récente de three.js et utilise la classe Ray à cet effet au lieu. Ce qui suit est une façon de procéder.

L'idée est la suivante: disons que nous voulons vérifier si un maillage donné, appelé "Player", croise des mailles contenues dans un tableau appelé "collidableMeshList". Ce que nous pouvons faire, c'est créer un ensemble de rayons qui commencent aux coordonnées du maillage Player (Player.position) et s'étendent vers chaque sommet de la géométrie du maillage Player. Chaque rayon a une méthode appelée "intersectObjects" qui renvoie un tableau d'objets que le rayon a intersecté et la distance à chacun de ces objets (telle que mesurée à partir de l'origine du rayon). Si la distance à une intersection est inférieure à la distance entre la position du joueur et le sommet de la géométrie, alors la collision s'est produite à l'intérieur du maillage du joueur - ce que nous appellerions probablement une collision "réelle".

J'ai publié un exemple de travail sur:

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

Vous pouvez déplacer le cube filaire rouge avec les touches fléchées et le faire pivoter avec W/A/S/D. Lorsqu'il intersecte l'un des cubes bleus, le mot "Hit" apparaîtra en haut de l'écran une fois pour chaque intersection comme décrit ci-dessus. La partie importante du code est ci-dessous.

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...
    }
}

Il y a deux problèmes potentiels avec cette approche particulière.

(1) Lorsque l'origine du rayon est dans un maillage M, aucun résultat de collision entre le rayon et M ne sera retourné.

(2) Il est possible qu'un objet qui est petit (par rapport au maillage du joueur) "glisse" entre les différents rayons et donc aucune collision ne sera enregistrée. Deux approches possibles pour réduire les risques de ce problème sont d'écrire du code afin que les petits objets créent les rayons et effectuent l'effort de détection de collision de leur point de vue, ou incluent plus de sommets sur le maillage (par exemple en utilisant CubeGeometry (100, 100, 100, 20, 20, 20) plutôt que CubeGeometry (100, 100, 100, 1, 1, 1).) Cette dernière approche entraînera probablement une baisse des performances, donc je recommande de l'utiliser avec parcimonie.

J'espère que d'autres contribueront à cette question avec leurs solutions à cette question. J'ai moi-même lutté pendant un bon moment avant de développer la solution décrite ici.

96
Lee Stemkoski

C'est vraiment beaucoup trop large d'un sujet à couvrir dans une question SO, mais dans le but de graisser un peu le référencement du site, voici quelques points de départ simples:

Si vous voulez une détection de collision vraiment simple et non un moteur physique complet, consultez Three.js: Détection de collision simple

Si, d'autre part, vous voulez une réponse aux collisions, pas seulement "A et B ont-ils sauté?", Jetez un œil à Physijs , qui est un wrapper Ammo.js super facile à utiliser construit autour Three.js

5
Toji