Cara paling efisien untuk menggambar sejumlah besar objek yang sama, tetapi dengan transformasi yang berbeda


8

Saya ingin menggambar sejumlah besar (ribuan) jerat sederhana (masing-masing mungkin ... maksimal 50 segitiga, tetapi bahkan itu adalah batas atas yang sangat besar), yang semuanya persis sama.

Sebagai cara brute force yang sederhana, saat ini saya hanya melakukan ribuan panggilan draw, di mana saya hanya mengubah matriks transformasi yang dibutuhkan oleh shader dan kemudian menggambar objek yang sama lagi.

Tentu saja ini sangat lambat, karena (saya menduga) ada terlalu banyak panggilan untuk pengemudi dan PC saya untuk menangani secara efisien.

Apa yang bisa saya lakukan untuk membuatnya lebih cepat?


4
Saya tidak bisa memberi Anda jawaban yang lengkap, tetapi jawaban tingkat tinggi adalah menggunakan geometri instancing .
Seth Battin

Cari google untuk "Geometry Instancing", mungkin Anda dapat menemukan sesuatu yang membantu Anda seperti itu
Luis W

Jawaban:


11

Solusi untuk ini adalah pemasangan. Tutorial ini menjelaskan beberapa metode pemasangan. Jika sudah ARB_draw_instanceddan ARB_instanced_arrays, gunakan.

Gagasan umum adalah untuk menyimpan semua transformasi jerat Anda dalam objek buffer terpisah dan mengikatnya ke array atribut yang menggunakan satu "titik" per instance via glVertexAttribDivisor.

Jika, setelah itu, Anda masih tidak berlari secepat yang Anda inginkan, Anda mungkin terikat prosesor vertex. Lakukan pemusnahan frustasi pada jerat, dan lebih baik buat BVH untuk dilintasi daripada melakukan pemusnahan pada semua jerat secara independen.


1
+1; dengan ribuan objek Anda juga dapat menjadi terikat pada CPU pada transformasi (hanya mengirim posisi dan rotasi dalam buffer per-instance Anda dan menghitung matriks per-objek pada GPU dapat membantu di sini), dan jangan lupa untuk menonton bagaimana Anda memperbarui buffer vertex dinamis!
Maximus Minimus

@Robert Rouhani: Terima kasih, saya telah meneliti dan segera mengimplementasikannya. Sekarang saya dapat menggambar 5000 jerat dengan masing-masing 20 tris pada 250 FPS. Ngomong-ngomong, cara yang disarankan Anda agak ketinggalan jaman. Karena OpenGL 3.something geometry instancing adalah bagian resmi dari spesifikasi inti OpenGL, tidak perlu lagi untuk ARB_xxx. Saya menggunakan buffer seragam untuk menyimpan matriks, dan menggunakan glDrawElementsInstanced. Di dalam vertex shader, ada layout (std140) matriks seragam {mat4 array [5000]; } di mana saya dapat mengakses elemen yang relevan melalui array [gl_InstanceID]
TravisG

1
@ TravisG Saya cenderung mencoba dan mendukung versi yang lebih lama. Saya mengerti bahwa kedua ekstensi tersebut telah dipromosikan ke core untuk sementara waktu, namun string ekstensi akan tetap ada :). Juga, menggunakan glVertexAttribDivisor(yang tidak usang atau ketinggalan zaman dengan cara apa pun) memiliki manfaat tidak memiliki batas atas pada jumlah instance. Kinerja secara historis lebih baik daripada buffer seragam, tetapi mungkin sama atau sangat mirip sekarang, dan kedua cara menyelesaikan pekerjaan.
Robert Rouhani

@Robert Rouhani: Mhm ... Saya kira itu benar. Seseorang dengan driver yang sudah ketinggalan zaman dapat mendukung ARB_xxx tetapi tidak dengan fitur inti resmi OpenGl 3.x. Saya akan melihat glVertexAttribDivisor, terima kasih.
TravisG

@Robert Rouhani: Saya menerapkan kedua versi (menggunakan buffer seragam, dan sebagai alternatifnya versi yang disarankan di mana saya menggunakan atribut vertex yang hanya berubah satu kali per instance), dan versi buffer seragam sebenarnya sekitar dua kali lebih cepat (4000 fps dalam mode rilis, vs ~ 2000 dengan glVertexAttribDivisor, angka 250 fps hanya untuk sisi CPU).
TravisG
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.