OpenGL: Apakah mungkin untuk menggunakan VAO tanpa menentukan VBO

12

Pada semua tutorial yang dapat saya temukan tentang VAO (Vertex Array Objects), mereka menunjukkan cara menggunakannya dengan mengkonfigurasi atribut vertex dan mengikat VBO (Vertex Buffer Object). Tapi saya ingin membuat VAO yang akan dikonfigurasi untuk satu set VBO dalam kombinasi dengan shader tetap, di mana setiap buffer menggunakan pola data yang sama (vertex, uv, warna, dll). Jadi, saya ingin membuat satu VAO untuk beberapa VBO yang akan ditarik menggunakan satu shader.

Saya tidak dapat menemukan demo tentang ini, jadi saya memutuskan untuk mencobanya. Tetapi itu tidak berhasil dan crash pada glDrawArraypanggilan. Sepertinya VBO tidak terikat. Ini kode yang saya gunakan:

Rendering:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

Pembuatan VAO:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

Di mana lssederhana structyang menyimpan lokasi atribut.

Di bagian Rendering, menukar glBindBufferdan glBindVertexArrayOESsekitar juga tidak berhasil.

Jadi, pertanyaannya adalah: Apakah mungkin untuk melakukannya, atau apakah saya harus membuat untuk setiap buffer sebuah VAO? Dan jika saya harus membuat VAO untuk setiap VBO, apakah mungkin untuk memperbarui data VBO menggunakan glBufferSubDatadalam kombinasi dengan VAO?

Martijn Courteaux
sumber

Jawaban:

18

VAO tidak mengandung status "glBindBuffer", dengan pengecualian GL_ELEMENT_ARRAY_BUFFERstatus pengikatan. Yang tidak Anda pahami adalah glBindBuffer(GL_ARRAY_BUFFER) tidak melakukan apa-apa . Yah, itu tidak melakukan apa-apa sejauh menyangkut rendering. Cobalah; tepat sebelum memanggil glDraw *, panggil glBindBuffer(GL_ARRAY_BUFFER, 0); rendering Anda akan berfungsi dengan baik.

Cara glVertexAttribPointerkerjanya adalah melihat apa yang terikat pada GL_ARRAY_BUFFER pada saat glVertexAttribPointeritu disebut . Tidak pada waktu render. Tidak nanti. Tepat pada saat itu juga. Dibutuhkan objek buffer apa pun yang ada di sana dan menyimpannya di bagian lain dari keadaan OpenGL, yang dienkapsulasi dalam VAO.

Secara umum, Anda memiliki dua opsi, salah satunya yang baru dan mungkin tidak boleh digunakan saat ini.

Opsi pertama Anda adalah untuk meletakkan semua objek yang menggunakan format vertex yang sama (yaitu: semuanya kecuali objek buffer dan offset) dalam objek buffer yang sama. Pada dasarnya, bangun array raksasa yang berisi semua simpul untuk semua objek yang menggunakan format yang sama.

Ketika tiba saatnya untuk membuat, Anda dapat membuat sebagian dari simpul. glDrawArraysmembutuhkan berbagai elemen untuk diurai, dan Anda dapat menyesuaikan indeks Anda glDrawElementsuntuk melakukan hal yang sama. Atau, Anda dapat menggunakan glDrawElementsBaseVertexuntuk membiaskan simpul , sehingga offset ditambahkan ke setiap indeks. Offset ini adalah jumlah simpul sebelum simpul dalam array besar.

Alternatif lain adalah dengan menggunakan sistem pemisahan atribut format yang relatif baru ditambahkan dalam GL 4.3. Itu akan memungkinkan Anda untuk mengubah buffer tanpa mengatur ulang format. Dengan demikian Anda akan mengikat VAO tunggal, kemudian hanya mengganti buffer yang berbeda sesuai kebutuhan glBindVertexBuffer. Ini juga tersedia di ES 3.1.

Nicol Bolas
sumber
1
Driver NV GL4.3 sekarang rilis penuh.
Maximus Minimus
Terima kasih banyak untuk menjelaskan cara glVertexAttribPointer bekerja. Itu mencerahkan dan menjelaskan mengapa dan bagaimana cara kerjanya.
Martijn Courteaux
5

VAO menyimpan status glVertexAttribPointer. Mengubah VAO tidak memengaruhi glBindBuffer saat ini, juga tidak mengubah glBindBuffer memengaruhi VAO. Hanya panggilan glVertexAttribPointer yang memengaruhi VAO, dengan merekam buffer yang digunakan saat panggilan berlangsung.

Jadi jawaban untuk pertanyaan Anda adalah tidak.

Salah satu opsi jika Anda ingin mengurangi jumlah objek adalah dengan meletakkan semua data mesh Anda ke dalam satu VBO besar dan tentukan di mana data mesh tinggal di VBO dalam panggilan glDrawArrays menggunakan argumen 'pertama' dan 'hitung'.

ccxvii
sumber
Semua artikel di internet menunjukkan bahwa mengikat VAO secara otomatis mengikat VBO. Jadi, saya pikir VAO adalah konfigurasi yang menampung status glVertexAttribPointer dan status glBindBuffer . Dan ya, mengikat VBO ketika VAO terikat mengubah VAO. Saya mengatakan ini karena saya menguji ini dan itu efektif. Dari mana informasi ini berasal?
Martijn Courteaux
2
@ MartijnCourteaux: " Semua artikel di internet tentang VAO menunjukkan bahwa mengikat VAO secara otomatis mengikat VBO. " Tidak, tidak. OpenGL Wiki pada spesifikasi vertex tidak. Memang, tunjukkan saya satu artikel di internet yang mengatakan bahwa setiap glBindBuffernegara kecuali GL_ELEMENT_ARRAY_BUFFER diubah dengan mengikat VAO.
Nicol Bolas
Jawaban lain menjelaskan dengan baik bagaimana metode glVertexAttribPointer bekerja. Ia menggunakan VBO yang terikat pada waktu itu. Kamu benar! Terima kasih, saya mengerti sekarang.
Martijn Courteaux