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?
Respostas:
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
porque você precisa vincular o VBO para especificar os locais dos atributos.
Então, você deve fazer assim:
Você pode alterar os dados do VBO quando quiser, mas deve vinculá-lo antes.
E o desenho deve ficar assim:
Como você deve ter notado, removi
unbind
chamadas 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.fonte
gl{Enable|Disable}VertexAttribArray()
), seus valores padrão (glVertexAttrib*()
), seu modo de instanciamento (glVertexAttribDivisor()
) e provavelmente outra coisa.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
glVertexAttribPointer
mais o buffer vinculado a Vertex_Array_buffer no momento da chamadaglVertexAttribPointer
e 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.
fonte
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
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
fonte