Benturan Objek Kecil, Berkecepatan Tinggi: Menghindari Tunneling


14

EDIT / PEMBARUAN: Pertanyaan terbesar saya saat ini adalah apakah persamaan "t = ..." langkah 3 adalah ide yang bagus atau ada cara yang lebih baik untuk melakukannya. Sebagian besar masalah lain telah ditangani sebagian atau seluruhnya, tetapi tidak ada komentar atau jawaban yang benar-benar menyentuh masalah ini. Sekali lagi, solusi analitik mungkin diperlukan, kecepatan dan jarak terlalu besar, dan benda-benda terlalu kecil, untuk setiap solusi iteratif / rekursif (beberapa disarankan di bawah ini di komentar) yang dapat saya pikirkan (walaupun jika ada solusi iteratif / rekursif khusus yang akan menangani situasi semacam ini baik-baik saja maka saya pasti terbuka untuk itu). Terima kasih banyak atas bantuan Anda sejauh ini, Anda semua luar biasa dan saya sangat menghargai pikiran dan bantuan Anda!

Saya mencoba mendeteksi tabrakan antara benda-benda kecil berkecepatan tinggi. Ini adalah situasi di mana tunneling dapat terjadi dengan sangat mudah, bahkan pada kecepatan yang relatif rendah.

Ray casting tidak akan berfungsi, karena ini mendeteksi tabrakan antara dua objek berkecepatan tinggi, bukan antara satu objek dan dinding stasioner. (Kecuali jika saya salah paham tentang pengecoran sinar?) Kinerja SANGAT BANYAK pertimbangan; jika mungkin, saya ingin menghindari hit kinerja besar. Saya sudah memiliki quadtree yang fungsional dan sangat efektif ( http://en.wikipedia.org/wiki/Quadtree ) diimplementasikan, jadi saya akan memodifikasi dan menggunakannya seperti dijelaskan di bawah ini.

Sunting: Mengurangi interval waktu tidak akan berfungsi. Kecepatannya terlalu tinggi untuk solusi ini, yang berarti bahwa hit kinerja akan terlalu besar, sementara masih kehilangan sebagian besar tabrakan tunneling . (Misalnya, saya mungkin memiliki objek dengan ukuran sekitar 1 unit dengan kecepatan yang diukur dalam jutaan unit per interval waktu ...)

SOLUSI YANG DIUSULKAN:

Langkah 1:

Buat kotak di sekitar pergerakan setiap objek, lalu masukkan kotak-kotak itu ke dalam quadtree untuk menghasilkan daftar awal kemungkinan tabrakan. Lihat gambar berikut (gambar ini menunjukkan objek lingkaran yang bergerak dari satu posisi ke posisi lain, dan gerakan menghasilkan persegi panjang, yang akan dimasukkan ke dalam quadtree):Rectangle Diproduksi Oleh Gerakan

Langkah 2: (mungkin ingin melewati langkah ini?)

Periksa daftar kemungkinan tabrakan yang dihasilkan oleh quadtree. Lihat apakah persegi panjang berpotongan di setiap kemungkinan tabrakan. Jika demikian, lanjutkan ke langkah 3.

SUNTING: Di bawah ini, Sean Middleditch menyarankan menggunakan volume sapuan / persimpangan kapsul (jika objeknya lingkaran). Itu menyisakan tiga opsi: 1) lewati langkah 2 seluruhnya. 2) Lakukan langkah 2 dengan cara saya. 3) Lakukan dengan cara Sean. Cara Sean akan lebih mahal secara komputasi daripada ide kotak saya, namun itu akan menghilangkan lebih banyak hal positif yang salah daripada cara saya, mencegah mereka mencapai langkah terakhir.

Adakah yang bisa berbicara dari pengalaman tentang mana dari 3 pilihan ini yang terbaik? (Saya bermaksud menggunakan mesin fisika ini untuk beberapa hal yang berbeda, jadi saya mencari solusi "umumnya terbaik" yang bekerja paling cepat di berbagai situasi terluas, bukan hanya satu kasus uji khusus di mana saya dapat dengan mudah mengukur solusi mana tercepat).

Langkah 3:

Gunakan persamaan t = di bawah ini, jika diskriminan (yaitu bagian di bawah akar kuadrat) negatif atau 0, tidak ada tabrakan, jika positif maka gunakan nilai t sebagai waktu tabrakan (setelah itu mudah untuk menyesuaikan posisi sesuai. ..Jika kedua objek terus ada setelah tabrakan). Persamaan:

t = (-1/2 sqrt ((2 a w-2 a x + 2 b y-2 b z-2 c w + 2 c x-2 d y + 2 dz) ^ 2-4 (w ^ 2- 2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2) (a ^ 2-2 a c + b ^ 2-2 b d + c ^ 2 + d ^ 2-r ^ 2-2 r ss ^ 2)) - a + a xb y + b z + c wc x + d yd z) / (w ^ 2-2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2 ) .

Di mana (1 dan 2 digunakan untuk menunjukkan objek 1 dan 2):

t adalah nilai waktu negatif antara 0 dan -1, di mana 0 adalah frame saat ini, dan -1 adalah frame sebelumnya;

a = x posisi 1;

b = y posisi 1;

c = x posisi 2;

d = posisi y 2;

w = x kecepatan 1;

x = x kecepatan 2;

y = y kecepatan 1;

z = y kecepatan 2;

r = radius 1;

s = radius 2;

Derivasi: (^ 2 berarti kuadrat)

Ambil persamaan parametrik (misalnya, newxpos1 = a + t w) untuk gerakan objek dan hubungkan ke rumus jarak (mengkuadratkan kedua sisi): rumus jarak kuadrat = (a + t w - (c + t x)) ^ 2 + (b + t y - (d + t * z)) ^ 2. Ingat, t akan menjadi negatif. Untuk menemukan waktu tabrakan untuk dua objek melingkar kami mengatur sisi kiri sama dengan (r + s) ^ 2. Memecahkan untuk t menggunakan persamaan kuadratik (dan banyak aljabar yang sangat membosankan), kita mendapatkan persamaan "t = ..." di atas.

Pertanyaan saya:

1) Apakah ini cara yang baik untuk melakukannya? Apakah ini akan berhasil? Apakah saya akan mengalami masalah yang tidak terduga? (Saya tahu saya akan mengalami masalah ketika lebih dari 2 objek pada suatu waktu bertabrakan, tetapi saya tidak peduli karena satu-satunya kasus yang saya benar-benar keberatan adalah ketika mereka memiliki kecepatan relatif rendah (jika kecepatan relatif tinggi) maka solusi "konyol" yang diberikan algoritma akan "cukup baik", dan tidak mungkin bagi manusia untuk melihat kesalahan), dan jika lebih dari 2 bertabrakan dengan kecepatan relatif rendah dalam langkah waktu yang sama, sebagian besar solusi akan cukup dekat saja, karena saya tidak berencana untuk memiliki banyak tabrakan inelastik)

2) Apakah kinerja saya akan banyak menderita? Saya pikir itu tidak akan terjadi, tetapi jika ya, apakah ada cara yang lebih baik untuk melakukannya?

3) Haruskah saya melewati langkah 2 dan langsung dari langkah 1 ke 3? Jelas langkah 2 tidak penting, tetapi mungkin membantu kinerja (ATAU mungkin lebih banyak waktu CPU daripada menghemat).

Semua komentar, saran, atau kritik lainnya sangat kami harapkan. Terima kasih untuk bantuannya!


1
Christer Ericson memiliki beberapa info tentang pengujian sapu / bola di buku oranye-nya. Ada beberapa cara untuk menyelesaikan masalah, tetapi saya pikir Anda akan suka interval yang paling membagi dua. Adalah baik untuk mencoba menurunkan barang-barang ini sendiri, tetapi Anda benar-benar harus melihat buku oranye dan membandingkan untuk mendapatkan rutin deteksi yang sangat baik dan belajar lebih banyak.
RandyGaul

Sepertinya Anda sudah punya rencana .. coba dan lihat cara kerjanya?
Trevor Powell

Saya pikir cara "biasa" adalah memiliki interval maksimum kecil pada waktu delta Anda. Jadi jika Anda memiliki 1000 ms terlewati, hanya mensimulasikan 10x 100ms (atau 100x 10ms, atau 33x 30ms, atau yang serupa).
ashes999

@RandyGaul Saya melihat algoritma yang dijelaskan pada halaman 215-218, terutama halaman 218 (pratinjau Google). Ini cukup elegan, meskipun saya belum memikirkan semua implikasinya, kekuatan, dan kelemahannya. Apakah ini akan jauh lebih cepat daripada milikku? Jika demikian, apa bagian dari algoritma saya yang lambat dibandingkan dengan rekursi Ericson? Apakah persamaan pada langkah 3 akan terlalu lambat? Rekursi membuat saya ragu, karena beberapa objek mungkin bergerak SANGAT cepat, dan karenanya banyak rekursi mungkin diperlukan dalam beberapa kasus. (Juga, OUCH, $ 70 untuk buku itu ...)
MindSeeker

1
@MindSeeker Saya tidak punya waktu untuk memeriksa derivasi Anda, tetapi saya yakin bahwa algoritma dalam buku Ericson, salah satunya, akan bekerja dengan sangat baik dan mungkin lebih cepat dan lebih kuat daripada barang-barang Anda. Anda dapat menemukan versi PDF online secara gratis, jika Anda ingin demo halaman lain. Juga jika Anda akan sering melakukan deteksi tabrakan, buku oranye itu merupakan bahan pokok.
RandyGaul

Jawaban:


9

Anda pada dasarnya telah membuat versi volume sapuan yang agak terlalu antusias .

Ambil dua posisi objek. "Sapu" objek dari awal hingga akhir. Untuk bola, ini akan membuat kapsul. Untuk kotak, ini akan membuat segi enam (atau kotak yang lebih panjang adalah pergerakan sepanjang sumbu tunggal). Untuk poligon cembung umum, ini akan membuat poligon cembung yang berbeda.

Anda sekarang dapat melakukan tes persimpangan (termasuk kueri quadtree) menggunakan volume sapuan ini. Anda dapat menghitung kapan tabrakan terjadi, memutar maju simulasi dari waktu mulai ke waktu tabrakan, dan ulangi.

Pilihan lain, yang agak sederhana, adalah melakukan apa yang @ ashes999 nyatakan dan hanya menggunakan interval waktu yang lebih kecil atau kecepatan yang lebih kecil. Ada kecepatan maksimum ideal yang diperoleh dari interval di mana tidak ada objek yang dapat bergerak lebih jauh dari sisi tersempitnya dalam satu interaksi fisika. Untuk objek yang sangat kecil atau sangat cepat, Anda mungkin tidak dapat menemukan interval yang cukup kecil yang berkinerja baik.

Lihat Deteksi Tabrakan Real-Time untuk salah satu buku pengantar / perantara yang lebih baik tentang topik mendeteksi tabrakan.


Terima kasih atas masukan yang luar biasa! Hancurkan jawaban Anda sehingga saya dapat mengajukan pertanyaan tentangnya: "" Sapu "objek dari awal hingga akhir." Sejauh ini saya melacak; jelas merupakan peningkatan dari metode kotak saya. Saya akan memberi makan bentuk ini dengan quadtree dan kemudian memeriksa tabrakan yang lebih tepat. "Kamu bisa menghitung kapan tabrakan terjadi." Haha lebih mudah diucapkan daripada dilakukan :) Apakah Anda merekomendasikan agar saya tetap dengan persamaan saya dari langkah 3 untuk langkah? Atau ada cara yang lebih baik? Ini adalah bagian yang sangat kritis.
MindSeeker

[lanjutan] "Opsi lain ..." Saya memikirkan opsi itu, tetapi sayangnya kecepatannya terlalu tinggi. Lihat tanggapan komentar saya pada @ ashes999 dan edit di atas untuk info lebih lanjut. Terima kasih banyak atas bantuan Anda!
MindSeeker

Satu-satunya cara untuk mengetahui kinerja adalah dengan mencobanya, mengukurnya, dan melihat. Saya telah melihat beberapa "jelas" kode tidak efisien secara besar-besaran melakukan versi efisien sebelumnya, biasanya untuk alasan yang sangat tidak intuitif. Jangan bertanya apa yang tercepat; menguji dan mencari tahu.
Sean Middleditch

Cukup adil, saya akan melanjutkan dan mencoba metode saya, dimodifikasi seperti yang Anda sarankan. Pertanyaan saya dalam komentar masih tetap: "Anda dapat menghitung kapan tabrakan terjadi." Apakah Anda merekomendasikan agar saya tetap dengan persamaan saya dari langkah 3 untuk langkah itu? Atau ada cara yang lebih baik? Ini adalah bagian paling sulit dari masalah yang saya pikir. Volume yang tersapu, jika saya memahaminya dengan benar, dapat memberi tahu saya bahwa jalur objek bersilangan, tetapi tidak dapat memberi tahu saya jika / ketika objek itu sendiri bertabrakan.
MindSeeker

1
@MindSeeker Swept geometry adalah raycasting kecuali Anda menggunakan bentuk bukan sinar. Jadi metode ini harus terlihat mirip dengan menggunakan pengecoran sinar dengan "sinar" untuk semua objek yang bergerak cepat, bukan hanya satu sinar dibandingkan objek yang diam. Setelah Anda menentukan potensi tabrakan dari "sinar" Anda perlu menyelesaikan waktu pada kedua "sinar" untuk memastikan mereka berada di tempat yang sama pada waktu yang sama.
stonemetal

2

Algoritme yang dikemukakan dalam pertanyaan bekerja dengan sangat baik: cepat dan sepenuhnya akurat , bahkan ketika benda-benda bergerak dengan kecepatan ekstrem. Saya memiliki quadtree diimplementasikan, jadi setelah memasukkan kotak-kotak dari langkah 1 ke quadtree, saya menemukan langkah 2 tidak perlu: program saya berjalan hampir secepat sebelumnya.

Saya telah menggunakan algoritma ini selama beberapa bulan sekarang, dan tampaknya sangat akurat dalam menentukan t, waktu tabrakan. Karena tampaknya tidak ada yang lebih baik di web, saya sangat merekomendasikan menggunakan yang ini. (Beberapa jawaban dalam jawaban dan komentar di atas bagus, tetapi mereka tidak cukup memenuhi kebutuhan seperti yang dinyatakan oleh pertanyaan atau penulis sangat ambigu tentang sesuatu dan tidak pernah kembali untuk menjawab ketika ditanya tentang ambiguitas ).


1

Saya belum memiliki reputasi yang cukup untuk berkomentar, tetapi saya hanya ingin menambahkan bahwa menggunakan apa yang Sean Middleditch sebutkan di atas memungkinkan untuk menghitung "t" Anda. Setidaknya jika saya mengerti jawabannya dan Anda bertanya dengan benar.

Berikut ini tautan ke jawaban yang luar biasa dari sam hocevar yang memberikan penjelasan terbaik tentang hal itu yang pernah saya temukan (dia menggambar juga, hore!)

/gamedev//a/55991/112940

Jika itu lebih cepat daripada metode Anda sendiri, saya tidak bisa mengatakannya, tetapi dia yakin memberi Anda semua yang Anda butuhkan untuk mengimplementasikannya dan membandingkannya dengan milik Anda.

Hanya untuk menghindari meninggalkan "tautan saja jawaban", saya akan memberikan ringkasan singkat idenya:

  1. menghitung Perbedaan Minkowski antara dua kotak yang terikat
  2. menggunakan kecepatan relatif antara itu, melemparkan segmen ray / garis dari asal ke kotak yang dibuat oleh Perbedaan Minkowski untuk mendapatkan titik persimpangan
  3. Jika sinar itu mengenai, bagi jarak jarak sinar Anda dilalui oleh panjang vektor yang mewakili kecepatan relatif dan Anda akan memiliki "t"
  4. klik pada tautan yang saya berikan di atas dan lihat sam penjelasan yang indah dari semua ini, dengan banyak gambar. Itu luar biasa.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.