OpenGL: Czy można używać VAO bez określania VBO

12

We wszystkich samouczkach, które mogę znaleźć o VAO (obiektach tablicy wierzchołków), pokazują one, jak ich używać, konfigurując atrybuty wierzchołków i wiążąc VBO (obiekt bufora wierzchołków). Ale chcę utworzyć VAO, który zostanie skonfigurowany dla zestawu VBO w połączeniu ze stałym shaderem, w którym każdy bufor używa tego samego wzorca danych (wierzchołek, ultrafiolet, kolor itp.). Chcę więc utworzyć jedno VAO dla wielu VBO, które zostaną narysowane przy użyciu jednego modułu cieniującego.

Nie mogłem znaleźć żadnej wersji demo, więc postanowiłem spróbować. Ale to nie działa i zawiesza się podczas glDrawArraypołączenia. Wygląda na to, że VBO nie jest związane. Oto kod, którego używam:

Wykonanie:

/* 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);

Kreacja 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);

Gdzie lsjest prosty, structktóry zawiera lokalizacje atrybutów.

W części Rendering zamiana glBindBufferi glBindVertexArrayOESreszta również nie działały.

Pytanie brzmi: czy jest to w ogóle możliwe, czy też muszę utworzyć dla każdego bufora wartość VAO? A jeśli muszę utworzyć VAO dla każdego VBO, czy można zaktualizować dane VBO przy użyciu glBufferSubDataw połączeniu z VAO?

Martijn Courteaux
źródło

Odpowiedzi:

18

VAO nie zawierają stanu „glBindBuffer”, z wyjątkiem GL_ELEMENT_ARRAY_BUFFERstanu wiązania. Nie rozumiesz, że glBindBuffer(GL_ARRAY_BUFFER) nic nie robi . Cóż, nie robi nic, jeśli chodzi o rendering. Spróbuj; tuż przed wywołaniem glDraw *, call glBindBuffer(GL_ARRAY_BUFFER, 0); renderowanie będzie działać dobrze.

Sposób glVertexAttribPointerdziałania polega na tym, że patrzy na to, co jest powiązane z GL_ARRAY_BUFFER w momencie glVertexAttribPointerwywołania . Nie w czasie renderowania. Nie później. Właśnie w tym momencie. Pobiera dowolny obiekt bufora i przechowuje go w innym stanie OpenGL, który jest zamknięty w VAO.

Ogólnie rzecz biorąc, masz dwie opcje, z których jedna jest nowa i prawdopodobnie nie powinna być w tej chwili używana.

Pierwszą opcją jest umieszczenie wszystkich obiektów, które używają tego samego formatu wierzchołków (tj. Wszystko oprócz obiektu buforowego i przesunięcia) w tym samym obiekcie buforowym. Zasadniczo zbuduj gigantyczną tablicę, która zawiera wszystkie wierzchołki dla wszystkich obiektów, które używają tego samego formatu.

Jeśli chodzi o czas renderowania, możesz renderować część wierzchołków. glDrawArraysrenderuje szereg elementów i możesz dostosować swoje indeksy, glDrawElementsaby zrobić to samo. Alternatywnie można użyć glDrawElementsBaseVertexdo odchylenia wierzchołków , aby przesunięcie było dodawane do każdego indeksu. To przesunięcie jest liczbą wierzchołków przed tym wierzchołkiem w dużej tablicy.

Inną alternatywą jest użycie stosunkowo nowego systemu separacji atrybutów formatu dodanego w GL 4.3. Umożliwiłoby to zmianę buforów bez resetowania formatu. W ten sposób powiążesz pojedynczy VAO, a następnie po prostu zastąpisz go w różnych buforach, jeśli potrzeba glBindVertexBuffer. Jest to również dostępne w ES 3.1.

Nicol Bolas
źródło
1
Sterowniki NV GL4.3 są teraz w pełnej wersji.
Maximus Minimus
Dziękujemy bardzo za wyjaśnienie sposobu działania glVertexAttribPointer. To było pouczające i wyjaśnia, dlaczego i jak to działa.
Martijn Courteaux
5

VAO przechowuje stan glVertexAttribPointer. Zmiana VAO nie wpływa na bieżący glBindBuffer, ani zmiana glBindBuffer nie wpływa na VAO. Tylko wywołanie glVertexAttribPointer wpływa na VAO, rejestrując bufor używany podczas połączenia.

Odpowiedź na twoje pytanie brzmi: nie.

Jedną z opcji, jeśli chcesz zmniejszyć liczbę obiektów, jest umieszczenie wszystkich danych siatki w jednym dużym VBO i określenie, gdzie dane siatki znajdują się w VBO w wywołaniu glDrawArrays przy użyciu argumentów „first” i „count”.

ccxvii
źródło
Wszystkie artykuły w Internecie na temat VAO pokazują, że wiązanie VAO automatycznie wiąże VBO. Myślę więc, że VAO to konfiguracja, która przechowuje zarówno stany glVertexAttribPointer, jak i stan glBindBuffer . I tak, powiązanie VBO, gdy VAO jest związane, zmienia VAO. Mówię to, ponieważ przetestowałem to i działa skutecznie. Skąd pochodzą te informacje?
Martijn Courteaux
2
@MartijnCourteaux: „ Wszystkie artykuły w Internecie na temat VAO pokazują, że wiązanie VAO automatycznie wiąże VBO. ” Nie, nie robią tego. Wiki OpenGL na temat specyfikacji wierzchołków nie. Rzeczywiście, pokaż mi jeden artykuł w Internecie, który mówi, że każdy glBindBufferstan oprócz GL_ELEMENT_ARRAY_BUFFER zmieniany jest przez związanie VAO.
Nicol Bolas,
Druga odpowiedź wyjaśniła dobrze, jak działa metoda glVertexAttribPointer. Używa wtedy związanego VBO. Masz rację! Dzięki, teraz rozumiem.
Martijn Courteaux