Bagaimana cara menerapkan Bullet Physics CollisionObject yang mewakili kubus seperti medan saya?

8

Saya telah berhasil mengintegrasikan perpustakaan Bullet Physics ke sistem entitas / komponen saya. Entitas dapat saling bertabrakan. Sekarang saya harus memungkinkan mereka untuk bertabrakan dengan medan, yang terbatas dan seperti kubus (pikirkan InfiniMiner atau tiruannya Minecraft ). Saya hanya mulai menggunakan perpustakaan Bullet Physics kemarin, jadi mungkin saya kehilangan sesuatu yang jelas.

Sejauh ini saya telah memperluas RigidBodykelas untuk menimpa checkCollisionWith(CollisionObject co)fungsi. Saat ini hanya pemeriksaan asal sederhana, tidak menggunakan bentuk lainnya. Saya akan mengulanginya nanti. Untuk saat ini terlihat seperti ini:

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

Ini berfungsi dengan baik, sejauh mendeteksi ketika tabrakan terjadi. Namun, ini tidak menangani respons tabrakan. Tampaknya respons tumbukan default adalah memindahkan objek bertabrakan di luar bentuk masing-masing, mungkin AABBs mereka.

Saat ini bentuk medan hanyalah kotak seukuran dunia. Ini berarti entitas yang bertabrakan dengan medan hanya menembak ke luar kotak ukuran dunia. Jadi jelas bahwa saya harus memodifikasi respons tumbukan atau saya perlu membuat bentuk yang sesuai langsung dengan bentuk medan. Jadi opsi mana yang terbaik dan bagaimana cara mengimplementasikannya? Mungkin ada opsi yang tidak saya pikirkan?

Perlu dicatat bahwa medannya dinamis dan sering dimodifikasi oleh pemain.

MichaelHouse
sumber

Jawaban:

8

Sementara saya menghargai jawaban Kevin Reid, itu pada tingkat yang lebih tinggi dari apa yang saya tanyakan. Maklum tanpa sepengetahuan Bullet Physics, akan sulit untuk menjawab pertanyaan ini. Saya mendapatkan ini bekerja dan punya jawaban yang khusus untuk Fisika Bullet.

Bersamaan dengan memperluas RigidBodykelas seperti yang saya sebutkan dalam pertanyaan saya. Saya juga perlu memperpanjang CollisionAlgorithmkelas. Ini sebagian besar untuk mengesampingkan processCollision()fungsi. Di dalam processCollision()fungsi (yang mengambil dua tubuh yang bertabrakan sebagai argumen), saya dapat membuat bentuk kubus dan sesuai Transformuntuk kubus yang saat ini sedang bertabrakan dengan entitas saya. Kemudian biarkan tabrakan default terjadi berdasarkan entitas dan kubus / kubus tertentu yang bertabrakan dengannya. Untuk menggunakan yang baru diperluas CollisionAlgorithm, saya perlu mendaftarkan algoritma untuk menangani bentuk yang ingin saya tangani. Dalam hal ini, itu jenis medan yang paling banyak melawan yang lainnya. Untuk itu saya gunakan registerCollisionCreateFunc()dengan saya CollisionDispatcher.

Jadi bagi mereka yang mengikuti di masa depan:

  1. Perluas RigidBodyuntuk melakukan pemeriksaan tabrakan dasar dengan medan Anda.
  2. Buat instance RigidBodykelas Anda dan tambahkan ke Anda DynamicsWorldatau apa pun yang PhysicsProccesorAnda gunakan.
  3. Perluas CollisionAlgorithm, khusus processCollision()untuk membuat bentuk dan Transformasi Fisika Bullet yang cocok dengan lokasi tumbukan Anda.
  4. Daftarkan versi CollisionAlgorithmAnda dengan CollisionDispatchermenggunakan Anda registerCollisionCreateFunc(). (Registrasi ini dilakukan beberapa kali, satu kali untuk setiap pasangan bentuk yang ingin Anda tabrak.)

EDIT

Berikut video dari video tersebut jika ada yang tertarik.

Mendeteksi tabrakan awal

Untuk pemeriksaan tabrakan awal saya, perpanjangan saya rigidBodymenimpa checkCollideWithfungsi yang dijelaskan dalam pertanyaan saya. Saya memiliki fungsi untuk medan saya yang dapat memeriksa apakah dunia solid pada titik tertentu. Pada dasarnya, saya menguji medan saya terhadap objek yang dilewati oleh checkCollideWithfungsi, melihat apakah medan saya solid di mana saja di dalam batas objek itu.

Sekarang, ada juga langkah selanjutnya di Bullet, menemukan titik kontak. Ini terjadi pada processCollision()fungsi yang saya sebutkan di atas. Di sini, saya telah membuat kotakBentuk ukuran kubus medan, lalu ketika saya mendeteksi tabrakan pada checkCollideWithfungsi, saya menempatkan kotakBentuk kotak ukuran medan di lokasi tabrakan, dan biarkan Bullet menggunakan semua algoritme default untuk mendeteksi titik tabrakan di sana .

Jadi pada dasarnya, jika suatu benda fisika menyentuh material padat. Saya akan menempatkan tubuh fisika sementara saya ke lokasi itu dan memberitahu Bullet untuk memeriksa tabrakan terhadap kubus sementara itu, seolah-olah selalu ada di sana. Ini semacam super optimal menempatkan kotak Bentuk untuk setiap kubus di medan saya. Alih-alih jutaan BoxShapes, saya hanya perlu memiliki satu yang diteleportasi saat tabrakan terdeteksi.

MichaelHouse
sumber
Bisakah Anda memperluas lebih lanjut tentang bagaimana Anda mendeteksi tabrakan di tempat pertama?
timoxley
1
@timoxley Saya sudah memperbarui jawabannya sedikit.
MichaelHouse
Lalu bagaimana Anda menangani satu benda yang bertabrakan di banyak titik, misalnya tangga yang bersandar di tanah dan di dinding?
timoxley
Kubus sementara dipindahkan di sekitar untuk semua tempat di mana objek menghubungi medan. Ini hanya digunakan untuk deteksi yang baik untuk mendapatkan titik kontak dan merespons dengan tepat.
MichaelHouse
3

Saya mengalami beberapa masalah dengan strategi yang diterapkan dalam jawaban saya yang lain. Titik kontak kadang-kadang akan bertahan, itu agak berantakan untuk melakukan bentuk selain kubus dan kadang-kadang akan memungkinkan benda untuk menyelinap melalui medan.

Jadi, alih-alih memodifikasi atau mengganti kelas Bullet mana pun, ada opsi alternatif menggunakan objek tabrakan Bullet bawaan yang akan mewakili medan. ItuBvhTriangleMeshShape ( doc ) adalah dibangun dalam bentuk yang diwakili oleh mesh segitiga.

Mesh ini dapat dihasilkan pada saat yang sama dengan mesh untuk memvisualisasikan dunia. Ini berarti bahwa objek fisika dapat mencocokkan objek yang diberikan dengan tepat.

Saya membuat RigidBodyuntuk setiap potongan di medan saya. Bentuk tubuh itu diatur keBvhTriangleMeshShape . Ketika medan diubah, pada saat yang sama saya membangun kembali representasi visual bongkahan, saya juga membangun kembali bentuk fisika. Kemudian, ketika tiba saatnya untuk buffer bentuk visual, saya juga menukar bentuk fisika seperti:

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

Ini memastikan bahwa tubuh dikeluarkan dengan benar, membersihkan titik kontak. Kemudian bentuknya diubah dan ditambahkan kembali.

Untuk menghasilkan BvhTriangleMeshShapesetiap chunk harus mempertahankan TriangleIndexVertexArray( doc ). Ini pada dasarnya adalah buffer dua byte. Satu dengan posisi simpul segitiga dan yang lainnya dengan indeks untuk membangun segitiga itu. Array vertex ini harus dipertahankan sebagaiBvhTriangleMeshShape tidak membuat salinan data.

Menggunakan semua yang dibangun di kelas fisika Bullet kemungkinan lebih cepat daripada apa pun yang bisa saya tulis, dan memang berjalan sangat cepat. Saya belum melihat adanya perlambatan setelah menerapkan strategi baru ini.

masukkan deskripsi gambar di sini

MichaelHouse
sumber
Saya akan mencatat kepada siapa pun yang membaca ini bahwa, setidaknya dalam pengujian saya, JBullet SANGAT lambat dalam memasak jerat (yaitu preprocessing mereka sebelum mereka dapat digunakan untuk fisika), setidaknya dibandingkan dengan waktu yang diperlukan bagi saya untuk mengubah sepotong menjadi jala melalui kubus berbaris. Kita bicara pesanan lebih lambat. Jadi, saya akan melihat ke PhysX dan melihat seberapa baik saya bisa membuatnya tampil. Jika ada yang punya info tentang ini, saya ingin mendengarnya.
Philip Guin
2

Saya tidak terbiasa dengan Fisika Peluru, tapi saya sudah menggunakan ODE. Di sana, setelah tes tabrakan ya atau tidak, ada tes tabrakan bentuk-bentuk yang lebih rinci yang menghasilkan satu set titik kontak.

Dalam kasus Anda, dunia Anda adalah kumpulan kotak, sehingga Anda bisa melakukan ini:

  1. Ambil AABB dari entitas yang bergerak.
  2. Iterasi di atas voxel medan dalam volume yang memotongnya.
  3. Untuk setiap voxel medan yang padat, buat kotak yang cocok dan hitung (lebih disukai menggunakan rutinitas yang disediakan mesin fisika) tabrakan kotak itu dengan entitas yang bergerak.
  4. Kembalikan koleksi semua titik kontak yang dihasilkan.

Ini bukan mendefinisikan ulang respons tabrakan ; ini adalah lapisan sebelumnya. Respon tumbukan ditentukan sepenuhnya oleh titik kontak yang dihitung dari tumbukan.

Seperti yang saya katakan, saya tidak akrab dengan Bullet Physics, jadi saya tidak tahu apakah arsitekturnya sesuai dengan ini.

Kevin Reid
sumber
Terima kasih. Saya akan berpikir respon tumbukan terikat ke dalam tes tumbukan bentuk juga. Itu harus menggunakan informasi itu untuk memutuskan cara mana yang memisahkan mereka dan seberapa jauh untuk memisahkan mereka, bukan? Saya akan baik-baik saja dengan respons tabrakan saat ini jika menanggapi bentuk medan saya.
MichaelHouse
Iya; Maksud saya, Anda tidak mendefinisikan ulang algoritma respons tumbukan, melainkan mendefinisikan ulang generasi titik kontak yang merupakan input untuk algoritma tersebut.
Kevin Reid