Jaki stan jest przechowywany w obiekcie OpenGL Vertex Array Object (VAO) i jak prawidłowo używać VAO?

25

Zastanawiałem się, jaki stan jest przechowywany w OpenGL VAO. Zrozumiałem, że VAO zawiera stan związany ze specyfikacją wierzchołków buforowanych wierzchołków (jakie atrybuty znajdują się w buforach i jakie bufory są powiązane, ...). Aby lepiej zrozumieć prawidłowe użycie VAO, chciałbym dokładnie wiedzieć, w jakim są stanie.


Jak zakładam, należy użyć VAO

Z prostych przykładów zrozumiałem, że prawidłowe użycie VAO jest następujące:

Ustawiać

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

Wykonanie

Bind VAO
---- Draw
Unbind VAO

Na podstawie tego zakładam, że co najmniej powiązania bufora wierzchołków i specyfikacje atrybutów wierzchołków są przechowywane w VAO. Nie jestem jednak pewien, w jaki sposób ten wzorzec użytkowania rozciąga się na sytuacje, w których wchodzą (wiele) tekstur i (wiele) programów do cieniowania. Czy aktywny program cieniujący jest przechowywany w VAO? I czy wiązania tekstur (wraz z ustawieniami próbkowania / zawijania ) są również przechowywane w VAO? To samo dotyczy mundurów ?


Dlatego moje pytania to:

  • Jaki dokładnie stan jest przechowywany w OpenGL VAO ? (Powiązania VBO, specyfikacje atrybutów, aktywny program cieniujący, wiązania tekstur, ustawienia próbkowania / zawijania tekstur, mundury ...?)
  • Jak poprawnie używać VAO w bardziej złożonej konfiguracji renderowania, w której zaangażowane są (wiele) tekstur z powiązanymi ustawieniami próbkowania / zawijania, (wiele) programów cieniujących i mundurów?
Jelle van Campen
źródło
1
VAO przechowuje dane o lokalizacjach atrybutów wierzchołków. Przechowuje również identyfikatory VBO, w których zawarte są te atrybuty. Nie musisz wiązać VBO podczas rysowania czegoś, musisz go powiązać przed wywołaniem glVertexAttribPointer () podczas tworzenia VAO.
HolyBlackCat

Odpowiedzi:

18

VAO przechowuje dane o lokalizacjach atrybutów wierzchołków. (I niektóre inne związane z nimi dane.)
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms"Są całkowicie z tym niezwiązane.

Możesz zapytać, dlaczego nie pamięta wiązania VBO. Ponieważ nie musisz wiązać VBO, aby coś narysować, musisz tylko powiązać to podczas tworzenia VAO: Kiedy dzwonisz glVertexAttribPointer(...), VAO pamięta, co VBO jest obecnie związane. I VAO weźmie atrybuty z tych VBO podczas rysowania, nawet jeśli te VBO nie są obecnie powiązane.


Ponadto VAO i VBO muszą być używane nieco inaczej:

To nie zadziała

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

ponieważ musisz powiązać VBO, aby określić lokalizacje atrybutów.

Powinieneś to zrobić w ten sposób:

Generate VAO
BindVAO
Generate VBO's
BindVBO's
Specify vertex attributes

Możesz zmienić dane VBO w dowolnym momencie, ale musisz je wcześniej powiązać.

A rysunek powinien wyglądać następująco:

Bind VAO
Draw


Jak zauważyłeś, usunąłem unbindpołączenia z twoich list. Są prawie całkowicie bezużyteczne i nieco spowalniają twój program, więc nie widzę powodu, aby je wywoływać.

HolyBlackCat
źródło
9
„więc nie widzę powodu, by do nich dzwonić”. aby zapobiec ich przypadkowej zmianie. Szczególnie problem podczas korzystania z bibliotek innych firm.
grzechotka
Dziękuję za świetną odpowiedź! Krótko mówiąc, VAO przechowuje tylko lokalizacje atrybutów wierzchołków. VBO nie są odbijane podczas wiązania VAO, ponieważ VAO wie, w jakich buforach znaleźć atrybuty. Wszystkie inne stany są zawarte w globalnym stanie OpenGL.
Jelle van Campen
@JellevanCampen Tak, poprawne. Do Twojej wiadomości, przechowuje również stan wyłączania / włączania atrybutów ( gl{Enable|Disable}VertexAttribArray()), ich wartości domyślne ( glVertexAttrib*()), ich tryb instancji ( glVertexAttribDivisor()) i prawdopodobnie coś innego.
HolyBlackCat
@HolyBlackCat czy jesteś pewien, że stan domyślny (glVertexAttrib ()) jest częścią stanu VAO? Wiki OpenGL twierdzi inaczej, mówiąc, że są stanem kontekstowym.
rdb
@ndb Nie, nie jestem pewien. Spodziewałem się, że będą częścią stanu VAO i nie sprawdziłem tego.
HolyBlackCat
4

Przechowuje tylko powiązanie wierzchołka i powiązanie bufora indeksu

To są wszystkie parametry glVertexAttribPointerplus bufor związany z Vertex_Array_buffer w momencie wywołania do glVertexAttribPointeri związany Element_Array_buffer.

Mundury są częścią bieżącego programu.

Cała reszta to stan globalny.

W razie wątpliwości możesz sprawdzić tabele stanu w specyfikacji używanej wersji.

maniak zapadkowy
źródło
Dziękuję również za odpowiedź! To dla mnie wyjaśnia.
Jelle van Campen
4

Oto proste, ale skuteczne wyjaśnienie, w zasadzie obiekt buforowy zawiera informacje, które można interpretować jako zwykłe fragmenty surowych danych, które same w sobie nic nie znaczą, więc OCZYWIŚCIE to dane, na które można naprawdę spojrzeć w jakikolwiek sposób

i.e float vbo[]={1.0,2.0,34.0...}

a sposób, w jaki OpenGL został zaprojektowany, polega na tym, że musisz OKREŚLIĆ, jak będą wyglądały dane przesyłane do różnych modułów cieniujących

w tym, że musisz również zdefiniować, w jaki sposób będą odczytywać te dane, w jakim formacie i jak z nimi postępować oraz w jaki sposób będą wykorzystywane i do czego, wszystkie te informacje są przechowywane w VAO

na przykład możesz zadeklarować dane przechowywane w takiej tablicy float vbo = {11.0,2.0,3.0,4.0}

w tym momencie wymagane jest, jak interpretować te dane z VBO w VAO, a to oznacza, co następuje

VAO można ustawić na odczyt 2 liczb zmiennoprzecinkowych na wierzchołek (co dałoby 2 wektory o dwóch wymiarach x, y) lub możesz powiedzieć vao, aby zinterpretowało go jako 1 wektor o 4 wymiarach, tj. x, y, z, w itp

ale także inne atrybuty tych danych są zdefiniowane i przechowywane w VAO, takie jak format danych (pomimo że zadeklarowałeś tablicę zmiennoprzecinkową, możesz nakazać modułowi cieniującemu odczytanie go jako liczbę całkowitą, przy czym system konwertuje nieprzetworzone dane w proces od liczby zmiennoprzecinkowej do liczby całkowitej i ma własny zestaw reguł, co robić w takich okolicznościach)

Zasadniczo VBO to dane, a VAO przechowuje informacje na temat interpretacji tych danych, ponieważ shadery i serwer OpenGL zostały zaprojektowane tak, aby były bardzo wścibskie i muszą wiedzieć wszystko, zanim zdecydują, jak je przetworzyć, co z nimi zrobić i gdzie położyć to

oczywiście nie jest wścibski, naprawdę wygląda na najbardziej wydajny, ponieważ musi przechowywać te dane w pamięci serwera graficznego, aby uzyskać najbardziej wydajne i najszybsze przetwarzanie (chyba że zdecyduje, że nie musi tego robić, jeśli dane nie mogą być przetwarzane w taki sposób i wykorzystywane do niektórych innych informacji, do których często nie ma dostępu), dlatego też szczegóły dotyczące tego, co zrobić z danymi i jak je przetwarzać, muszą być przechowywane w VAO, więc VAO jest jak nagłówek, a VBO jest jak czyste, surowe dane, które nagłówek używa i definiuje (w tym przypadku przekazuje atrybuty wierzchołka modułu cieniującego), z tym wyjątkiem, że VBO nie jest ograniczone tylko do jednego VAO, to mogą być używane i ponownie używane oraz powiązane z wieloma VAO, na przykład:

co możesz zrobić, to możesz powiązać jeden obiekt buforowy z VAO1, a także (osobno) powiązać ten sam obiekt buforowy z VAO2, przy czym każdy interpretuje go inaczej, tak że jeśli twój moduł cieniujący przetwarza dane, w zależności od tego, który VAO jest tym, który jest związany, przetwarzałby te same surowe dane inaczej niż frambuffer (rysowanie pikseli do okna), co skutkowałoby innym wyświetlaniem tych samych danych, które byłyby oparte na tym, jak zdefiniowałeś ich użycie w VAO

hopjopper
źródło
To najlepsza odpowiedź!
CodingMadeEasy