Résoudre une collision avec des forces

14

Dans mon moteur de physique 2D, je peux détecter les collisions AABB vs AABB et les résoudre en trouvant le vecteur de pénétration le plus court et en l'ajoutant à la position de l'AABB.

Faire cela "pousse" le premier AABB en dehors du second AABB, mais ne gère pas du tout les changements de vitesse / accélération.

Si j'ajoute une accélération de la gravité à ma simulation, la vitesse du premier AABB dynamique continue de croître même lorsqu'il repose sur le deuxième AABB statique. Finalement, la vitesse deviendra trop grande et la collision ne sera pas détectée (l'AABB dynamique tombera à travers la statique).

J'ai essayé de mettre la vitesse à zéro après la résolution, mais cela n'a évidemment pas bien fonctionné et j'ai créé des simulations irréalistes.

J'ai lu en ligne que la résolution des collisions en travaillant manuellement sur la position ou la vitesse n'est pas correcte. J'ai essayé de mettre en œuvre des forces (la masse est "codée en dur" 1 pour l'instant):

void Body::applyForce(sf::Vector2f mForce) { acceleration += mForce; }

void Body::integrate(float mFrameTime)
{
    velocity += acceleration * mFrameTime;
    position += velocity * mFrameTime;

    acceleration = {0, 0};
}

Si j'applique le vecteur de pénétration le plus court en tant que force pendant la résolution de la collision, l'AABB dynamique sera "expulsé" du statique, mais sa vitesse ne diminuera jamais dans une simulation sans gravité et il continuera de se déplacer pour toujours.

Existe-t-il un moyen d'appliquer une force "temporaire"? Une force qui s'occupe de pousser le premier AABB hors du second AABB, puis s'arrête lorsque l'AABB ne se heurte plus?

Code source complet disponible ici: https://github.com/SuperV1234/SSVSCollision

Vittorio Romeo
la source
1
Ça m'intéresse. Avez-vous déjà trouvé une solution?
TravisG
@TravisG: pas encore, malheureusement. J'ajouterai une prime demain si je n'ai pas de réponse.
Vittorio Romeo
La force n'est pas égale à l'accélération, tout d'abord. Vous avez besoin de masse pour calculer l'accélération. Si vous modifiez des positions pour empêcher les deux corps de pénétrer, vous devez également utiliser la masse et déplacer les deux corps en fonction de celle-ci. L'application d'une force égale au vecteur de pénétration n'a aucun mérite. Box2D est basé sur l'impulsion, il fonctionne directement sur les vitesses, il n'est peut-être pas "correct", mais c'est assez bon. Gérer les changements de vitesse dans un moteur basé sur les impulsions est très simple, alors pourriez-vous spécifier si vous voulez définitivement une solution basée sur les forces, ou la solution basée sur les impulsions beaucoup plus simple est-elle suffisamment bonne.
dreta
Personnellement, je suggère de prendre un livre sur les moteurs physiques, au moins de lire les premiers chapitres sur la physique newtonienne. Vos hypothèses sont incorrectes et essayer de répondre à cette question signifierait devoir vous enseigner les bases de la physique tout en essayant d'expliquer des algorithmes de haut niveau pour résoudre les collisions.
dreta
@dreta ses hypothèses sont bonnes. Il a souligné que sa masse pour tous les objets est simplement "1" pour l'instant, ce qui rend ses sections de code valides. Soit dit en passant, même si Box2D peut traiter directement les vitesses, il doit en quelque sorte résoudre le même problème. Si au lieu d'appliquer une force, Box2D applique une impulsion, elle doit quand même en quelque sorte tenir compte du fait que l'impulsion ne disparaît pas simplement une fois les objets séparés. Bien, il est possible qu'il ne traite pas du tout de cela et laisse simplement les objets garder leur énergie (ce serait comme ça dans le monde réel après tout)
TravisG

Réponses:

13

Tout d'abord, je recommande d'utiliser une bibliothèque de physique libre et open source comme Box2D et de se concentrer uniquement sur les aspects de votre jeu qui le rendent unique! Si vous insistez pour réinventer la roue, lisez la suite ... notez que tous les moteurs physiques sont des approximations, et bien que la méthode que je décris ci-dessous soit plus précise que votre modèle actuel, les résultats de Box2D seront beaucoup plus réalistes.


Pour un moyen rapide de modéliser une résolution de collision plus précise de deux objets A et B:

  1. Trouvez les positions juste avant la collision. Vous vous rapprochez déjà de ceci en: "trouvant le vecteur de pénétration le plus court et l'ajoutant à la position de l'AABB."
  2. Trouvez les vitesses juste après la collision en utilisant la physique newtonienne :
    • Dans le cas où la masse est codée en dur à 1, il suffit d'échanger les vitesses (cela ne s'applique pas aux objets statiques qui doivent avoir une masse infinie):
      • Av = Bu
      • Bv = Au
    • Si les objets A et B ont des masses différentes:
      • Av = (Au * (Am - Bm) + (2 * Bm * Bu)) / (Am + Bm)
      • Bv = (Bu * (Bm - Am) + (2 * Am * Au)) / (Am + Bm)
    • où:
      • v: vitesse après collision
      • u: vitesse avant collision
      • m: masse (utilisez le plus grand nombre possible pour la masse d'un objet statique fixe)
  3. Réglez l'accélération sur 0: l'accélération de la collision a été prise en compte ci-dessus par les calculs de vitesse à l'étape numéro 2.

Veuillez jeter un œil à mon exemple de programme d'astéroïdes qui illustre ces concepts.


Ensuite, comptez les objets empilés:

Comme vous l'avez noté, l'utilisation de la vitesse pour simuler des objets empilés / au repos ne fonctionne pas bien: la vitesse est la vitesse à laquelle un objet se déplace, donc s'il repose sur un objet statique, la vitesse doit être proche de 0. Il n'est pas logique d'augmenter la vitesse d'un objet pour le faire apparaître au repos:

Si j'ajoute une accélération de la gravité à ma simulation, la vitesse du premier AABB dynamique continue de croître même lorsqu'il repose sur le deuxième AABB statique. Finalement, la vitesse deviendra trop grande et la collision ne sera pas détectée (l'AABB dynamique tombera à travers la statique).

Ce qui devrait vraiment se produire, c'est une force d'accélération qui va dans la direction opposée car la gravité devrait annuler la gravité. (C'est ce qu'on appelle la force de contact normale). Un raccourci consiste simplement à ne pas appliquer la gravité aux corps qui ne sont pas dans l'air:

  • Une méthode pour ce faire consiste à conserver un état "à la terre":
    • N'appliquez pas de gravité sur des objets à la terre.
    • Si un objet entre en collision avec un objet d'en bas et que sa vitesse est très faible, il entre dans l'état de mise à la terre.
    • Un objet quitte l'état ancré lorsque sa vitesse verticale dépasse une certaine valeur positive.

Mise à jour:

  • En termes simples, la physique newtonienne dit que l'énergie totale avant et après une collision doit correspondre. Lorsque deux objets se percutent, leur énergie est redistribuée. L'énergie est une combinaison de vitesse et de poids: les choses plus lourdes et plus rapides ont plus d'énergie. C'est intuitif. Cependant, ce qui n'est pas intuitif, c'est la façon exacte dont les poids affectent la redistribution de l'énergie.
  • L'échange de vitesses n'est un raccourci que pour deux corps dynamiques non fixés qui ont la même masse (les objets fixes statiques ont de très grandes masses infinies).
  • Le raccourci lorsqu'un corps statique est fixé est le suivant: l'autre corps dynamique non fixé conserve la même vitesse; seul l'angle est modifié (imaginez une table de billard lorsqu'une balle frappe le rail. Le rail a essentiellement une très grande masse infinie).
  • Pour d'autres cas, comme trois objets ou plus, les équations de mouvement newtoniennes complètes doivent être résolues (conservation de la quantité de mouvement et conservation de l'énergie cinétique).
  • Je ne sais pas si les équations newtoniennes du mouvement peuvent être résolues pour plus de deux corps. Heureusement, cependant, trois objets ne se heurtent presque jamais en même temps. Il suffit de gérer les deux premiers corps qui entrent en collision, puis de gérer les collisions suivantes en utilisant les nouvelles vitesses des résolutions de collision précédentes. C'est une bonne raison de garder vos pas de temps physiques aussi petits que possible et de gérer les collisions avant toute pénétration.
  • Vous remarquerez que dans ma démo d'astéroïdes, de nombreux corps sont créés lorsque de plus grosses roches sont divisées en plus petites. Cependant, je gère toujours les collisions entre paires de corps; ne jamais gérer explicitement une collision avec plus de deux corps.
Leftium
la source
Merci pour la réponse détaillée. Il y a quelque chose que je ne comprends pas cependant: les vitesses d'échange fonctionnent bien en cas de collision avec 2 corps - cependant, je ne vois pas comment cela peut fonctionner lorsque plusieurs corps (et aussi des corps statiques) entrent en collision en même temps. Même sans gravité, le fait d'avoir un corps dynamique en collision en même temps qu'un corps statique et un autre corps dynamique pose des problèmes. Puisque la vitesse est permutée, tout dépend de l'ordre de collision. Si le corps statique est entré en collision en dernier, le corps cessera de bouger. Si c'est dynamique, le corps bougera à nouveau. Comment est-ce résolu?
Vittorio Romeo
@Vee: Bonnes questions! Les corps trois + et les corps statiques sont deux problèmes distincts. J'ai abordé les deux dans une mise à jour. Résumé: gérer les collisions deux objets à la fois; les corps statiques ont une très grande masse infinie.
Leftium
Votre modèle pour les contacts au repos est étrange. Les contacts au repos ne sont pas seulement pour la gravité, ils devraient fonctionner pour n'importe quelle force. Le moyen le plus simple qui fonctionne est de simplement supprimer la vitesse acquise en raison de l'accélération dans l'image précédente au contact. De plus, pour les petites vitesses, vous pouvez supprimer complètement la restitution, bien que vos calculs ne tiennent pas compte de la restitution. Cette approche fonctionne pour toutes les forces, elle est facile à mettre en œuvre et semble assez bonne.
dreta
16

La résolution de ce problème nécessite d'ajuster la position et éventuellement la vitesse. Les moteurs de physique des corps rigides ont un solveur qui fait avancer les objets dans le temps en utilisant les lois du mouvement de Newton tout en résolvant les contraintes de non-pénétration et les frottements. Ces moteurs peuvent calculer la bonne combinaison de mouvement linéaire et angulaire pour créer des trajectoires plausibles.

Si vous souhaitez uniquement résoudre le chevauchement, vous pouvez utiliser des pseudo-vitesses qui génèrent des trajectoires de séparation sans ajouter à l'élan. Cela se fait dans le solveur de position de Box2D.

Je recommande de recevoir mes présentations GDC de 2006 et 2007 ici:

http://code.google.com/p/box2d/downloads/list

Vous pouvez également consulter Box2D Lite pour une implémentation simplifiée.

Erin Catto
la source
+1 pour la remarque d'être nécessaire d'ajuster également la position. Peu de gens se livrent à cela, mais pour ajouter à la stabilité de la simulation, la plupart des moteurs trichent en ajustant directement les positions. Dans l'ensemble, si c'est plausible, cela fonctionne pour les jeux.
teodron
Merci d'avoir répondu. Je voulais savoir quelque chose qui m'a probablement manqué dans la présentation: les corps statiques sont-ils traités d'une manière spéciale dans Box2D? Je veux dire - que se passe-t-il lorsqu'un corps dynamique heurte un corps statique?
Vittorio Romeo
2

entrez la description de l'image ici

Dans le monde réel, il n'y a aucune force qui "pousse" un corps à l'extérieur d'un autre corps parce que les objets ne se pénètrent jamais. La chose la plus proche est la force normale : créée au moment du contact lors de collisions réelles, elle empêche en premier lieu la pénétration.

L'angle de cette force normale est perpendiculaire à la surface de contact des deux objets en collision. L'ampleur dépend de la force nécessaire pour empêcher la pénétration. (Notez que seule la composante y de la force normale doit être utilisée à moins que d'autres forces comme la force de friction ne soient également modélisées).

Bien qu'il soit possible de modéliser explicitement la force normale, il est plus simple de modéliser uniquement ses effets:

  1. Empêchez l'intersection d'objets par:
    • Ajuster les vitesses en résolvant les collisions au moment de l'impact. (meilleur)
    • Ajuster manuellement les positions des corps afin qu'ils ne se croisent pas. (plus facile) Vous faites déjà cela "en trouvant le vecteur de pénétration le plus court et en l'ajoutant à la position de l'AABB".
  2. N'appliquez pas de gravité là où il y aurait une force normale annulant la force de gravité.
    • Un objet en contact avec un autre objet en dessous est soumis à la force normale. Il s'agit donc de garder une trace de ces objets. (En fait, tous les objets qui sont en contact devraient avoir une force normale appliquée, mais tous n'auront pas un effet net en ce qui concerne la gravité.)
    • Si vous souhaitez ajouter des objets qui peuvent glisser vers le bas d'autres objets qui sont à un angle, vous devrez ajouter la force de friction et la composante x de la force normale.

Je l'ai décrit légèrement différemment dans mon autre réponse qui concerne davantage les collisions en général .

Leftium
la source