web-dev-qa-db-fra.com

Meilleur algorithme pour une détection efficace des collisions entre objets

Je suis confus. Eh bien pas confus, autant que de ne pas vouloir faire 6 programmes de test pour voir quel algorithme est le meilleur. J'ai donc pensé demander à mes amis experts ici à SO de me faire bénéficier de leur expérience.

Le scénario est une scène 3D avec potentiellement une assez grande surface par rapport à la taille des objets à l'intérieur. Il y a potentiellement des milliers d'objets dans la scène. La taille des objets varie du dixième d'une unité à environ 10 unités, mais pas plus grande (ou plus petite). Les objets ont tendance à être regroupés, mais ces groupes peuvent potentiellement apparaître n'importe où dans la scène. Tous les objets sont dynamiques et en mouvement. Les grappes ont tendance à se déplacer ensemble, mais quand elles le font, leur vitesse peut ne pas être la même tout le temps. Il y a aussi la géométrie statique à considérer. Bien qu'il y ait un grand nombre d'objets dynamiques, il y a aussi quelques objets statiques dans la scène (les objets statiques ont tendance à être un ou deux ordres de grandeur plus grands que les objets dynamiques).

Maintenant, ce que je veux, c'est une structure de données spatiales pour effectuer efficacement la détection de collision pour tous les éléments de la scène. Ce serait bien si l'algorithme supportait également la requête de visibilité pour le pipeline de rendu. Par souci de simplicité, supposons que la détection de collision est ici à phase large (c'est-à-dire que tous les objets dynamiques ne sont que des sphères parfaites).

Donc, dans mes recherches, je peux utiliser l'un des:

(1) Octree (2) Octree lâche (3) Octree linéaire (+ lâche) (4) Arbre KD (5) Arbre BSP (6) Hachage

Jusqu'à présent (6) est le seul que j'ai essayé. C'est en fait totalement superbe en termes de vitesse (8192 collisions d'objets enregistrées en moins de 1 ms sur mon système) si les objets de la scène sont en moyenne uniformément répartis. Ce n'est pas un si bon algorithme si tous les objets sont découpés dans une zone plus petite, ce qui, je suppose, est possible.

Quelqu'un a-t-il une idée de celui à utiliser ou des astuces que je peux utiliser pour accélérer les choses? Je pense que quoi qu'il arrive, je peux simplement utiliser un arbre BSP distinct pour la géométrie statique. Je suppose que les "sphères" dynamiques sont ce qui me préoccupe le plus ici. Remarque: pas de CUDA, c'est uniquement CPU: p.

Merci

EDIT: Ok, grâce à Floris, j'ai trouvé plus d'informations sur les arbres AABB. Il y a une vieille discussion sur GameDev ici: http://www.gamedev.net/topic/308665-aabb-tree---wheres-the-poly-o_o/ . On dirait un bon compromis.

EDIT final: décidé de ne pas réinventer la roue. Il est possible que la bibliothèque de physique des puces fasse tout cela pour moi (elle contient un arbre AABB, probablement très bien optimisé aussi).

42
Robinson

Grande question.

Vous avez essentiellement un compromis complexe entre:

  1. Vitesse d'une phase complète de détection de collision
  2. Frais généraux de mise à jour/maintenance de la structure de données à mesure que les objets se déplacent

La mauvaise nouvelle est qu'il n'y a pas de réponse "parfaite" à cause de cela - cela dépendra vraiment de nombreux facteurs différents propres à votre situation. Les BSP par exemple sont extrêmement rapides pour 1. lorsqu'ils sont pré-calculés avec beaucoup de géométrie planaire statique, ce qui explique pourquoi ils étaient si répandus dans les premiers jeux FPS.

Ma supposition personnelle est qu'un arbre AABB (Axis Aligned Bounding Box) lâche avec un nombre raisonnable d'objets (5-10?) Dans chaque zone de délimitation de niveau inférieur fonctionnera probablement mieux dans votre cas. Les raisons:

  • Vous avez un espace assez grand/clairsemé avec des grappes d'objets. Les arbres AABB ont tendance à être bons pour cela, car vous pouvez supprimer de nombreux niveaux dont vous auriez autrement besoin.
  • Vous supposez des sphères parfaites. Les tests de collision de sphère à sphère sont très bon marché, vous pouvez donc facilement vous permettre de faire 10 à 45 tests pour chaque nœud de niveau inférieur. Fondamentalement, N ^ 2 convient pour les petites valeurs de N :-)
  • L'alignement des axes rend la mise à jour de l'arbre beaucoup plus simple et les tests d'intersection beaucoup moins chers que la plupart des alternatives. Puisque vous supposez des objets à peu près sphériques, je ne pense pas que vous gagneriez beaucoup à des boîtes englobantes orientées (qui ne vous donnent vraiment un avantage que si vous avez beaucoup de formes longues/minces à des angles amusants).
  • En permettant aux zones de délimitation d'être lâches et de contenir un nombre raisonnable d'objets, vous réduisez les chances que le mouvement d'un objet individuel le fasse sortir des limites AABB. À moins que cela ne se produise, vous n'avez pas besoin de mettre à jour l'arborescence. Cela vous fera économiser beaucoup de temps de mise à jour de l'arborescence. Lorsque cela se produit, étendez la limite avec un peu de marge afin de ne pas avoir à retendre immédiatement l'image suivante - rappelez-vous que la plupart des mouvements ont tendance à continuer dans la même direction pendant quelques images!

Désolé pour la réponse légèrement laineuse mais j'espère que cela vous donne quelques idées/choses utiles à considérer!

19
mikera

De nombreux moteurs physiques utilisent un AABBTree (Axis Bounding Box Tree), il subdivise un objet en morceaux de plus en plus petits. Vous pouvez obtenir une très bonne détection des collisions en utilisant cet algo. Cet arbre ressemble un peu à un octree.

Un OOBBTree (boîte de délimitation orientée) serait sa meilleure contrepartie.

5
Floris