Beberapa terminologi agak salah:
- A
Vertex Array
hanyalah sebuah larik (biasanya a float[]
) yang berisi data simpul. Tidak perlu terikat pada apa pun. Jangan bingung dengan Vertex Array Object
atau VAO, yang akan saya bahas nanti
- A
Buffer Object
, biasanya disebut sebagai Vertex Buffer Object
saat menyimpan simpul, atau singkatnya VBO, adalah apa yang Anda sebut hanya a Buffer
.
- Tidak ada yang disimpan kembali ke array vertex,
glVertexAttribPointer
bekerja persis seperti glVertexPointer
atau glTexCoordPointer
berfungsi, hanya sebagai ganti atribut bernama, Anda bisa memberikan nomor yang menentukan atribut Anda sendiri. Anda meneruskan nilai ini sebagai index
. Semua glVertexAttribPointer
panggilan Anda akan diantrekan untuk saat berikutnya Anda menelepon glDrawArrays
atau glDrawElements
. Jika Anda memiliki ikatan VAO, VAO akan menyimpan pengaturan untuk semua atribut Anda.
Masalah utama di sini adalah Anda mengacaukan atribut vertex dengan VAO. Atribut simpul hanyalah cara baru untuk mendefinisikan simpul, texcoords, normals, dll. Untuk menggambar. Status penyimpanan VAO. Pertama-tama saya akan menjelaskan cara menggambar bekerja dengan atribut vertex, lalu menjelaskan bagaimana Anda dapat mengurangi jumlah panggilan metode dengan VAO:
- Anda harus mengaktifkan atribut sebelum Anda dapat menggunakannya di shader. Misalnya, jika Anda ingin mengirim simpul ke shader, kemungkinan besar Anda akan mengirimkannya sebagai atribut pertama, 0. Jadi sebelum Anda merender, Anda perlu mengaktifkannya dengan
glEnableVertexAttribArray(0);
.
- Sekarang setelah atribut diaktifkan, Anda perlu menentukan data yang akan digunakannya. Untuk melakukannya, Anda perlu mengikat VBO Anda -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- Dan sekarang kita bisa mendefinisikan atribut -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. Urutan parameter: 0 adalah atribut yang Anda definisikan, 3 adalah ukuran setiap simpul, GL_FLOAT
adalah tipe, GL_FALSE
artinya tidak menormalkan setiap simpul, 2 angka nol terakhir berarti tidak ada langkah atau offset pada simpul.
- Gambarlah sesuatu dengannya -
glDrawArrays(GL_TRIANGLES, 0, 6);
- Hal berikutnya yang Anda gambar mungkin tidak menggunakan atribut 0 (secara realistis memang demikian, tetapi ini adalah contoh), jadi kami dapat menonaktifkannya -
glDisableVertexAttribArray(0);
Gabungkan itu dalam glUseProgram()
panggilan dan Anda memiliki sistem rendering yang bekerja dengan shader dengan benar. Tetapi katakanlah Anda memiliki 5 atribut yang berbeda, simpul, texcoords, normals, warna, dan koordinat peta cahaya. Pertama-tama, Anda akan membuat satu glVertexAttribPointer
panggilan untuk masing-masing atribut ini, dan Anda harus mengaktifkan semua atribut sebelumnya. Katakanlah Anda menentukan atribut 0-4 seperti yang saya daftarkan. Anda akan mengaktifkan semuanya seperti ini:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
Dan kemudian Anda harus mengikat VBO yang berbeda untuk setiap atribut (kecuali Anda menyimpan semuanya dalam satu VBO dan menggunakan offset / langkah), maka Anda perlu membuat 5 glVertexAttribPointer
panggilan berbeda , dari glVertexAttribPointer(0,...);
ke glVertexAttribPointer(4,...);
untuk simpul ke koordinat lightmap.
Mudah-mudahan sistem itu saja masuk akal. Sekarang saya akan beralih ke VAO untuk menjelaskan cara menggunakannya untuk mengurangi jumlah pemanggilan metode saat melakukan jenis rendering ini. Perhatikan bahwa menggunakan VAO tidak perlu.
A Vertex Array Object
atau VAO digunakan untuk menyimpan status semua glVertexAttribPointer
panggilan dan VBO yang ditargetkan saat setiap glVertexAttribPointer
panggilan dilakukan.
Anda membuat satu dengan panggilan ke glGenVertexArrays
. Untuk menyimpan semua yang Anda butuhkan dalam VAO, ikat dengan glBindVertexArray
, lalu lakukan panggilan undian penuh . Semua panggilan draw bind dicegat dan disimpan oleh VAO. Anda dapat melepaskan VAO denganglBindVertexArray(0);
Sekarang ketika Anda ingin menggambar objek, Anda tidak perlu memanggil ulang semua pengikat VBO atau glVertexAttribPointer
panggilan, Anda hanya perlu mengikat VAO dengan glBindVertexArray
panggilan itu glDrawArrays
atau glDrawElements
dan Anda akan menggambar hal yang persis sama seolah-olah Anda melakukan semua panggilan metode tersebut. Anda mungkin ingin melepaskan VAO setelahnya juga.
Setelah Anda melepaskan VAO, semua status akan kembali seperti sebelum Anda mengikat VAO. Saya tidak yakin apakah ada perubahan yang Anda buat saat VAO terikat disimpan, tetapi itu dapat dengan mudah diketahui dengan program pengujian. Saya kira Anda dapat menganggap glBindVertexArray(0);
sebagai mengikat ke "default" VAO ...
Pembaruan: Seseorang memberi tahu saya perlunya panggilan undian yang sebenarnya. Ternyata, Anda sebenarnya tidak perlu melakukan panggilan draw LENGKAP saat menyiapkan VAO, cukup semua hal yang mengikat. Tidak tahu mengapa saya pikir itu perlu sebelumnya, tetapi sekarang sudah diperbaiki.
glVertexAttribPointer
? Dalam pengujian saya, urutan tampaknya tidak menjadi masalah. (2) Jika saya memahami Anda dengan benar, Atribut Vertex bersifat global, dan hanya status aktif / nonaktif yang disimpan ke VAO terikat saat ini?glDrawArrays
atauglDrawElements
. Saya akan memperbarui posting untuk mencerminkan bahwa (2) Ya, tetapi bukan hanya status aktifkan / nonaktifkan yang disimpan, itu semua yang berkaitan dengan panggilan tersebut - apa yang terikat ke GL_ARRAY_BUFFER pada saat itu, jenis, langkah, dan offset. Pada dasarnya itu menyimpan cukup untuk mengubah semua Atribut Vertex kembali ke cara Anda mengaturnya dengan VAO.layout(location = x)
di shader atau denganglBindAttributeLocation
saat mengompilasi shader. ContohTerminologi dan urutan API yang akan dipanggil memang cukup membingungkan. Yang lebih membingungkan adalah bagaimana berbagai aspek - penyangga, atribut simpul umum dan variabel atribut shader dikaitkan. Lihat OpenGL-Terminology untuk penjelasan yang cukup bagus.
Selanjutnya, tautan OpenGL-VBO, shader, VAO menunjukkan contoh sederhana dengan panggilan API yang diperlukan. Ini sangat bagus untuk mereka yang beralih dari mode langsung ke pipeline yang dapat diprogram.
Semoga membantu.
Sunting: Seperti yang Anda lihat dari komentar di bawah ini, orang dapat membuat asumsi dan mengambil kesimpulan. Kenyataannya cukup membingungkan bagi pemula.
sumber
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)
pengenal tersebut disebutindex
. Pengenal yang sama dalam konteks program disebutlocation
di API glGetAttribLocation .