OpenGL: É possível usar VAOs sem especificar um VBO

12

Em todos os tutoriais que posso encontrar sobre os VAO (Vertex Array Objects), eles mostram como usá-los, configurando atributos de vértice e vinculando um VBO (Vertex Buffer Object). Mas eu quero criar um VAO que será configurado para um conjunto de VBOs em combinação com um sombreador fixo, em que cada buffer usa o mesmo padrão de dados (vértice, UV, cor, etc.). Então, eu quero criar um VAO para vários VBOs que serão desenhados usando um shader.

Não consegui encontrar nenhuma demonstração sobre isso, então decidi tentar. Mas não funciona e trava na glDrawArraychamada. Parece que o VBO não está vinculado. Aqui está o código que estou usando:

Renderização:

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

Criação 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);

Onde ls é um simples structque contém os locais dos atributos.

Na parte Rendering, trocando o glBindBuffere oglBindVertexArrayOES redor também não funcionou.

Então, a pergunta é: é possível, ou terei que criar para cada buffer um VAO? E se eu tiver que criar um VAO para cada VBO, é possível atualizar os dados do VBO usando glBufferSubDataem combinação com um VAO?

Martijn Courteaux
fonte

Respostas:

18

Os VAOs não contêm o estado "glBindBuffer", com exceção do GL_ELEMENT_ARRAY_BUFFERestado de ligação. O que você não está entendendo é que glBindBuffer(GL_ARRAY_BUFFER) não faz nada . Bem, isso não faz nada no que diz respeito à renderização. Tente; logo antes de chamar glDraw *, call glBindBuffer(GL_ARRAY_BUFFER, 0); sua renderização funcionará perfeitamente.

A maneira como glVertexAttribPointerfunciona é que ele olha o que está vinculado a GL_ARRAY_BUFFER no momento em que glVertexAttribPointeré chamado . Não no momento da renderização. Mais tarde não. Bem naquele exato momento. Ele pega qualquer objeto de buffer existente e o armazena em outra parte do estado OpenGL, que é encapsulado no VAO.

Em geral, você tem duas opções, uma delas nova e provavelmente não deve ser usada neste momento.

Sua primeira opção é colocar todos os objetos que usam o mesmo formato de vértice (ou seja, tudo, exceto o objeto de buffer e deslocamento) no mesmo objeto de buffer. Basicamente, crie uma matriz gigante que contenha todos os vértices para todos os objetos que usam o mesmo formato.

Quando chega a hora de renderizar, você pode renderizar uma parte dos vértices. glDrawArraysrequer vários elementos para renderizar e você pode ajustar seus índices glDrawElementspara fazer o mesmo. Como alternativa, você pode usar glDrawElementsBaseVertexpara desviar os vértices , para que um deslocamento seja adicionado a cada índice. Esse deslocamento é o número de vértices antes desse vértice na grande matriz.

A outra alternativa é usar o relativamente novo sistema de separação de atributos de formato incluído no GL 4.3. Isso permitiria que você alterasse os buffers sem redefinir o formato. Assim, você vincularia um único VAO e, em seguida, substituiria em diferentes buffers conforme necessário glBindVertexBuffer. Isso também está disponível no ES 3.1.

Nicol Bolas
fonte
1
Os drivers NV GL4.3 estão agora na versão completa.
Maximus Minimus
Muito obrigado por explicar como o glVertexAttribPointer funciona. Isso foi esclarecedor e explica por que e como funciona.
Martijn Courteaux
5

O VAO armazena o estado glVertexAttribPointer. A alteração do VAO não afeta o glBindBuffer atual, nem a alteração do glBindBuffer afeta o VAO. Somente a chamada glVertexAttribPointer afeta o VAO, gravando o buffer em uso na chamada.

Portanto, a resposta para sua pergunta é não.

Uma opção se você deseja reduzir o número de objetos é colocar todos os seus dados de malha em um VBO grande e especificar onde os dados da malha residem no VBO na chamada glDrawArrays usando os argumentos 'first' e 'count'.

ccxvii
fonte
Todos os artigos da Internet nos VAO mostram que a ligação de um VAO vincula automaticamente o VBO. Então, acho que um VAO é uma configuração que contém os estados glVertexAttribPointer e o estado glBindBuffer . E sim, vincular um VBO quando um VAO está vinculado altera o VAO. Estou dizendo isso porque testei isso e efetivamente o faz. De onde vêm essas informações?
Martijn Courteaux
2
@MartijnCourteaux: " Todos os artigos da Internet nos VAO mostram que vincular um VAO vincula automaticamente o VBO. " Não, eles não fazem. A Wiki do OpenGL na especificação de vértice não. De fato, mostre-me um único artigo na internet que diz que qualquer glBindBufferestado, exceto, GL_ELEMENT_ARRAY_BUFFER é alterado pela ligação de um VAO.
Nicol Bolas
A outra resposta explicou bem como o método glVertexAttribPointer funciona. Ele usa o VBO vinculado naquele momento. Você está certo! Obrigado, eu entendo agora.
Martijn Courteaux