Le moteur physique est-il capable de réduire cette complexité, par exemple en regroupant des objets proches les uns des autres et en vérifiant les collisions à l'intérieur de ce groupe plutôt que contre tous les objets? (par exemple, des objets éloignés peuvent être supprimés d'un groupe en regardant sa vitesse et sa distance par rapport à d'autres objets).
Sinon, cela rend-il la collision triviale pour les sphères (en 3D) ou les disques (en 2D)? Dois-je faire une double boucle ou créer un tableau de paires à la place?
EDIT: Pour un moteur physique comme bullet et box2d, la détection de collision est-elle toujours O (N ^ 2)?
Réponses:
La division spatiale est toujours O (N ^ 2) dans le pire des cas et c'est à cela que sert la complexité de l'informatique.
Cependant il existe des algorithmes qui fonctionnent en temps linéaire O (N) . Tous sont basés sur une sorte de ligne de balayage.
Fondamentalement, vous devez trier vos objets selon une seule coordonnée. Disons X. Si vous effectuez le tri à chaque fois avant la détection de collision, la complexité sera O (N * logN). L'astuce consiste à trier uniquement lorsque vous ajoutez des objets à la scène et plus tard lorsque quelque chose change dans la scène. Le tri après mouvement n'est pas anodin. Voir l'article lié ci-dessous pour un algorithme qui prend en mouvement et fonctionne toujours en temps linéaire.
Ensuite, vous balayez de gauche à droite. Chaque fois que votre ligne de balayage traverse le début d'un objet, vous le placez dans une liste temporaire. Chaque fois que votre ligne de balayage quitte l'objet, vous le retirez de la liste. Vous ne considérez les collisions qu'à l'intérieur de cette liste temporaire.
La ligne de balayage naïf est également O (N ^ 2) dans le pire des cas (vous faites en sorte que tous les objets s'étendent sur toute la carte de gauche à droite), mais vous pouvez la rendre O (N) en la rendant plus intelligente (voir le lien ci-dessous). Un très bon algorithme sera assez complexe.
Voici un schéma simple du fonctionnement de la ligne de balayage:
La ligne passe de gauche à droite. Les objets sont triés par coordonnée X.
De tels algorithmes ont une complexité O (C * N) = O (N).
Source: Deux ans de cours de géométrie computationnelle.
Dans la détection de collision, cela est généralement appelé balayage et élagage , mais la famille d'algortithmes de lignes de balayage est utile dans de nombreux autres domaines.
Lecture supplémentaire recommandée qui, selon moi, est hors de portée de cette question, mais néanmoins intéressante: Méthodes efficaces de balayage et d'élagage à grande échelle avec insertion et retrait AABB - Cet article présente un algorithme amélioré de balayage et d'élagage qui utilise des boîtes de délimitation alignées sur l'axe (AABB ) avec un tri prenant en compte les mouvements. Algorigthm présenté dans les travaux papier en temps linéaire.
Notez maintenant que c'est le meilleur algorithme en théorie . Cela ne signifie pas qu'il est utilisé. En pratique, l'algorithme O (N ^ 2) avec division spatiale aura de meilleures performances en termes de vitesse dans un cas typique (proche de O (N)) et un besoin supplémentaire de mémoire. En effet, la constante C dans O (C * N) peut être très élevée! Comme nous avons généralement suffisamment de mémoire et que les cas typiques ont des objets répartis uniformément dans l'espace - un tel algorithme fonctionnera mieux. Mais O (N) est la réponse à la question d'origine.
la source
Non. La détection de collision n'est pas toujours O (N ^ 2).
Par exemple, disons que nous avons un espace de 100x100 avec des objets de taille 10x10. Nous pourrions diviser cet espace en cellules de 10x10 avec une grille.
Chaque objet peut se trouver dans jusqu'à 4 cellules de la grille (il peut s'insérer directement dans un bloc ou être «entre» les cellules). Nous pourrions garder une liste d'objets dans chaque cellule.
Nous avons seulement besoin de vérifier les collisions dans ces cellules. S'il y a un nombre maximum d'objets par cellule de grille (par exemple, il n'y a jamais plus de 4 objets dans le même bloc), la détection de collision pour chaque objet est O (1) et la détection de collision pour tous les objets est O (N).
Ce n'est pas le seul moyen d'éviter la complexité O (N ^ 2). Il existe d'autres méthodes, plus adaptées à d'autres cas d'utilisation - utilisant souvent des structures de données basées sur des arbres.
L'algorithme que j'ai décrit est un type de partitionnement d'espace , mais il existe d'autres algorithmes de partitionnement d'espace. Voir Types de structures de données de partitionnement d'espace pour plus d'algorithmes qui évitent la complexité temporelle O (N ^ 2).
Les mécanismes de prise en charge Box2D et Bullet réduisent le nombre de paires vérifiées.
Du manuel , section 4.15:
Du Bullet Wiki :
la source
O (N ^ 2) fait référence au fait que si vous avez N objets, déterminer ce qui entre en collision avec ce qui est, dans le pire des cas , N ^ 2 calculs de collision. Disons que vous avez 3 objets. Pour trouver "qui frappe qui", vous devez trouver:
C'est 6 contrôles pour les collisions, ou N * (N-1) contrôles. En analyse asymptotique, nous élargirions le polynôme et nous approcherions comme O (N ^ 2). Si vous aviez 100 objets, ce serait 100 * 99, ce qui est assez proche de 100 * 100.
Donc, si vous partitionnez l'espace en utilisant un octree par exemple, le nombre moyen de comparaisons entre les corps est réduit. S'il est possible que tous les objets se rassemblent dans une très petite zone (par exemple, si vous faites une sorte de simulation de flux de particules, où les particules peuvent se rassembler dans la même zone), alors l'O (N ^ 2) peut toujours se produire à points dans la simulation (à quels points vous verrez un ralentissement).
Donc, le point entier de O (N ^ 2) est dû à la nature de chaque corps vérifiant tous les autres corps de la scène. C'est juste la nature du calcul. Beaucoup de choses peuvent aider à rendre cela moins cher. Même un graphique de scène (par exemple, la détection entre des objets dans la même pièce uniquement) réduira considérablement le nombre de calculs de collision à effectuer, mais ce sera toujours O (M ^ 2) (où M est le nombre d'objets dans la pièce à contre laquelle une collision a été détectée). Les volumes englobants sphériques rendent la vérification initiale très rapide (
if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS
), donc même si la détection de collision est O (N ^ 2), les calculs de la sphère englobante sont susceptibles de se produire très rapidement.la source