Pracuję nad doskonałymi samouczkami pod arcsynthesis podczas budowania silnika graficznego i odkryłem, że nie rozumiem VAO tak bardzo, jak myślałem Miałem.Obiekty wierzchołków wierzchołków - Zamieszanie dotyczące dokładnie informacji o stanie zapisanych na temat aktualnie powiązanego bufora wierzchołków
z samouczka Chapter 5. Objects In Depth
buforu wiążącego i atrybut Association
Można zauważyć, że glBindBuffer (GL_ARRAY_BUFFER) nie znajduje się na tej liście, choć jest częścią konfiguracji atrybutu dla renderowania. Wiązanie z GL_ARRAY_BUFFER nie jest częścią VAO, ponieważ powiązanie między obiektem bufora i atrybutem vertex nie występuje, gdy wywołuje się glBindBuffer (GL_ARRAY_BUFFER). To skojarzenie ma miejsce, gdy wywołujesz glVertexAttribPointer.
Podczas wywoływania glVertexAttribPointer, OpenGL bierze dowolny bufor w momencie wywołania tego połączenia do GL_ARRAY_BUFFER i kojarzy go z danym atrybutem wierzchołka. Pomyśl o powiązaniu GL_ARRAY_BUFFER jako globalnym wskaźniku, który odczytuje glVertexAttribPointer. Więc możesz swobodnie wiązać cokolwiek chcesz lub nic do GL_ARRAY_BUFFER po wykonaniu wywołania glVertexAttribPointer; wpłynie to na nic w ostatecznym renderowaniu. Zatem VAO zapisują, które obiekty bufora są powiązane z określonymi atrybutami; ale nie przechowują samego powiązania GL_ARRAY_BUFFER.
Początkowo brakowało mi ostatniego wiersza "... ale nie przechowują one samego powiązania GL_ARRAY_BUFFER". Zanim zauważyłem ten wiersz, pomyślałem, że aktualnie powiązany bufor został zapisany po wywołaniu glVertexAttribPointer. Tęsknię za tą wiedzą zbudowałem klasę siatki i udało mi się uzyskać scenę z kilkoma siatkami renderującymi poprawnie.
Część tego kodu jest wymieniona poniżej. Zauważ, że nie nazywam glBindBuffer w funkcji rysowania.
// MESH RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW);
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_normal);
glEnableVertexAttribArray(e_aid_color);
glEnableVertexAttribArray(e_aid_tex);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos));
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col));
glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, tex));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
Teraz, kiedy zaczynam oświetlenie, chciałem uzyskać trochę debugowania, aby sprawdzić, czy wszystkie moje normalne są poprawne. Obecnie po prostu przechowuję wszystkie linie, które mają być renderowane dla ramki w wektorze. Ponieważ te dane będą prawdopodobnie zmieniać każdą klatkę, używam GL_DYNAMIC_DRAW i określam dane tuż przed renderowaniem.
Początkowo, gdy to zrobiłem, otrzymywałbym linie śmieci, które po prostu wskazywałyby nieskończoność. Kod wykraczająca jest poniżej:
// DEBUG DRAW LINE RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
// Note: no buffer data supplied here!!!
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_color);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, pos));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, col));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
// Specifying buffer data here instead!!!
glBufferData(GL_ARRAY_BUFFER, _line_vertices.size() * sizeof(line_vertex), &_line_vertices[0], GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINES, 0, _line_vertices.size());
Po nieco polowania, a także znalezienie detal Tęskniłem powyżej, uważam, że jeśli zadzwonię glBindBuffer przed glBufferData w funkcji draw, wszystko działa obecnie w porządku.
Jestem zdezorientowany, dlaczego mój rendering siatki działał w pierwszej kolejności. Czy muszę ponownie wywołać ponownie glBindBuffer, jeśli zmienię dane w buforze? Czy zachowanie jest niezdefiniowane, jeśli nie wiążemy bufora i miałem po prostu pecha i działało?
Proszę zauważyć, że jestem ukierunkowany na OpenGL w wersji 3.0.
OK, to ma więcej sensu. Mam jeden drobny szczegół, że wciąż jestem trochę nieostry. Powiedzmy, że wywołuję glBindVertexArray z VAO 1, który pamięta, że VBO 1 był związany, gdy został wywołany glVertexAttribPointer. Następnie wywołuję glBindBuffer z VBO 2, a następnie glDrawArrays. Którego bufora należy użyć, VBO 1 lub VBO 2? Nie sądzę, żeby to było coś, co normalnie byśmy robili, chcę tylko upewnić się, że rozumiem, co się dzieje. –
VBO 1 zostanie użyty. Należy pamiętać, że jest to prawdą niezależnie od tego, czy używasz VAO. Również mógłbyś związać kilka VBO podczas gdy miałeś VAO związany (być może inny dla każdego atrybutu). Po wywołaniu glVertexAttribPointer, bufor powiązany w tym czasie jest tym, który zostanie użyty. – GuyRT
Fantastyczny, dobrze wiedzieć! Dziękuję za wyjaśnienia! –