Perbedaan glDrawArrays dan glDrawElements

12

Sambil menyegarkan pikiran saya pada OpenGL ES, saya menemukan glDrawArraysdan glDrawElements.

Saya mengerti bagaimana mereka digunakan dan mengerti mengapa mereka berbeda.

Apa yang saya tampaknya tidak mengerti adalah bahwa, saya gagal melihat bagaimana cara glDrawElementsmenyimpan panggilan draw ( menyimpan panggilan draw adalah deskripsi yang disebutkan oleh sebagian besar buku yang saya baca, maka saya menyebutkannya di sini).

Bayangkan skenario sederhana di mana saya mencoba menggambar persegi menggunakan 2 segitiga.

Saya perlu memiliki satu set 6 simpul menggunakan glDrawArrayssaat menggunakan glDrawElements, saya hanya perlu 4 di samping array indeks yang memiliki 6 elemen.

Mengingat hal di atas, inilah yang saya tidak mengerti:

  1. bagaimana bisa glDrawElementsmenyimpan panggilan draw, jika masih perlu menggunakan array indeks (6 indeks, dalam kasus kuadrat) untuk mengindeks ke dalam array vertex saya yang memiliki 4 elemen (6 kali)? Dengan kata lain, apakah itu berarti glDrawElementsmasih perlu memiliki total 6 panggilan draw sama seperti glDrawArrays?
  2. bagaimana menggunakan glDrawElementsmenghemat ruang, jika seseorang masih perlu memiliki 2 array, yaitu, satu untuk simpul dan satu untuk indeks?
  3. Dalam kasus menggambar kuadrat dari 2 segitiga, untuk kesederhanaan, berapa banyak panggilan draw tidak glDrawElements(4 item dalam array verteks dan 6 item dalam array indeks) dan glDrawArrays(6 item hanya dalam array vertex) perlu, secara individual?

Terima kasih.

Unheilig
sumber

Jawaban:

16

Setiap glDraw * adalah panggilan undian.

1 glDrawArrays adalah 1 panggilan draw.
1 glDrawElements adalah 1 panggilan draw.

Tidak masalah (sejauh menyangkut penghitungan panggilan), berapa banyak simpul atau indeks yang Anda gunakan, 1 glDraw * adalah 1 panggilan draw.

Kasus-kasus sederhana menggambar paha depan (dengan asumsi versi GL yang Anda gunakan belum menghapus paha depan) atau segitiga bukan contoh yang baik untuk membandingkan ini, karena daftar paha depan atau daftar segitiga dapat ditarik dengan satu panggilan ke salah satu, dan glDrawArrays akan tampak lebih efisien karena tidak memiliki overhead pengindeksan tambahan.

Mari kita ambil kasus yang sedikit lebih rumit, tetapi yang mewakili skenario dunia nyata. Bayangkan Anda memiliki model yang terdiri dari beberapa strip segitiga dan kipas:

glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);

Dalam contoh ini, menggunakan glDrawArrays memberi Anda total 6 panggilan draw untuk model. Namun, strip dan kipas dapat dengan mudah dikonversi menjadi segitiga yang diindeks, jadi tambahkan indeks dan itu menjadi:

glDrawElements (GL_TRIANGLES, .....);

Itu satu panggilan undian, untuk seluruh model.


Kelebihan glDrawElements dibandingkan glDrawArrays lebih dari sekadar penghematan memori, yang merupakan cara naif untuk mengukurnya. Ada potensi untuk menghemat memori di mana simpul dapat digunakan kembali, karena indeks biasanya lebih kecil dari simpul (jadi bahkan jika Anda memiliki banyak indeks pada keseimbangan mereka akan lebih kecil), tetapi keuntungan lainnya termasuk:

  • Jumlah panggilan undian berkurang. Setiap draw call mengeluarkan beberapa overhead dari memvalidasi state, mengatur segalanya, dll, dan banyak overhead ini terjadi di sisi CPU. Dengan mengurangi jumlah panggilan draw, kami menghindari banyak overhead ini.

  • Vertex digunakan kembali. Ini jauh lebih dari sekedar penghematan memori. GPU Anda kemungkinan memiliki cache vertex perangkat keras, tempat simpul yang baru diubah dapat disimpan; jika titik yang sama masuk lagi, dan jika ada di cache, itu dapat digunakan kembali dari cache daripada harus mengubah lagi. Perangkat keras Anda akan memeriksa cache dengan membandingkan indeks, jadi dalam istilah OpenGL satu-satunya cara Anda menggunakan cache adalah dengan menggunakan glDrawElements.


Jadi untuk menjawab pertanyaan spesifik Anda:

  1. bagaimana glDrawElements menyimpan panggilan draw ...? Dalam contoh yang Anda gunakan, tidak. Masing-masing memiliki satu panggilan undian. Seperti yang saya diskusikan di atas, contoh ini sangat buruk untuk membandingkan keduanya.

  2. bagaimana menggunakan glDrawElements menghemat ruang ...? Karena indeks lebih kecil dari simpul. Indeks 16-bit adalah dua byte, posisi / warna / texcoord adalah 24 byte. 6 simpul adalah 144 byte, 4 simpul ditambah 6 indeks adalah 108 byte.

  3. Dalam hal menggambar persegi dari 2 segitiga ...? Satu dan satu. Panggilan glDraw * adalah panggilan satu kali, jumlah simpul atau indeks yang digunakan tidak relevan untuk pengukuran ini. Tetapi saya harus menekankan kembali, ini adalah contoh yang sangat buruk untuk membandingkan keduanya.


Akhirnya, dan hanya sedikit memperumit masalah, sementara glDrawElements dengan segitiga adalah jalur optimal pada GPU desktop, pada seluler mungkin sangat berbeda. Beberapa GPU seluler mungkin lebih suka glDrawArrays dengan GL_TRIANGLE_STRIP (Anda akan menambahkan segitiga yang merosot untuk menggabungkan primitif dalam kasus ini), dan saya bahkan belum menyentuh topik yang lebih maju seperti restart primitif atau multi-draw.

Maximus Minimus
sumber
Terima kasih banyak atas umpan balikmu; Saya hanya mengambil sedikit waktu untuk membaca apa yang telah Anda bagikan. Hanya ingin memberi tahu Anda, saya mengakui respons Anda. Terima kasih lagi.
Unheilig
Dalam contoh Anda mengonversi 6 panggilan DrawTriangleFans dan DrawTriangleStrips menjadi 1 panggilan DrawTriangles tunggal. Apakah ini benar-benar meningkatkan kinerja? Untuk pemahaman saya, menggambar strip segitiga yang terdiri dari 100 segitiga jauh lebih efisien daripada menggambar 100 segitiga secara individual, dan manfaatnya akan dengan mudah mengimbangi penalti yang terjadi karena menggunakan 6 pemanggilan fungsi daripada 1.
Samuel Li
@SamuelLi 6-to-1 tidak akan menjadi peningkatan besar, itu hanya dimaksudkan untuk menggambarkan prinsip tersebut. Juga, dan seperti yang saya sebutkan, strip biasanya bukan kemenangan kinerja atas daftar yang diindeks pada perangkat keras desktop pasca-1998. Periksa tanggal pada dokumen apa pun yang menyarankan Anda untuk menggunakan strip.
Maximus Minimus
Dapatkan poin Anda, terima kasih atas klarifikasi! @MaximusMinimus
Samuel Li