2012-01-02 25 views
86

Po prostu chcę się upewnić, rozumiem to poprawnie (pytałem na SO Czat, ale żyje tam!):glVertexAttribPointer wyjaśnienie

Mamy Vertex Array, który wykonujemy „prąd” przez związanie go
wtedy mamy bufor, które wiązać się z celem
następnie wypełniamy że docelowy poprzez glBufferData który zasadniczo wypełnia co musiało do tego celu, czyli nasz bufor
a następnie nazywamy glVertexAttribPointer który opisuje sposób rozmieszczenia danych - dane są niezależnie od tego, co jest związane z GL_ARRAY_BUFFER it jego deskryptor jest zapisany w naszej oryginalnej Tablicy wierzchołków

(1) Czy moje zrozumienie jest prawidłowe?
The documentation jest trochę ubogi w to, jak wszystko się koreluje.

(2) Czy jest jakiś domyślny zestaw wierzchołków wierzchołków? Ponieważ zapomniałem/pominąłem glGenVertexArrays i glBindVertexArray i mój program działał bez niego.


Edit: Tęskniłem krok ... glEnableVertexAttribArray.

(3) Czy Vertex Attrib jest powiązany z Vertex Array w czasie, gdy wywoływana jest glVertexAttribPointer, a następnie możemy włączyć/wyłączyć ten atrybut przez glEnableVertexAttribArray w dowolnym momencie, niezależnie od tego, który Vertex Array jest aktualnie powiązany?

Albo (3b) Czy Vertex Attrib przywiązany do tablicy Vertex w czasie glEnableVertexAttribArray nazywa, a więc możemy dodać taką samą Vertex Attrib do wielu Vertex tablice wywołując glEnableVertexAttribArray w różnych czasach, kiedy różne Tablice Vertex są związani ?

Odpowiedz

195

Część terminologii Nieco:

  • Vertex Array znajduje się szereg (zwykle float[]), który zawiera dane wierzchołek. Nie musi być związany z niczym. Nie należy mylić z Vertex Array Object lub vào, który pójdę na później
  • Buffer Object, powszechnie określany jako Vertex Buffer Object podczas przechowywania wierzchołków lub VBO w skrócie, jest to, co dzwonisz tylko Buffer.
  • Nic nie zostanie zapisane z powrotem do tablicy wierzchołków, glVertexAttribPointer działa dokładnie tak samo jak glVertexPointer lub glTexCoordPointer działa, zamiast zamiast nazwanych atrybutów, podajesz liczbę określającą własny atrybut. Przekazujesz tę wartość jako index. Wszystkie twoje połączenia glVertexAttribPointer zostaną umieszczone w kolejce do następnego połączenia z numerem glDrawArrays lub glDrawElements. Jeśli masz powiązanie VAO, VAO przechowa ustawienia dla wszystkich twoich atrybutów.

Głównym problemem jest to, że wprowadzasz mylące atrybuty wierzchołków za pomocą VAO. Atrybuty vertex to tylko nowy sposób definiowania wierzchołków, texcoordów, normaliów itp. Do rysowania. Stan sklepu VAO. Ja pierwszy zamiar wyjaśnić, jak rysunek współpracuje z atrybutów wierzchołków, a następnie wyjaśnić, w jaki sposób można zmniejszyć liczbę od metoda nazywa się VAOs:

  1. należy włączyć atrybut, zanim będzie można go używać w cieniującego.Na przykład, jeśli chcesz wysłać wierzchołki do modułu cieniującego, najprawdopodobniej prześlesz go jako pierwszy atrybut, 0. Zanim więc wyrenderujesz, musisz włączyć go przy pomocy glEnableVertexAttribArray(0);.
  2. Teraz, gdy atrybut jest włączony, musisz zdefiniować dane, których zamierzasz użyć. W tym celu musisz powiązać swój VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
  3. A teraz możemy zdefiniować atrybut - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. W kolejności parametru: 0 jest definiowanym atrybutem, 3 jest rozmiarem każdego wierzchołka, GL_FLOAT jest typem, GL_FALSE oznacza, że ​​nie znormalizuje każdego wierzchołka, ostatnie 2 zera oznaczają, że nie ma żadnego kroku ani przesunięcia na wierzchołkach.
  4. narysować coś z nim - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. Następną rzeczą, którą wyciągnąć nie mogą wykorzystywać atrybut 0 (realnie to będzie, ale jest to przykład), więc możemy go wyłączyć - glDisableVertexAttribArray(0);

Wrap, że w glUseProgram() połączenia i masz system renderowania, który działa poprawnie z shaderów. Ale załóżmy, że masz 5 różnych atrybutów, wierzchołków, texcoordów, normalnych, kolorowych i współrzędnych lightmap. Po pierwsze, będziesz wykonywał pojedyncze wywołanie glVertexAttribPointer dla każdego z tych atrybutów, a wcześniej musisz włączyć wszystkie atrybuty. Powiedzmy, że definiujesz atrybuty 0-4, tak jak je mam na liście. Można by umożliwić wszystkie z nich tak:

for (int i = 0; i < 5; i++) 
    glEnableVertexAttribArray(i); 

I wtedy trzeba by powiązać różne VBOs dla każdego atrybutu (chyba, że ​​je wszystkie przechowywać w jednym VBO i wykorzystania przesunięć/krok), a następnie trzeba wykonać 5 różne połączenia glVertexAttribPointer, od glVertexAttribPointer(0,...); do glVertexAttribPointer(4,...); dla współrzędnych wierzchołków do lightmap.

Mam nadzieję, że sam system ma sens. Teraz przejdę do VAO, aby wyjaśnić, jak z nich korzystać, aby ograniczyć liczbę wywołań metod podczas wykonywania tego typu renderowania. Należy pamiętać, że korzystanie z VAO nie jest konieczne.

Vertex Array Object lub VAO służy do przechowywania stan wszystkich połączeń glVertexAttribPointer i VBOs które były kierowane gdy każde z połączeń glVertexAttribPointer zostały wykonane.

Generujesz jeden z połączenia z numerem glGenVertexArrays. Aby przechowywać wszystko, czego potrzebujesz w VAO, powiązaj je z glBindVertexArray , a następnie wykonaj pełne połączenie remisowe . Wszystkie wywołania bindowania są przechwytywane i przechowywane przez VAO. Można rozwiązać ten vào z glBindVertexArray(0);

Teraz kiedy chcesz narysować obiekt, nie trzeba ponownie wywołać wszystkie VBO wiąże lub połączenia glVertexAttribPointer, wystarczy powiązać vào z glBindVertexArray następnie wywołać glDrawArrays lub glDrawElements i będziesz rysował dokładnie to samo, jakbyś wykonywał wszystkie te wywołania metod. Prawdopodobnie również chcesz później rozwiązać VAO.

Po odzwiązaniu VAO, cały stan powraca do stanu sprzed zawiązania VAO. Nie jestem pewien, czy jakiekolwiek zmiany, które wprowadzisz podczas wiązania VAO, są zachowane, ale można je łatwo ustalić za pomocą programu testowego. Myślę, że można myśleć o glBindVertexArray(0); jako wiążące do „default” vào ...


Aktualizacja: Ktoś zwrócił moją uwagę na potrzebę rzeczywistej rozmowy rysować.Jak się okazuje, nie musisz wykonywać PEŁNEGO wywołania losowania podczas konfigurowania VAO, tylko wszystkie wiążące rzeczy. Nie wiem, dlaczego uważałem, że było to konieczne wcześniej, ale teraz jest naprawione.

+9

"Obiekt bufora wierzchołków lub VBO (czasami nazywany tylko obiektem buforowym)" To "czasami" jest nazywane, ponieważ tak właśnie się nazywa. Jest to po prostu obiekt buforowy, nie różni się od jakiegokolwiek innego obiektu bufora, którego można użyć do tworzenia jednolitych bloków, przesyłania pikseli, przekształcania informacji zwrotnych lub jakiegokolwiek innego użycia. Specyfikacja OpenGL * never * odnosi się do niczego jako "obiekt bufora wierzchołków"; nawet [oryginalna specyfikacja rozszerzenia] (http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt) nigdy tego tak nie nazywa. –

+0

Edytowane w celu dopasowania właściwego nazewnictwa, dziękuję. –

+3

Doskonała odpowiedź. Dziękujemy za poświęcenie czasu na napisanie tego! Kilka pytań uzupełniających jednak: (1) Powiedziałeś "zanim wyrenderujesz, a zanim zdefiniujesz atrybut, musisz go włączyć za pomocą glEnableVertexAttribArray (0)" - czy na pewno trzeba go włączyć przed wywołaniem? glVertexAttribPointer'? W moich testach kolejność nie ma znaczenia. (2) Jeśli rozumiem cię poprawnie, Atrybuty wierzchołków są globalne i tylko ich stan włączony/wyłączony jest zapisany w aktualnie powiązanym VAO? – mpen

2

Terminologia i sekwencja API, które należy nazwać, jest naprawdę niezrozumiała. Jeszcze bardziej mylące jest to, w jaki sposób powiązane są różne aspekty - bufor, ogólny atrybut vertex i zmienna atrybutów shadera. Zobacz OpenGL-Terminology, aby uzyskać całkiem niezłe wyjaśnienie.

Ponadto link OpenGL-VBO,shader,VAO pokazuje prosty przykład z niezbędnymi wywołaniami API. Jest to szczególnie dobre dla osób przechodzących z trybu natychmiastowego do programowalnego potoku.

Mam nadzieję, że to pomaga.

Edytuj: Jak widać z poniższych komentarzy, ludzie mogą przyjmować założenia i wyciągać wnioski. W rzeczywistości jest to dość mylące dla początkujących.

+0

"* Zobacz terminologię OpenGL z całkiem niezłym wyjaśnieniem. *" W czasie krótszym niż 1 minuta znalazłem już jeden dezinformację: "Są one zastąpione ogólnymi atrybutami wierzchołków z identyfikatorem (zwanym indeks), który jest powiązany ze zmienną modułu cieniującego (dla współrzędnych, kolorem itp.), który przetwarza atrybut. " Nie nazywa się ich "wskaźnikami"; są "lokalizacjami". To bardzo ważne rozróżnienie, ponieważ atrybuty wierzchołków [* także * mają "wskaźniki"] (https://www.opengl.org/wiki/Program_Introspection#Attributes), które * różnią się * od lokalizacji. To bardzo okropna strona. –

+1

To jest uczciwy komentarz, ale nie do końca dokładny. Jeśli spojrzysz na API OpenGL, aby zdefiniować atrybut ogólny [glVertexAttribPointer] (https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml), "void glVertexAttribPointer (indeks GLuint, rozmiar GLint, GLenum typ, GLboolean znormalizowany, GLsizei krok, const GLvoid * wskaźnik) ', identyfikator jest określany jako" indeks ". Ten sam identyfikator w kontekście programu nazywa się 'location' w interfejsie API [glGetAttribLocation] (https://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml). –