Dans un moteur de physique 2D, comment éviter les résolutions de collisions inutiles lorsque les objets s'arrêtent?

9

Dans un moteur physique que je développe (pour apprendre) en utilisant love-2d , j'ai implémenté des résolutions de collision de cette manière:

FixedUpdate(dt)  // I use fixed timestep
 foreach collide c1 in allNotStaticColliders
   c1.integartePhysic // i.e. apply gravitational force..
   foreach collider c2 "near" c1 // "near"= I use spatial hashing 
      if collide(c1,c2)
        resolve collision (c1,c2)  // the heavy operation
        collison callbacks c1
        collison callbacks c2
        ...

animation d'objets tombant et s'arrêtant

Comme vous pouvez le voir à la fin de l'animation gif, il y a une décroissance FPS lorsque tous les collisionneurs sont presque mis à la terre sur un objet statique.

l'état statique final, avec 2 FPS

En effet, le nombre de résolutions de collision augmente à mesure que les objets passent plus de temps à se toucher lorsqu'ils s'installent. Cependant, de nombreux calculs sont "inutiles" car les objets se sont déjà installés dans des positions stables les uns contre les autres.

Quelle est la meilleure pratique (si tout va bien n'exige pas un diplôme de physique) pour éviter ces détections de collision "inutiles"?

Edit: astuces DMGregory acceptées et arriver à ce résultat (pas encore optimal)

entrez la description de l'image ici

(Rouge = statique, Bleu = actif, Vert = endormi)

dnk drone.vs.drones
la source
1
L'approche habituelle consiste à «dormir» les objets qui se reposent, et ne pas considérer les interactions entre les objets dormants / statiques (mais un objet dormant peut toujours être réveillé par une interaction d'un objet dynamique qui est toujours éveillé et en mouvement). Malheureusement, cela n'aide qu'une fois qu'un objet est complètement au repos. Si je lis votre exemple correctement, il semble que vos problèmes de performances commencent lorsque les objets se stabilisent et se déplacent encore légèrement. Tout ce que je peux penser ici, c'est ajouter plus de friction / amortissement au système (éventuellement avec un seuil de vitesse) afin que les petits mouvements se désintègrent pour se reposer plus rapidement.
DMGregory
@DMGregory Cela ressemble à une bonne réponse. Ajoutez-le?
Anko

Réponses:

9

Je soupçonnais que OP connaissait déjà cette approche, je l'ai donc mentionnée dans un commentaire comme point de départ, mais je vais essayer de l'étoffer un peu plus ...

La plupart des moteurs physiques divisent les objets dynamiques en deux groupes, « éveillé » et « endormi ».

Les objets dorment lorsqu'ils sont assis au repos et se réveillent lorsqu'ils sont déplacés ou accélérés par une influence extérieure.

Un objet endormi se comporte comme un objet statique à bien des égards - son mouvement n'est pas intégré dans le temps (car il est au repos, il n'a donc aucun mouvement) et le moteur ignore les collisions entre des objets endormis ou statiques.

Un objet endormi assis sur un sol statique ne tombe pas à travers lui, malgré l'absence de réponse à la collision, car toute intégration de mouvement est ignorée pour les objets endormis, y compris la gravité.

Ainsi, seules les collisions impliquant au moins un objet dynamique éveillé doivent être vérifiées:

Collisions    Static          Sleeping           Awake
          ------------------------------------------------
Awake     |    Check        Check & Wake         Check
Sleeping  |     No               No
Static    |     No

Cela peut réduire considérablement le nombre d'objets qui nécessitent une simulation active, en particulier dans les piles qui, comme illustré dans la question, ont beaucoup de collisions mutuelles pour vérifier peu ou pas de mouvement net.

Dormir n'aide que lorsque les objets atteignent effectivement le repos, ce qui peut prendre un certain temps.

Certaines choses que vous pouvez faire pour vous reposer plus tôt:

  • Ayez une vitesse ou un élan minimum non nul et fixez à zéro tout ce qui tombe en dessous. (Il s'agit essentiellement d'un epsilon, couramment utilisé pour comparer les flotteurs)

  • Utilisez la friction, l'amortissement et les collisions inélastiques pour retirer l'énergie du système et l'aider à se reposer plus rapidement dans l'ensemble.

  • Augmentez la friction / l'amortissement / l'inélasticité de manière sélective pour les objets se déplaçant lentement pour leur donner ce dernier coup de pouce pour se reposer, sans affecter le comportement des corps plus énergétiques.

DMGregory
la source
Bonne réponse. Vous signalez un tas de bonnes idées. Pour les contrôles sommeil / éveillé, je vois 2 points faibles: 1) si l'objet endormi o1 sous l'objet endormi o2 se réveille en s'éloignant de o2, il ne réveille pas o2; 2) si je supprime une plate-forme statique sous un objet endormi, cet objet ne se réveille pas (sous la force de la gravitation)
dnk drone.vs.drones
1
@ dnkdrone.vs.drones Bonnes observations. N'ayant jamais écrit moi-même un moteur physique, je ne sais pas comment cela est normalement géré. Une possibilité est, lorsque nous mettons un objet en veille, nous stockons une liste des objets qu'il touche (ou l'ajoutons à un cluster local d'objets). Lorsque nous réveillons un objet endormi, nous réveillons également tout dans sa liste / cluster. Il peut y avoir des options plus élégantes, comme vérifier les contacts à proximité au moment du réveil (avant qu'il ne s'éloigne).
DMGregory