2013-06-21 15 views
7

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.

Odpowiedz

10

Czy tylko muszę zadzwonić glBindBuffer ponownie w przypadku zmiany danych w buforze ?

Tak Obiekt VAO pamięta które były związane bufory za każdym razem o nazwie glVertexAttribPointer VAO natomiast, że był związany, więc zwykle nie trzeba zadzwonić glBindBuffer ponownie. Jeśli chcesz zmienić dane w buforze, OpenGL musi wiedzieć, który bufor chcesz zmienić, więc musisz zadzwonić pod numer glBindBuffer, zanim zadzwonisz pod numer glBufferData. Nie ma znaczenia, który obiekt VAO jest związany w tym momencie.

+2

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. –

+2

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

+1

Fantastyczny, dobrze wiedzieć! Dziękuję za wyjaśnienia! –

Powiązane problemy