Comment calculer la réponse de collision entre une sphère et un avion?

9

J'essaie de créer un jeu 3D simple et j'ai besoin de contraindre le joueur dans les limites du monde du jeu. Lorsque le joueur touche les côtés du monde, je veux que le vaisseau du joueur rebondisse légèrement.

En effet j'essaie de piéger le joueur dans une boîte, et de l'empêcher de s'échapper par les côtés ...

J'ai réussi à définir les limites du monde du jeu comme une collection d'avions, avec des normales et des distances depuis l'origine. Le joueur a une sphère englobante sphérique et en suivant ce site Web http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php, j'ai réussi à détecter les collisions.

Je ne peux maintenant pas vraiment savoir quoi faire lorsqu'une collision est détectée. Le mieux que je puisse gérer est que le joueur reste coincé dans l'avion, le traverse directement ou rebondisse à plusieurs reprises à un rythme très rapide.

Le bon sens me dit que je dois calculer l'angle réfléchi par rapport à l'avion, en utilisant sa normale et l'appliquer à la vitesse du joueur, mais je pense que je dois d'abord voir si le joueur a traversé l'avion, ce qui est le bit que je ne peux pas faire des exercices.

Piku
la source

Réponses:

4

Vous devrez appliquer une impulsion à votre objet, qui est un changement immédiat de sa vitesse. Dans le monde réel, une force puissante serait appliquée à l'objet sur un pas de temps très court, inversant son accélération et provoquant un changement de sa vitesse. Cependant, puisque nous travaillons dans un monde discret, nous devons tricher un peu pour simuler ce brusque changement de direction. Pour une sphère et un avion, c'est assez simple. La réponse de collision la plus fondamentale consiste à refléter la vitesse de la sphère autour de la normale de l'avion, puis le résultat est la nouvelle vitesse de la sphère. Le pseudo-code ressemblerait à ceci:

reflected = 2 * plane.normal * (plane.normal * sphere.velocity)
sphere.velocity -= reflected

De là, vous pouvez ajouter un peu d'amortissement (multiplier par un certain coefficient, comme 0,9) pour tenir compte de l'énergie perdue par la chaleur ou le frottement. Si vous voulez impliquer la vitesse angulaire (peut-être que votre sphère tourne), alors les équations deviennent un peu plus compliquées.

Pour plus d'informations, je vous renvoie aux articles de Chris Hecker sur la dynamique du corps rigide . Si vous n'avez jamais entendu parler de Chris Hecker auparavant, il est bien connu pour la physique des jeux ainsi que pour son travail sur la génération et l'animation de personnages procéduraux dans Spore.

kevintodisco
la source
4
C'est essentiellement la bonne voie à suivre, mais le calcul du temps d'impact (TOI) peut rendre les choses plus précises à mesure que les cadreurs fluctuent ou chutent. Savoir, en fonction de la vitesse actuelle, depuis combien de temps l'impact s'est produit peut vous aider à calculer un moment d'impact, et en utilisant cela, vous pouvez ramener la sphère à sa position au moment de l'impact et ajuster la vitesse à partir de là. Après avoir ajusté la position et la vitesse à partir du point d'impact, au moment de l'impact, vous vous déplacez ensuite le long de la nouvelle vitesse du temps que vous avez soustrait pour arriver à la TOI.
Nic Foster
D'accord, cela semble fonctionner principalement, mais c'est un peu ... étrange. Je pense que je peux faire cela au mauvais moment dans mon code. Dois-je parcourir tous mes objets et tester s'ils vont entrer en collision avant de les déplacer (en fonction de l'endroit où ils se trouveront dans la prochaine image) ou les déplacer, puis tester les collisions par la suite?
Piku
@Piku, non ne détecte pas s'ils vont entrer en collision. Si une collision se produit, souvenez-vous qu'il y a de très bonnes chances que les deux objets se chevauchent maintenant bien au-delà de l'endroit où la collision réelle aurait eu lieu. Vous devez essentiellement déterminer où la collision s'est produite comme si vous aviez une fréquence d'images infinie (ce que vous n'avez pas) et ramener l'objet à la position où la collision aurait initialement eu lieu. Si vous ne séparez pas les objets comme celui-ci, vous réagirez continuellement à la même collision et l'objet restera coincé.
Jonathan Dickinson
@Piku et pour ce faire, nous avons déterminé le moment dans le passé où la collision s'est produite (appelée TOI / moment de l'impact). Une fois que nous avons cela, nous pouvons utiliser la vitesse de l'objet pour le reculer ( distance = speed * time, généralement avec une distance supplémentaire minuscule pour éviter les erreurs), puis mettre à jour sa vitesse en fonction du résultat de la collision.
Jonathan Dickinson
@Piku aussi, nous ne savons pas où nous serons dans la prochaine image (je n'ai jamais vu cela fait personnellement), mais, généralement, nous faisons la détection et la réponse aux collisions: APRÈS nous calculons la nouvelle position pour CETTE image, mais AVANT nous appliquons la nouvelle position pour CE cadre.
Jonathan Dickinson
1

F = ma, ou a = F / m. Calculez le point de collision entre la sphère et le plan. Il s'agit généralement du centre Sphère - rayon normal *. Si vous voulez plus de précision, calculez jusqu'où la sphère a pénétré le plan et ajustez votre calcul. Bien sûr, cela est largement facultatif, sauf si vous voulez une physique vraiment précise. Maintenant, calculez la vitesse relative le long de la normale. Pour un plan statique, c'est: Vball Dot N. Puis multipliez VballDotN par -1, et multipliez par masse. En physique, à ce stade, vous multiplieriez également cela par le coefficient de restitution (facteur de rebond). Multipliez ce scalaire par N et vous avez votre force.

Lorsque vous ajustez Vball, divisez à nouveau la force en masse et vous avez l'accélération finale, il suffit donc d'ajouter cela à la vitesse et vous avez votre vitesse finale post-collision.

vec3 Vrel = Ball.getVelocity();
float vDotN = Vrel.Dot(CollisionNormal);
vec3 F = -(1.0f+Ball.getRestitution())*vDotN;
F*=Ball.getMass();
Ball.accelerate(F/Ball.getMass());

Cette méthode est précise pour les formules de réponse aux collisions. Si vous voulez encore plus de précision, vous devrez tenir compte du frottement, ce qui fera tourner la balle, mais je ne sais pas si vous le souhaitez dans votre jeu. Dans le cas contraire, voici comment vous calculez la force tangentielle:

vec3 Ft = -(Ball.getvelocity()+(vDotN*CollisionNormal));
Ft*=Ball.getKineticFriction()+Wall.getKineticFriction(); //you could fudge these numbers
Ft*=Ball.getMass();
vec3 vec2Centre = Ball.getPosition()-ContactPoint;
vec3 Torque = cross(vec2Centre,Ft);
Ball.AngularAccelerate(Torque/Ball.getMomentofInertia(glm::normalize(Torque)));

Assurez-vous de calculer Ft avant d'appliquer des effets linéaires, sinon le frottement ne sera pas précis.

Ian Young
la source
La ligne 3 ne devrait-elle pas être vec3 F = -CollisionNormal * (1.0f+Ball.getRestitution())*vDotN;:?
Shital Shah
En effet oui, j'ai raté cette partie. Merci de l'avoir signalé.
Ian Young
0

Je suggérerais de vous calculer d'abord la distance de l'avion; puis lorsque la distance <= au rayon effectue la réaction de collision.

Vous pouvez ensuite modifier cela pour calculer la distance et si la distance est inférieure à ce rayon (ce qui signifie que l'objet se chevauche), déplacez la position des billes puis effectuez la réaction de collision.

Ciel rouge
la source