2012-06-24 3 views
7

Ich versuche Bullet Physics nur für die Kollisionserkennung zu verwenden. Ich brauche es nicht, um irgendwelche Objekte für mich zu bewegen oder Renderings mit Callbacks durchzuführen. Ich möchte nur Objektpositionen jedes Bild aktualisieren und es verwenden, um mir zu sagen, wenn ich Kollisionen habe. Um das einfachste Beispiel zu bekommen, versuche ich Kollisionen zwischen Objekten mit btBoxShape als Form zu finden. Alles läuft gut ohne Abstürze oder offensichtliche Speicherlecks, aber ich bekomme keine Kollisionen, also muss ich irgendwo Fehler machen. Ich werde versuchen, das so kurz wie möglich zu halten, ohne etwas Wichtiges auszulassen.Bullet Physik Simplest Collision Beispiel

Hier ist meine Welt Setup-Funktion:

collisionConfig  = new btDefaultCollisionConfiguration(); 
dispatcher   = new btCollisionDispatcher(collisionConfig); 
overlappingPairCache = new btDbvtBroadphase(); 
solver    = new btSequentialImpulseConstraintSolver; 
dynamicsWorld  = new btDiscreteDynamicsWorld(dispatcher, 
overlappingPairCache, solver, collisionConfig);   

dynamicsWorld->setGravity(btVector3(0.0f, -9.8f, 0.0f)); 

Im Moment habe ich Spieler und Feind Objekte vom Typ btCollisionObject *. Ich richte sie so ein:

mPlayerBox = new btBoxShape(btVector3(1,3,1)); 
mPlayerObject = new btCollisionObject(); 
mPlayerObject->setCollisionShape(mPlayerBox); 
btTransform playerWorld; 
playerWorld.setIdentity(); 
//playerPos is a D3DXVECTOR3 that holds the camera position. 
playerWorld.setOrigin(btVector3(playerPos.x, playerPos.y, playerPos.z)); 
mPlayerObject->setWorldTransform(playerWorld); 
mPlayerObject->forceActivationState(DISABLE_DEACTIVATION);//maybe not needed 
dynamicsWorld->addCollisionObject(mPlayerObject); 

Ich mache im Wesentlichen die gleiche Sache mit meinen Feindobjekten.

Dann jeder Frame ich alle meine Objekte mit so etwas wie dies aktualisieren:

btTransform updatedWorld; 
updatedWorld.setIdentity(); 
updatedWorld.setOrigin(btVector3(position.x, position.y, position.z)); 
mPlayerObject->setWorldTransform(updatedWorld); 

//do the same for my enemies, and then... 

dynamicsWorld->performDiscreteCollisionDetection(); 
//Also tried doing this with stepSimulation(deltaTime, 7), but nothing changed. 
//stepSimulation seems to only be for letting Bullet set world Transforms? 

//check collisions with player 
dynamicsWorld->contactTest(mPlayerObject, resultCallback); 
int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds(); 
if(numManifolds > 0) 
{ 
    //there's a collision, execute blah blah blah 
} 

Und schließlich ist hier die Struktur, die mein Ergebnis Rückruf definiert:

struct rCallBack : public btCollisionWorld::ContactResultCallback 
{ 
btScalar rCallback::addSingleResult(btManifoldPoint& cp, const btCollisionObject* 
colObj0, int partId0, int index0, const btCollisionObject* colObj1, int partId1, 
int index1) 
{ 
    btVector3 ptA = cp.getPositionWorldOnA(); 
    btVector3 ptB = cp.getPositionWorldOnB(); 
    return 0; 
} 
} 

ich viel haben gesucht von den Demos, aber sie scheinen die Bewegung meistens auf Bullet zu belassen, und da ich Charaktere mit einer festgelegten Geschwindigkeit ohne spezielle Physik bewegte, wenn sie kollidierten, hatte ich Probleme, die Beispiele in meine Anwendung zu übernehmen. Das Ergebnis Callback kam tatsächlich von diesem Beitrag in den Foren: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6816 Es geht um Dreiecksnetze, aber es schien am nächsten zu dem, was ich versuchte zu implementieren.

Wie auch immer, wenn Sie so weit lesen, danke !! Jeder Rat oder Links, die Sie frei hätten, wäre sehr willkommen.

+3

"Ich möchte nur Objektpositionen jeden Rahmen aktualisieren und es verwenden, um mir zu sagen, wenn ich Kollisionen habe." Das steht im Gegensatz zu dem System * physics *. Sie sollten versuchen, mit Ihrer Physik-Engine zu arbeiten, nicht * dagegen *. Wenn Sie Charaktere haben, die sich mit einer bestimmten Geschwindigkeit bewegen, sollten Sie Ihr Physiksystem wirklich bewegen lassen. Das kann es gut. –

+0

Ja, ich wünschte, ich könnte dies als Antwort markieren. Nachdem ich das gelesen und ein wenig mehr darüber gelesen hatte, wurde mir klar, dass ich die Kollisionserkennung selbst mit Hilfe von Volumen und Mathe machen kann. Vielen Dank! – Aztal

+0

Was ist die Eingabe und Ausgabe? ZB: für jeden Frame Input = Position + Geschwindigkeit (pro Step) aller Objekte Output = welche Objektpaare kollidierten an welcher Stelle im Raum? Und Sie aktualisieren Positionen/Geschwindigkeiten manuell mit einer benutzerdefinierten Methode? –

Antwort

4

Ich schreibe eine IOS-App mit Flighter schießen auf 3D-Szene. Ich benutze bullet Physik für die Kollisionserkennung Ich setze den flighter als kinematisches Objekt, meine Logik verschiebe den flighter und update dann die btMotionState worldTransform des kinematischen Objekts. Ich habe auch keine Kollisionserkennung, bis ich die beide folgenden Anweisungen ändern (die Maskierung und die dieselbe Gruppe sowohl für den Spieler und Feind)

dynamicsWorld->addRigidBody(mPlayerObject,1,1); 
dynamicsWorld->addRigidBody(mEnemyObject,1,1); 
... 
dynamicsWorld->setInternalTickCallback(myTickCallback); 

dann kann ich das sehen

void myTickCallback(btDynamicsWorld *world, btScalar timeStep) { 
    int numManifolds = world->getDispatcher()->getNumManifolds(); 
    printf("numManifolds = %d\n",numManifolds); 
} 

numManifolds Wert wird 1, wenn Objekt kollidiert.

1

Sie können die Kontaktinformationen überprüfen, wie here erklärt:

Kontaktdaten

Der beste Weg, um zu bestimmen, ob Kollisionen zwischen bestehenden Objekte in der Welt passiert, ist jeden Kontakt iterieren Mannigfaltigkeiten. Diese sollte während eines Simulationsticks (Teilschritt) Callback durchgeführt werden, da Kontakte während mehrerer Teilschritte eines Einzelschrittstimulationsaufruf hinzugefügt und entfernt werden können.Ein Kontaktverteiler ist ein Cache, der alle Kontaktpunkte zwischen Paaren von Kollisionsobjekten enthält. Eine gute Art und Weise ist es, alle Paare von Objekten in der gesamten Kollision/Dynamik Welt iterieren:

//Assume world->stepSimulation or world->performDiscreteCollisionDetection has been called 

    int numManifolds = world->getDispatcher()->getNumManifolds(); 
    for (int i=0;i<numManifolds;i++) 
    { 
     btPersistentManifold* contactManifold = world->getDispatcher()->getManifoldByIndexInternal(i); 
     btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0()); 
     btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1()); 

     int numContacts = contactManifold->getNumContacts(); 
     for (int j=0;j<numContacts;j++) 
     { 
      btManifoldPoint& pt = contactManifold->getContactPoint(j); 
      if (pt.getDistance()<0.f) 
      { 
       const btVector3& ptA = pt.getPositionWorldOnA(); 
       const btVector3& ptB = pt.getPositionWorldOnB(); 
       const btVector3& normalOnB = pt.m_normalWorldOnB; 
      } 
     } 
    } 

Sie in btGhostObject interessiert sein, die Spur seiner eigenen überlappende Paare hält.

0

Minimal runnable Beispiel

Eine Kugel fällt und den Boden zu schlagen.

Kollisionen werden erkannt und auf stdout gedruckt.

Gnuplot Visualisierung:

Die "Kollision" line geht zu 1, wenn die Kugel den Boden berührt.

Und für kleinere Restitutionskoeffizienten (0.5 und 0.5):

Hier wird der Ball nicht mehr springen kontinuierlich den Boden vollständig und berührt.

Code:

#include <cstdio> 
#include <cstdlib> 
#include <vector> 

#include <btBulletDynamicsCommon.h> 

#define PRINTF_FLOAT "%7.3f" 

constexpr float gravity = -10.0f; 
constexpr float initialY = 10.0f; 
constexpr float timeStep = 1.0f/60.0f; 
// TODO some combinations of coefficients smaller than 1.0 
// make the ball go up higher/not lose height. Why? 
constexpr float groundRestitution = 0.9f; 
constexpr float sphereRestitution = 0.9f; 
constexpr int maxNPoints = 500; 

std::vector<btVector3> collisions; 
void myTickCallback(btDynamicsWorld *dynamicsWorld, btScalar timeStep) { 
    collisions.clear(); 
    int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds(); 
    for (int i = 0; i < numManifolds; i++) { 
     btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i); 
     // TODO those are unused. What can be done with them? 
     // I think they are the same objects as those in the main loop 
     // dynamicsWorld->getCollisionObjectArray() and we could compare 
     // the pointers to see which object collided with which. 
     { 
      const btCollisionObject *objA = contactManifold->getBody0(); 
      const btCollisionObject *objB = contactManifold->getBody1(); 
     } 
     int numContacts = contactManifold->getNumContacts(); 
     for (int j = 0; j < numContacts; j++) { 
      btManifoldPoint& pt = contactManifold->getContactPoint(j); 
      const btVector3& ptA = pt.getPositionWorldOnA(); 
      const btVector3& ptB = pt.getPositionWorldOnB(); 
      const btVector3& normalOnB = pt.m_normalWorldOnB; 
      collisions.push_back(ptA); 
      collisions.push_back(ptB); 
      collisions.push_back(normalOnB); 
     } 
    } 
} 

int main() { 
    int i, j; 

    btDefaultCollisionConfiguration *collisionConfiguration 
      = new btDefaultCollisionConfiguration(); 
    btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration); 
    btBroadphaseInterface *overlappingPairCache = new btDbvtBroadphase(); 
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver; 
    btDiscreteDynamicsWorld *dynamicsWorld = new btDiscreteDynamicsWorld(
      dispatcher, overlappingPairCache, solver, collisionConfiguration); 
    dynamicsWorld->setGravity(btVector3(0, gravity, 0)); 
    dynamicsWorld->setInternalTickCallback(myTickCallback); 
    btAlignedObjectArray<btCollisionShape*> collisionShapes; 

    // Ground. 
    { 
     btTransform groundTransform; 
     groundTransform.setIdentity(); 
     groundTransform.setOrigin(btVector3(0, 0, 0)); 
     btCollisionShape* groundShape; 
#if 1 
     // x/z plane at y = -1. 
     groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), -1); 
#else 
     // A cube of width 10 at y = -6. 
     // Does not fall because we won't call: 
     // colShape->calculateLocalInertia 
     // TODO: remove this from this example into a collision shape example. 
     groundTransform.setOrigin(btVector3(0, -6, 0)); 
     groundShape = new btBoxShape(
       btVector3(btScalar(5.0), btScalar(5.0), btScalar(5.0))); 

#endif 
     collisionShapes.push_back(groundShape); 
     btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); 
     btRigidBody::btRigidBodyConstructionInfo rbInfo(0, myMotionState, groundShape, btVector3(0, 0, 0)); 
     btRigidBody* body = new btRigidBody(rbInfo); 
     body->setRestitution(groundRestitution); 
     dynamicsWorld->addRigidBody(body); 
    } 

    // Sphere. 
    { 
     btCollisionShape* colShape = new btSphereShape(btScalar(1.0)); 
     collisionShapes.push_back(colShape); 
     btTransform startTransform; 
     startTransform.setIdentity(); 
     startTransform.setOrigin(btVector3(0, initialY, 0)); 
     btVector3 localInertia(0, 0, 0); 
     btScalar mass(1.0f); 
     colShape->calculateLocalInertia(mass, localInertia); 
     btDefaultMotionState *myMotionState = new btDefaultMotionState(startTransform); 
     btRigidBody *body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
       mass, myMotionState, colShape, localInertia)); 
     body->setRestitution(sphereRestitution); 
     dynamicsWorld->addRigidBody(body); 
    } 

    // Main loop. 
    std::printf("step body x y z collision a b normal\n"); 
    for (i = 0; i < maxNPoints; ++i) { 
     dynamicsWorld->stepSimulation(timeStep); 
     for (j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; --j) { 
      btCollisionObject *obj = dynamicsWorld->getCollisionObjectArray()[j]; 
      btRigidBody *body = btRigidBody::upcast(obj); 
      btTransform trans; 
      if (body && body->getMotionState()) { 
       body->getMotionState()->getWorldTransform(trans); 
      } else { 
       trans = obj->getWorldTransform(); 
      } 
      btVector3 origin = trans.getOrigin(); 
      std::printf("%d %d " PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ", 
        i, 
        j, 
        float(origin.getX()), 
        float(origin.getY()), 
        float(origin.getZ())); 
      if (collisions.empty()) { 
       std::printf("0 "); 
      } else { 
       std::printf("1 "); 
       // Yes, this is getting reprinted for all bodies when collisions happen. 
       // It's just a quick and dirty way to visualize it, should be outside 
       // of this loop normally. 
       for (auto& v : collisions) { 
        std::printf(
          PRINTF_FLOAT " " PRINTF_FLOAT " " PRINTF_FLOAT " ", 
          v.getX(), v.getY(), v.getZ()); 
       } 
      } 
      puts(""); 
     } 
    } 

    // Cleanup. 
    for (i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; --i) { 
     btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i]; 
     btRigidBody* body = btRigidBody::upcast(obj); 
     if (body && body->getMotionState()) { 
      delete body->getMotionState(); 
     } 
     dynamicsWorld->removeCollisionObject(obj); 
     delete obj; 
    } 
    for (i = 0; i < collisionShapes.size(); ++i) { 
     delete collisionShapes[i]; 
    } 
    delete dynamicsWorld; 
    delete solver; 
    delete overlappingPairCache; 
    delete dispatcher; 
    delete collisionConfiguration; 
    collisionShapes.clear(); 
} 

Basierend auf: http://www.bulletphysics.org/mediawiki-1.5.8/index.php

Version dieses auf Scheidungs ​​konzentriert, welches Objekt berührt, welches Objekt: https://gamedev.stackexchange.com/a/120881/25171

Upstream GitHub: https://github.com/cirosantilli/cpp-cheat/blob/503a3b6487ccb75334798839b5ed912270446d14/bullet/ground_ball.cpp

auf Einschuss Getestet 2,83 , Ubuntu 15.10.