Qual estado é armazenado em um VAO (OpenGL Vertex Array Object) e como uso o VAO corretamente?

25

Eu queria saber qual estado é armazenado em um OpenGL VAO. Entendi que um VAO contém um estado relacionado às especificações de vértices em buffer (quais atributos estão nos buffers e quais buffers estão ligados ...). Para entender melhor o uso correto dos VAO, eu gostaria de saber exatamente qual estado eles mantêm.


Como presumo que os VAO devem ser usados

A partir de exemplos simples, entendi que o uso correto dos VAO é o seguinte:

Configuração

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

Renderização

Bind VAO
---- Draw
Unbind VAO

A partir disso, suponho que pelo menos as ligações do buffer de vértice e as especificações de atributo de vértice sejam armazenadas no VAO. No entanto, não tenho certeza de como esse padrão de uso se estende a situações em que (várias) texturas e (vários) programas de sombreador entram em cena. O programa shader ativo está armazenado no VAO? E as ligações de textura (com suas configurações de amostragem / quebra automática ) também são armazenadas no VAO? O mesmo vale para uniformes ?


Portanto, minhas perguntas são:

  • Que estado exato é armazenado em um OpenGL VAO ? (Ligações VBO, especificações de atributos, programa de sombreador ativo, ligações de textura, configurações de amostragem / quebra automática de textura, uniformes ...?)
  • Como uso corretamente os VAOs em uma configuração de renderização mais complexa em que (várias) texturas estão associadas a configurações de amostragem / quebra automática, (vários) programas de sombreamento e uniformes?
Jelle van Campen
fonte
11
O VAO armazena dados sobre os locais dos atributos dos vértices. Ele também armazena IDs de VBOs nos quais esses atributos estão contidos. Você não precisa vincular o VBO ao desenhar algo, é necessário vinculá-lo antes de chamar glVertexAttribPointer () ao criar o VAO.
precisa saber é o seguinte

Respostas:

18

O VAO armazena dados sobre os locais dos atributos dos vértices. (E alguns outros dados relacionados a eles.) Não
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms"têm nenhuma relação com isso.

Você pode perguntar por que ele não se lembra da ligação do VBO. Como você não precisa vincular o VBO para desenhar algo, basta vinculá-lo ao criar o VAO: Quando você liga glVertexAttribPointer(...), o VAO lembra o que o VBO está atualmente vinculado. E o VAO receberá atributos desses VBOs quando você o desenhar, mesmo que esses VBOs não estejam vinculados atualmente.


Além disso, os VAOs e VBOs devem ser usados ​​de maneira ligeiramente diferente:

Isso não vai funcionar

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

porque você precisa vincular o VBO para especificar os locais dos atributos.

Então, você deve fazer assim:

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

Você pode alterar os dados do VBO quando quiser, mas deve vinculá-lo antes.

E o desenho deve ficar assim:

Bind VAO
Draw


Como você deve ter notado, removi unbindchamadas de suas listas. Eles são quase completamente inúteis e tornam o programa um pouco mais lento, por isso não vejo motivo para chamá-los.

HolyBlackCat
fonte
9
"então não vejo razão para ligar para eles." para evitar alterá-los acidentalmente. Especialmente um problema ao usar bibliotecas de terceiros.
Ratchet freak
Obrigado pela ótima resposta! Portanto, em resumo, o VAO armazena apenas os locais dos atributos do vértice. Os VBOs não são recuperados ao vincular um VAO, pois o VAO sabe em quais buffers encontrar os atributos. Todos os outros estados estão contidos no estado global do OpenGL.
Jelle van Campen
@JellevanCampen Sim, correto. Para sua informação, ele também armazena o estado ativado / desativado dos atributos ( gl{Enable|Disable}VertexAttribArray()), seus valores padrão ( glVertexAttrib*()), seu modo de instanciamento ( glVertexAttribDivisor()) e provavelmente outra coisa.
precisa saber é o seguinte
@HolyBlackCat tem certeza de que o estado padrão (glVertexAttrib ()) faz parte do estado VAO? O wiki do OpenGL afirma o contrário, dizendo que eles são um estado de contexto.
rdb
@ndb Não, eu não tenho certeza. Eu esperava que eles fizessem parte do estado da VAO e não verifiquei.
9118 HolyBlackCat
4

Ele armazena apenas a ligação de vértice e a ligação do buffer de índice

Esses são todos os parâmetros de glVertexAttribPointermais o buffer vinculado a Vertex_Array_buffer no momento da chamada glVertexAttribPointere ao Element_Array_buffer associado.

Os uniformes fazem parte do programa atual.

Tudo o resto é estado global.

Na dúvida, você pode verificar as tabelas de estado nas especificações da versão que você está usando.

catraca arrepiante
fonte
Obrigado pela resposta também! Isso esclarece as coisas para mim.
Jelle van Campen
4

Aqui está uma explicação simples, mas eficaz: basicamente, um objeto de buffer possui informações que podem ser interpretadas apenas como bits de dados brutos, que por si só não significam nada; portanto, é PURAMENTE os dados que podem ser vistos de alguma maneira realmente

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

e a maneira como o OpenGL foi projetado para funcionar é que você DEFINE como serão os dados que sua passagem aos vários shaders se parecerá com os shaders

na medida em que você também precisa definir como os dados serão lidos, em que formato eles estão, o que fazer com eles, como serão usados ​​e para quê, todas essas informações serão armazenadas no VAO

por exemplo, você pode declarar dados armazenados em uma matriz como esta float vbo = {11.0,2.0,3.0,4.0}

o que é necessário a seguir neste momento é como interpretar esses dados do VBO no VAO e o que isso significa é o seguinte

o VAO pode ser configurado para ler 2 flutuadores por vértice (o que tornaria 2 vetores com duas dimensões x, y) ou você pode dizer ao vao para interpretá-lo como 1 vetor com 4 dimensões, ou seja, x, y, z, w etc.

mas também outros atributos desses dados são definidos e armazenados no VAO, como formato de dados (apesar de você ter declarado uma matriz de flutuação, você pode dizer ao shader para lê-lo como um número inteiro, é claro que o sistema converte os dados brutos em o processo de flutuar para inteiro e tem seu próprio conjunto de regras o que fazer em tais circunstâncias)

Então, basicamente, a VBO são os dados, e o VAO armazena como interpretá-los, porque os shaders e o servidor OpenGL foram projetados para serem muito curiosos e precisam saber tudo antes de decidir como processá-los, o que fazer com eles e onde Para colocá-lo

é claro que não é realmente intrometido, está realmente procurando ser mais eficiente porque precisa armazenar esses dados na memória do servidor gráfico para obter o processamento mais eficiente e rápido (a menos que decida que não precisa fazer isso se os dados não devem ser processados ​​dessa maneira e utilizados para outras informações que não são acessadas com frequência) e, portanto, por que os detalhes sobre o que fazer com os dados e como processá-los devem ser armazenados no VAO, portanto o VAO é como um cabeçalho e o VBO é como os dados brutos puros que o cabeçalho usa e define (nesse caso, passa para os atributos de vértice de sombreador), com a exceção de que o VBO não é limitado apenas para ser usado por um VAO, pode ser usado e reutilizado e vinculado a muitos VAOs, por exemplo:

o que você pode fazer é vincular um objeto de buffer ao VAO1 e também (separadamente) vincular o mesmo objeto de buffer ao VAO2, cada um interpretando-o de forma diferente, de modo que, se o seu shader processa os dados, dependendo de qual VAO é aquele vinculado, ele processaria os mesmos dados brutos de maneira diferente do frambuffer (desenhando pixels para janela), resultando em uma exibição diferente dos mesmos dados, com base em como você definiu seu uso no VAO

hopjopper
fonte
Esta é a melhor resposta!
CodingMadeEasy