Apa itu Objek Array Vertex?

114

Saya baru mulai mempelajari OpenGL hari ini dari tutorial ini: http://openglbook.com/the-book/
Saya sampai pada bab 2, di mana saya menggambar segitiga, dan saya memahami segalanya kecuali VAO (apakah akronim ini OK?). Tutorial memiliki kode ini:

glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);

Meskipun saya memahami bahwa kode itu diperlukan, saya tidak tahu apa fungsinya. Meskipun saya tidak pernah menggunakan VaoId melewati titik ini (kecuali untuk menghancurkannya), kode tidak akan berfungsi tanpanya. Saya berasumsi ini karena itu harus terikat, tapi saya tidak tahu mengapa. Apakah kode persis ini hanya perlu menjadi bagian dari setiap program OpenGL? Tutorial menjelaskan VAO sebagai:

Objek Array Vertex (atau VAO) adalah objek yang menjelaskan bagaimana atribut simpul disimpan dalam Objek Penyangga Vertex (atau VBO). Ini berarti bahwa VAO bukanlah objek sebenarnya yang menyimpan data simpul, melainkan deskriptor dari data simpul tersebut. Atribut vertex dapat dijelaskan oleh fungsi glVertexAttribPointer dan dua fungsi kembarnya glVertexAttribIPointer dan glVertexAttribLPointer, yang pertama akan kita bahas di bawah.

Saya tidak mengerti bagaimana VAO mendeskripsikan atribut vertex. Saya belum menjelaskannya dengan cara apa pun. Apakah itu mendapatkan informasi dari glVertexAttribPointer? Saya kira ini pasti itu. Apakah VAO hanyalah tujuan untuk informasi dari glVertexAttribPointer?

Di samping catatan, apakah tutorial yang saya ikuti dapat diterima? Apakah ada hal yang harus saya perhatikan atau tutorial yang lebih baik untuk diikuti?

Patrick
sumber

Jawaban:

100

"Vertex Array Object" dipersembahkan oleh Subkomite ARB OpenGL untuk Nama-Nama Konyol.

Anggap saja sebagai objek geometri. (Sebagai programmer SGI Performer lama, saya menyebutnya geosets.) Variabel instan / anggota objek adalah penunjuk titik, penunjuk normal, penunjuk warna, penunjuk attrib N, ...

Ketika VAO terikat pertama, Anda menetapkan anggota ini dengan menelepon

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;

dan seterusnya. Atribut mana yang diaktifkan dan petunjuk yang Anda berikan disimpan di VAO.

Setelah itu ketika Anda mengikat VAO lagi, semua atribut dan pointer juga menjadi saat ini. Jadi satu glBindVertexArraypanggilan setara dengan semua kode yang sebelumnya diperlukan untuk menyiapkan semua atribut. Ini berguna untuk melewatkan geometri di antara fungsi atau metode tanpa harus membuat struct atau objek Anda sendiri.

(Penyiapan satu kali, banyak penggunaan adalah cara termudah untuk menggunakan VAO, tetapi Anda juga dapat mengubah atribut hanya dengan mengikatnya dan melakukan lebih banyak panggilan pengaktifan / penunjuk. VAO bukanlah konstanta.)

Info lebih lanjut untuk menanggapi pertanyaan Patrick:

Default untuk VAO yang baru dibuat adalah kosong (AFAIK). Tidak ada geometri sama sekali, bahkan titik pun, jadi jika Anda mencoba menggambarnya, Anda akan mendapatkan kesalahan OpenGL. Ini cukup masuk akal, seperti dalam "menginisialisasi semuanya ke False / NULL / zero".

Anda hanya perlu glEnableClientStatesaat Anda menyiapkan semuanya. VAO mengingat status aktifkan / nonaktifkan untuk setiap penunjuk.

Ya, VAO akan menyimpan glEnableVertexAttribArraydan glVertexAttrib. Array simpul lama, normal, warna, ... sama dengan larik atribut, simpul == # 0 dan seterusnya.

Hugh
sumber
62
'"Vertex Array Object" dipersembahkan oleh Subkomite ARB OpenGL untuk Nama-Nama Konyol.' Ya, nama yang konyol untuk sebuah objek yang menyimpan binding array vertex .
Nicol Bolas
2
Juga, apakah VAO sama sekali terkait denganglVertexAttribPointer
Patrick
2
Harap tambahkan beberapa informasi tentang penggunaan atribut simpul umum untuk orang-orang yang menggunakan profil inti.
Oskar
8
@NicolBolas Nama yang lebih baik akan menjadi VertexArrayMacroatau sesuatu yang serupa.
bobobobo
7
@NicolBolas "Objek Array Vertex" adalah nama yang buruk. Ini tentang mengikat data ke atribut . Ini bukan tentang array dari simpul, seperti namanya. Tidak ada referensi ke binding atau atribut dalam nama, dan karena "larik verteks" adalah konsep terpisah itu sendiri, hal itu membuat pemahaman menjadi lebih sulit. IMHO, "(Vertex) Attributes Binding Object" lebih mudah dipahami. Bahkan Objek Geometri lebih baik: Saya tidak suka, tapi setidaknya tidak kelebihan beban.
AkiRoss
8

Objek Array Vertex seperti makro dalam program pengolah kata dan sejenisnya. Deskripsi yang bagus ditemukan di sini .

Makro hanya mengingat tindakan yang Anda lakukan, seperti mengaktifkan atribut ini, mengikat buffer itu, dll. Saat Anda memanggil glBindVertexArray( yourVAOId ), itu hanya memutar ulang binding pointer atribut dan binding buffer.

Jadi panggilan Anda berikutnya untuk menggambar menggunakan apa pun yang terikat oleh VAO.

VAO tidak menyimpan data titik . Tidak. Data vertex disimpan dalam buffer vertex atau dalam array memori klien.

bobobobo
sumber
19
-1: Mereka tidak seperti makro. Jika ya, maka mengikat VAO baru tidak akan menonaktifkan array vertex yang diaktifkan oleh VAO sebelumnya, kecuali jika VAO baru telah "merekam" Anda secara eksplisit menonaktifkan array tersebut. VAO, seperti semua objek OpenGL, menahan status , bukan perintah. Perintah hanya mengubah status, tetapi objek datang dengan set status default. Itulah mengapa mengikat VAO yang baru dibuat akan selalu menonaktifkan semua atribut.
Nicol Bolas
6

Saya selalu berpikir tentang VAO sebagai array buffer data yang digunakan oleh OpenGL. Dengan menggunakan OpenGL modern Anda akan membuat Objek VAO dan Vertex Buffer.

masukkan deskripsi gambar di sini

//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer

Langkah selanjutnya adalah mengikat data ke buffer:

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices

Pada titik ini OpenGL Melihat:

masukkan deskripsi gambar di sini

Sekarang kita dapat menggunakan glVertexAttribPointer untuk memberi tahu OpenGL apa yang diwakili oleh data dalam buffer:

glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)

masukkan deskripsi gambar di sini

OpenGL sekarang memiliki data di buffer dan mengetahui bagaimana data diatur ke dalam simpul. Proses yang sama dapat diterapkan ke koordinat tekstur dll, tetapi untuk koordinat tekstur akan ada dua nilai.

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

Selanjutnya Anda dapat mengikat tekstur dan menggambar array, Anda akan ingin membuat shader Vert dan Frag, mengkompilasi dan memasangnya ke program (tidak disertakan di sini).

glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square
vasmos
sumber
5

VAO adalah objek yang merepresentasikan tahap pengambilan vertex dari pipeline OpenGL dan digunakan untuk menyuplai input ke vertex shader.

Anda dapat membuat objek vertex array seperti ini

GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

Pertama mari kita lakukan contoh sederhana. Pertimbangkan parameter input seperti itu dalam kode shader

layout (location = 0) in vec4 offset; // input vertex attribute

Untuk mengisi atribut ini bisa kita gunakan

glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0

Meskipun objek vertex array menyimpan nilai atribut statis ini untuk Anda, ia dapat melakukan lebih banyak lagi.

Setelah membuat objek vertex array kita bisa mulai mengisi statusnya. Kami akan meminta OpenGL untuk mengisinya secara otomatis menggunakan data yang disimpan di objek buffer yang kami suplai. Setiap atribut vertex dapat mengambil data dari buffer yang terikat ke salah satu dari beberapa ikatan buffer vertex. Untuk tujuan ini kami gunakan glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). Juga kami menggunakan glVertexArrayVertexBuffer()fungsi untuk mengikat buffer ke salah satu ikatan buffer simpul. Kami menggunakan glVertexArrayAttribFormat()fungsi untuk mendeskripsikan tata letak dan format data, dan terakhir kami mengaktifkan pengisian otomatis atribut dengan memanggil glEnableVertexAttribArray().

Saat atribut vertex diaktifkan, OpenGL akan memasukkan data ke shader vertex berdasarkan format dan informasi lokasi yang Anda berikan dengan glVertexArrayVertexBuffer()dan glVertexArrayAttribFormat(). Saat atribut dinonaktifkan, shader vertex akan diberikan informasi statis yang Anda berikan dengan panggilan glVertexAttrib*().

// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));

// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);

glEnableVertexArrayAttrib(vao, 0);

Dan kode di shader

layout (location = 0) in vec4 position;

Setelah semua yang Anda butuhkan untuk menelepon glDeleteVertexArrays(1, &vao).


Anda dapat membaca OpenGL SuperBible untuk memahaminya dengan lebih baik.

Yola
sumber
3
Senang rasanya melihat orang-orang mempromosikan penggunaan OpenGL gaya DSA.
Nicol Bolas