Comment puis-je implémenter un Bullet Physics CollisionObject qui représente mon cube comme un terrain?

8

J'ai réussi à intégrer la bibliothèque Bullet Physics dans mon système d'entités / composants. Les entités peuvent entrer en collision les unes avec les autres. Maintenant, je dois leur permettre d'entrer en collision avec le terrain, qui est fini et semblable à un cube (pensez à InfiniMiner ou à son clone Minecraft ). J'ai commencé à utiliser la bibliothèque Bullet Physics hier seulement, alors peut-être que je manque quelque chose d'évident.

Jusqu'à présent, j'ai étendu la RigidBodyclasse pour remplacer la checkCollisionWith(CollisionObject co)fonction. Pour le moment, ce n'est qu'une simple vérification de l'origine, sans utiliser l'autre forme. Je répéterai cela plus tard. Pour l'instant, cela ressemble à ceci:

@Override
public boolean checkCollideWith(CollisionObject co) {
    Transform t = new Transform();
    co.getWorldTransform(t);
    if(COLONY.SolidAtPoint(t.origin.x, t.origin.y,t.origin.z)){
        return true;
    }
    return false;
}

Cela fonctionne très bien, en ce qui concerne la détection des collisions. Cependant, cela ne gère pas la réponse de collision. Il semble que la réponse de collision par défaut consiste à déplacer les objets en collision en dehors des formes les uns des autres, éventuellement leurs AABB.

Pour le moment, la forme du terrain n'est qu'une boîte de la taille du monde. Cela signifie que les entités qui entrent en collision avec le terrain tirent juste à l'extérieur de cette zone de taille mondiale. Il est donc clair que je dois soit modifier la réponse à la collision, soit créer une forme qui s'adapte directement à la forme du terrain. Alors, quelle option est la meilleure et comment procéder pour la mettre en œuvre? Peut-être y a-t-il une option à laquelle je ne pense pas?

Il est à noter que le terrain est dynamique et fréquemment modifié par le joueur.

MichaelHouse
la source

Réponses:

8

Bien que j'apprécie la réponse de Kevin Reid, c'était à un niveau supérieur à ce que ma question demandait. Naturellement, sans connaissance de la physique des balles, il serait difficile de répondre à cette question. Je l'ai fait fonctionner et j'ai une réponse spécifique à la physique des balles.

Parallèlement à l'extension de la RigidBodyclasse comme je l'ai mentionné dans ma question. J'avais aussi besoin d'étendre la CollisionAlgorithmclasse. C'est principalement pour remplacer la processCollision()fonction. À l'intérieur de la processCollision()fonction (qui prend les deux corps en collision comme arguments), j'ai pu créer une forme de cube et appropriée Transformpour le cube avec lequel mon entité était actuellement en collision. Ensuite, laissez simplement la collision par défaut se produire en fonction de l'entité et du ou des cubes spécifiques avec lesquels elle entre en collision. Afin d'utiliser la nouvelle extension CollisionAlgorithm, j'avais besoin d'enregistrer l'algorithme pour gérer les formes que je veux qu'il gère. Dans ce cas, c'est à peu près le type de terrain contre tout le reste. Pour cela, je l'ai utilisé registerCollisionCreateFunc()avec mon CollisionDispatcher.

Donc pour ceux qui suivront à l'avenir:

  1. Prolongez RigidBodypour avoir un contrôle de collision de base avec votre terrain.
  2. Créez une instance de votre RigidBodyclasse et ajoutez-la à votre DynamicsWorldou à tout PhysicsProccesorce que vous utilisez.
  3. Étendez-vous CollisionAlgorithm, spécifiquement processCollision()pour créer des formes et des transformations de physique de balle qui correspondent à votre emplacement de collision.
  4. Enregistrez votre version de CollisionAlgorithmavec votre CollisionDispatcherutilisation registerCollisionCreateFunc(). (Cet enregistrement est effectué plusieurs fois, une fois pour chaque paire de formes que vous souhaitez heurter.)

ÉDITER

Voici une vidéo de celui-ci en action si quelqu'un est intéressé.

Détection de la collision initiale

Pour mes vérifications de collision initiales, mon extension rigidBodyremplace la checkCollideWithfonction décrite dans ma question. J'ai une fonction pour mon terrain qui peut vérifier si le monde est solide à un point spécifique. Fondamentalement, je teste mon terrain contre l'objet passant par la checkCollideWithfonction, pour voir si mon terrain est solide n'importe où dans les limites de cet objet.

Maintenant, il y a aussi la prochaine étape dans Bullet, trouver les points de contact. Cela se produit dans la processCollision()fonction que j'ai mentionnée ci-dessus. Ici, j'ai créé un boxShape de la taille d'un cube de terrain, puis lorsque je détecte une collision dans la checkCollideWithfonction, je place ce boxShape de la taille d'un cube de terrain à l'emplacement de la collision et laisse Bullet utiliser tous ses algorithmes par défaut pour détecter les points de collision là-bas .

Donc, fondamentalement, si les limites d'un objet physique touchent un matériau solide. Je vais placer mon corps physique temporaire à cet endroit et dire à Bullet de vérifier les collisions avec ce cube temporaire, comme s'il était toujours là. C'est un peu comme une super optimisation en plaçant une forme de boîte pour chaque cube de mon terrain. Au lieu de millions de boxShapes, je n'en ai besoin que d'un qui se téléporte quand une collision est détectée.

MichaelHouse
la source
Pouvez-vous développer davantage sur la façon dont vous avez détecté les collisions en premier lieu?
timoxley
1
@timoxley J'ai un peu mis à jour la réponse.
MichaelHouse
Comment manipuleriez-vous alors un seul élément qui entre en collision en plusieurs points, par exemple une échelle appuyée au sol et contre un mur?
timoxley
Le cube temporaire est déplacé pour tous les endroits où un objet entre en contact avec le terrain. Il est juste utilisé pour la détection fine pour obtenir des points de contact et répondre de manière appropriée.
MichaelHouse
3

J'avais des problèmes avec la stratégie mise en œuvre dans mon autre réponse. Les points de contact restaient parfois autour, c'était une sorte de hacky de faire des formes autres que des cubes et cela permettait parfois aux objets de glisser à travers le terrain.

Ainsi, au lieu de modifier ou de remplacer l'une des classes Bullet, il existe une option alternative d'utiliser un objet de collision Bullet intégré qui représentera le terrain. Le BvhTriangleMeshShape( doc ) est une forme intégrée qui est représentée par un maillage triangulaire.

Ce maillage peut être généré en même temps que le maillage pour visualiser le monde. Cela signifie que l'objet physique peut correspondre exactement à l'objet rendu.

Je crée un RigidBodypour chaque morceau de mon terrain. Ce corps a sa forme définie sur a BvhTriangleMeshShape. Lorsque le terrain est modifié, en même temps je reconstruis la représentation visuelle du morceau, je reconstruis également la forme physique. Ensuite, quand vient le temps de tamponner la forme visuelle, j'échange également les formes physiques comme ceci:

dynamicsWorld.removeRigidBody(chunk.getRigidBody());
chunk.getRigidBody().setCollisionShape(newShape);
dynamicsWorld.addRigidBody(chunk.getRigidBody());

Cela garantit que le corps est correctement retiré, nettoyant les points de contact. Ensuite, sa forme est modifiée et elle est rajoutée.

Afin de générer le BvhTriangleMeshShapechaque morceau doit maintenir un TriangleIndexVertexArray( doc ). Il s'agit essentiellement de tampons à deux octets. L'un avec les positions des sommets des triangles et l'autre avec les indices de construction de ces triangles. Ce tableau de sommets doit être conservé car BvhTriangleMeshShapene fait pas de copie des données.

Utiliser toutes les classes de physique Bullet intégrées est probablement plus rapide que tout ce que je pourrais écrire, et cela fonctionne en effet très rapidement. Je n'ai vu aucun ralentissement après la mise en œuvre de cette nouvelle stratégie.

entrez la description de l'image ici

MichaelHouse
la source
Je noterai à tous ceux qui liront que, au moins dans mes tests, JBullet est TRÈS lent à cuire les mailles (c'est-à-dire à les prétraiter avant de les utiliser pour la physique), au moins par rapport au temps qu'il me faut pour convertir un morceau dans un maillage via des cubes de marche. Nous parlons des ordres de grandeur plus lentement. Je vais donc examiner PhysX et voir à quel point je peux améliorer ses performances. Si quelqu'un a des informations à ce sujet, je serais ravi de les entendre.
Philip Guin
2

Je ne connais pas Bullet Physics, mais j'ai utilisé ODE. Là, après le test de collision oui ou non, il y a un test de collision forme-forme plus détaillé qui génère un ensemble de points de contact.

Dans votre cas, votre monde est une collection de boîtes, vous pouvez donc faire ceci:

  1. Prenez l'AABB de l'entité en mouvement.
  2. Itérer sur les voxels de terrain dans le volume qui l'intersecte.
  3. Pour chaque voxel du terrain qui est solide, construisez une boîte correspondante et calculez (de préférence en utilisant les routines fournies par le moteur physique) la collision de cette boîte avec l'entité en mouvement.
  4. Renvoyez la collection de tous les points de contact résultants.

Cela ne redéfinit pas la réponse à la collision ; c'est une couche avant ça. La réponse à la collision est entièrement déterminée par les points de contact calculés à partir de la collision.

Comme je l'ai dit, je ne connais pas la physique des puces, donc je ne sais pas si son architecture s'y prête.

Kevin Reid
la source
Merci. Je pense que la réponse à la collision est également liée au test de collision de formes. Il doit utiliser ces informations pour décider de quelle manière les séparer et jusqu'où les séparer? Je serais d'accord avec la réponse de collision actuelle si elle répondait à la forme de mon terrain.
MichaelHouse
Oui; Je voulais dire que vous ne redéfinissez pas l'algorithme de réponse aux collisions, mais redéfinissez plutôt la génération de points de contact qui sont les entrées de cet algorithme.
Kevin Reid