Wie implementiere ich ein Bullet Physics CollisionObject, das mein würfelförmiges Gelände darstellt?

8

Ich habe die Bullet Physics-Bibliothek erfolgreich in mein Entitäts- / Komponentensystem integriert. Entitäten können miteinander kollidieren. Jetzt muss ich ihnen ermöglichen, mit dem Gelände zu kollidieren, das endlich und würfelförmig ist (denken Sie an InfiniMiner oder den Klon Minecraft ). Ich habe erst gestern angefangen, die Bullet Physics-Bibliothek zu benutzen, also fehlt mir vielleicht etwas Offensichtliches.

Bisher habe ich die RigidBodyKlasse erweitert, um die checkCollisionWith(CollisionObject co)Funktion zu überschreiben . Im Moment ist es nur eine einfache Überprüfung des Ursprungs, ohne die andere Form zu verwenden. Ich werde das später wiederholen. Im Moment sieht es so aus:

@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;
}

Dies funktioniert hervorragend, um zu erkennen, wann Kollisionen auftreten. Dies behandelt jedoch nicht die Kollisionsreaktion. Es scheint, dass die Standardkollisionsantwort darin besteht, die kollidierenden Objekte außerhalb der jeweils anderen Formen, möglicherweise ihrer AABBs, zu verschieben.

Im Moment ist die Form des Geländes nur eine Kiste von der Größe der Welt. Dies bedeutet, dass die Entitäten, die mit dem Gelände kollidieren, nur außerhalb dieser Weltgröße schießen. Es ist also klar, dass ich entweder die Kollisionsreaktion ändern oder eine Form erstellen muss, die direkt der Form des Geländes entspricht. Welche Option ist die beste und wie implementiere ich sie? Vielleicht gibt es eine Option, an die ich nicht denke?

Es ist zu beachten, dass das Gelände dynamisch ist und vom Spieler häufig geändert wird.

MichaelHouse
quelle

Antworten:

8

Obwohl ich die Antwort von Kevin Reid schätze, war sie höher als meine Frage. Verständlicherweise wäre es ohne Kenntnisse der Bullet Physics schwierig, diese Frage zu beantworten. Ich habe das zum Laufen gebracht und habe eine Antwort, die spezifisch für Bullet Physics ist.

Zusammen mit der Erweiterung der RigidBodyKlasse, wie ich in meiner Frage erwähnt habe. Ich musste auch die CollisionAlgorithmKlasse erweitern. Dies dient hauptsächlich dazu, die processCollision()Funktion zu überschreiben . Innerhalb der processCollision()Funktion (die die beiden kollidierenden Körper als Argumente verwendet) konnte ich eine Würfelform erstellen, die Transformfür den Würfel geeignet ist, mit dem meine Entität gerade kollidiert. Lassen Sie dann einfach die Standardkollision basierend auf der Entität und den spezifischen Würfeln / Würfeln, mit denen sie kollidiert, geschehen. Um die neu erweiterte CollisionAlgorithmVersion verwenden zu können, musste ich den Algorithmus registrieren, um mit den Formen umgehen zu können, mit denen er umgehen soll. In diesem Fall ist das so ziemlich der Geländetyp gegen alles andere. Dafür habe ich registerCollisionCreateFunc()mit meinem verwendet CollisionDispatcher.

Also für diejenigen, die in Zukunft mitmachen:

  1. Erweitern Sie RigidBody, um eine grundlegende Kollisionsprüfung mit Ihrem Gelände durchzuführen.
  2. Erstellen Sie eine Instanz Ihrer RigidBodyKlasse und fügen Sie sie Ihrer DynamicsWorldoder einer anderen von PhysicsProccesorIhnen verwendeten hinzu.
  3. Erweitern Sie diese Option CollisionAlgorithm, processCollision()um Bullet Physics-Formen und -Transformationen zu erstellen, die mit Ihrem Kollisionsort übereinstimmen.
  4. Registrieren Sie Ihre Version von CollisionAlgorithmbei Ihrer CollisionDispatcherVerwendung registerCollisionCreateFunc(). (Diese Registrierung wird mehrmals durchgeführt, einmal für jedes Formpaar, das Sie kollidieren möchten.)

BEARBEITEN

Hier ist ein Video davon in Aktion, wenn jemand interessiert ist.

Erkennen der anfänglichen Kollision

Bei meinen ersten Kollisionsprüfungen rigidBodyüberschreibt meine erweiterte checkCollideWithFunktion die in meiner Frage beschriebene Funktion. Ich habe eine Funktion für mein Gelände, die prüfen kann, ob die Welt an einem bestimmten Punkt fest ist. Grundsätzlich teste ich mein Gelände anhand des Objekts, das von der checkCollideWithFunktion übergeben wird, um festzustellen, ob mein Gelände irgendwo innerhalb der Grenzen dieses Objekts fest ist.

Jetzt gibt es auch den nächsten Schritt in Bullet, die Kontaktpunkte zu finden. Dies geschieht in der processCollision()oben erwähnten Funktion. Hier habe ich eine BoxShape in der Größe eines Geländewürfels erstellt. Wenn ich dann eine Kollision in der checkCollideWithFunktion erkenne, platziere ich die BoxShape in der Größe eines Geländewürfels an der Kollisionsstelle und lasse Bullet alle Standardalgorithmen zum Erkennen von Kollisionspunkten verwenden .

Wenn also die Grenzen eines Physikobjekts festes Material berühren. Ich werde meinen temporären Physikkörper an diesem Ort platzieren und Bullet anweisen, Kollisionen mit diesem temporären Würfel zu überprüfen, als ob er immer da wäre. Dies ist wie eine super Optimierung beim Platzieren einer Boxform für jeden Würfel in meinem Gelände. Anstelle von Millionen von BoxShapes brauche ich nur eine, die sich teleportiert, wenn eine Kollision erkannt wird.

MichaelHouse
quelle
Können Sie näher erläutern, wie Sie Kollisionen überhaupt erkannt haben?
Timoxley
1
@ Timoxley Ich habe die Antwort ein bisschen aktualisiert.
MichaelHouse
Wie würden Sie dann mit einem einzelnen Gegenstand umgehen, der an mehreren Stellen kollidiert, z. B. einer Leiter, die sich auf den Boden und an eine Wand stützt?
Timoxley
Der temporäre Würfel wird an allen Stellen verschoben, an denen ein Objekt das Gelände berührt. Es wird nur für die Feinerkennung verwendet, um Kontaktpunkte zu erhalten und angemessen zu reagieren.
MichaelHouse
3

Ich hatte einige Probleme mit der Strategie, die in meiner anderen Antwort implementiert wurde. Kontaktpunkte blieben manchmal hängen, es war etwas hackig, andere Formen als Würfel zu machen, und es erlaubte manchmal Objekten, durch das Gelände zu rutschen.

Anstatt eine der Bullet-Klassen zu ändern oder zu überschreiben, gibt es eine alternative Option zur Verwendung eines integrierten Bullet-Kollisionsobjekts, das das Gelände darstellt. Das BvhTriangleMeshShape( doc ) ist eine eingebaute Form, die durch ein Dreiecksnetz dargestellt wird.

Dieses Netz kann gleichzeitig mit dem Netz zur Visualisierung der Welt erzeugt werden. Dies bedeutet, dass das Physikobjekt genau mit dem gerenderten Objekt übereinstimmen kann.

Ich erstelle RigidBodyfür jeden Block in meinem Gelände einen. Dieser Körper hat seine Form auf a eingestellt BvhTriangleMeshShape. Wenn das Gelände geändert wird, baue ich gleichzeitig die visuelle Darstellung des Blocks und die physikalische Form neu auf. Wenn es dann an der Zeit ist, die visuelle Form zu puffern, tausche ich auch die physikalischen Formen wie folgt aus:

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

Dies stellt sicher, dass der Körper ordnungsgemäß entfernt wird und die Kontaktpunkte gereinigt werden. Dann wird die Form geändert und erneut hinzugefügt.

Um das zu generieren, BvhTriangleMeshShapemuss jeder Block ein TriangleIndexVertexArray( doc ) pflegen . Dies sind im Wesentlichen zwei Byte-Puffer. Eine mit den Positionen der Dreiecksscheitelpunkte und die andere mit den Indizes zum Konstruieren dieser Dreiecke. Dieses Vertex-Array muss beibehalten werden, da BvhTriangleMeshShapekeine Kopie der Daten erstellt wird.

Die Verwendung aller integrierten Bullet-Physikklassen ist wahrscheinlich schneller als alles, was ich schreiben könnte, und es läuft tatsächlich sehr schnell. Nach der Umsetzung dieser neuen Strategie habe ich keine Verlangsamung festgestellt.

Geben Sie hier die Bildbeschreibung ein

MichaelHouse
quelle
Ich werde jedem, der dies liest, mitteilen, dass JBullet zumindest in meinen Tests SEHR langsam beim Kochen von Maschen ist (dh beim Vorverarbeiten, bevor sie für die Physik verwendet werden können), zumindest im Vergleich zu der Zeit, die ich zum Konvertieren eines Chunks benötige über marschierende Würfel in ein Netz. Wir sprechen um Größenordnungen langsamer. Also werde ich mir PhysX ansehen und sehen, wie viel besser ich es ausführen kann. Wenn jemand Informationen dazu hat, würde ich sie gerne hören.
Philip
2

Ich bin nicht mit Bullet Physics vertraut, aber ich habe ODE verwendet. Dort gibt es nach dem Ja-Nein-Kollisionstest einen detaillierteren Form-Form-Kollisionstest, der eine Reihe von Kontaktpunkten generiert.

In Ihrem Fall ist Ihre Welt eine Sammlung von Kisten, also können Sie dies tun:

  1. Nehmen Sie den AABB der sich bewegenden Entität.
  2. Iterieren Sie über die Geländevoxel in dem Volumen, das sie schneidet.
  3. Konstruieren Sie für jedes feste Voxel des Geländes eine passende Box und berechnen Sie (vorzugsweise unter Verwendung der von der Physik-Engine bereitgestellten Routinen) die Kollision dieser Box mit der sich bewegenden Entität.
  4. Geben Sie die Sammlung aller resultierenden Kontaktpunkte zurück.

Dies ist nicht die Neudefinition Kollisionsantwort ; Dies ist eine Schicht davor. Die Kollisionsantwort wird vollständig durch die aus der Kollision berechneten Kontaktpunkte bestimmt.

Wie gesagt, ich bin mit Bullet Physics nicht vertraut, daher weiß ich nicht, ob die Architektur dafür geeignet ist.

Kevin Reid
quelle
Vielen Dank. Ich würde denken, dass die Kollisionsantwort auch in den Formkollisionstest eingebunden ist. Diese Informationen müssen verwendet werden, um zu entscheiden, wie und wie weit sie auseinander bewegt werden sollen. Ich würde mit der aktuellen Kollisionsreaktion gut zurechtkommen, wenn sie auf die Form meines Geländes reagieren würde.
MichaelHouse
Ja; Ich meinte, dass Sie den Kollisionsantwortalgorithmus nicht neu definieren, sondern die Erzeugung von Kontaktpunkten neu definieren, die die Eingaben für diesen Algorithmus sind.
Kevin Reid