OpenGL: ¿Es posible usar VAO sin especificar un VBO?

12

En todos los tutoriales que puedo encontrar sobre VAO (Vertex Array Objects), muestran cómo usarlos configurando atributos de vértice y vinculando un VBO (Vertex Buffer Object). Pero quiero crear un VAO que se configure para un conjunto de VBO en combinación con un sombreador fijo, donde cada búfer use el mismo patrón de datos (vértice, uv, color, etc.). Por lo tanto, quiero crear un VAO para varios VBO que se dibujarán con un sombreador.

No pude encontrar ninguna demostración de esto, así que decidí probarlo. Pero no funciona y se bloquea en la glDrawArrayllamada. Parece que el VBO no está vinculado. Aquí está el código que estoy usando:

Representación:

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

Creación de 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);

Donde lses un simple structque contiene las ubicaciones de los atributos.

En la parte de Renderizado, intercambiar el glBindBuffery el glBindVertexArrayOESentorno tampoco funcionó.

Entonces, la pregunta es: ¿es posible hacerlo, o tendré que crear un VAO para cada búfer? Y si tengo que crear un VAO para cada VBO, ¿es posible actualizar los datos del VBO glBufferSubDataen combinación con un VAO?

Martijn Courteaux
fuente

Respuestas:

18

Los VAO no contienen el estado "glBindBuffer", con la excepción del GL_ELEMENT_ARRAY_BUFFERestado de enlace de '. Lo que no estás entendiendo es que glBindBuffer(GL_ARRAY_BUFFER) no hace nada . Bueno, no hace nada en lo que respecta al renderizado. Intentalo; justo antes de llamar a glDraw *, llame glBindBuffer(GL_ARRAY_BUFFER, 0); tu renderizado funcionará bien.

La forma en que glVertexAttribPointerfunciona es que analiza lo que está vinculado a GL_ARRAY_BUFFER en el momento en que glVertexAttribPointerse llama . No en el momento de render. Después no. Justo en ese momento exacto. Toma cualquier objeto de búfer que haya allí y lo almacena en otra parte del estado de OpenGL, que está encapsulado dentro del VAO.

En general, tiene dos opciones, una de ellas nueva y que probablemente no debería usarse en este momento.

Su primera opción es colocar todos los objetos que usan el mismo formato de vértice (es decir, todo excepto el objeto de búfer y el desplazamiento) en el mismo objeto de búfer. Básicamente, construya una matriz gigante que contenga todos los vértices de todos los objetos que usen el mismo formato.

Cuando llega el momento de renderizar, puede renderizar una parte de los vértices. glDrawArraystoma una variedad de elementos para renderizar, y puede ajustar sus índices glDrawElementspara hacer lo mismo. Alternativamente, puede usar glDrawElementsBaseVertexpara sesgar los vértices , de modo que se agregue un desplazamiento a cada índice. Este desplazamiento es el número de vértices antes de ese vértice en la gran matriz.

La otra alternativa es utilizar el sistema de separación de atributos de formato relativamente nuevo agregado en GL 4.3. Le permitiría cambiar los búferes sin restablecer el formato. Por lo tanto, vincularía un solo VAO, luego simplemente sustituirá en diferentes buffers según sea necesario glBindVertexBuffer. Esto también está disponible en ES 3.1.

Nicol Bolas
fuente
1
Los controladores NV GL4.3 ahora son de lanzamiento completo.
Maximus Minimus
Muchas gracias por explicar la forma en que funciona glVertexAttribPointer. Eso fue esclarecedor y explica por qué y cómo funciona.
Martijn Courteaux
5

El VAO almacena el estado glVertexAttribPointer. Cambiar el VAO no afecta el glBindBuffer actual, ni cambiar el glBindBuffer afecta el VAO. Solo la llamada glVertexAttribPointer afecta al VAO, al registrar el búfer en uso en la llamada.

Entonces la respuesta a tu pregunta es no.

Una opción si desea reducir la cantidad de objetos es colocar todos sus datos de malla en un VBO grande y especificar dónde viven los datos de malla en el VBO en la llamada glDrawArrays utilizando los argumentos 'primero' y 'contar'.

ccxvii
fuente
Todos los artículos en Internet sobre VAO muestran que vincular un VAO vincula automáticamente al VBO. Entonces, creo que un VAO es una configuración que contiene los estados glVertexAttribPointer y el estado glBindBuffer . Y sí, vincular un VBO cuando un VAO está vinculado cambia el VAO. Lo digo porque lo probé y efectivamente lo hace. ¿De dónde viene esta información?
Martijn Courteaux
2
@MartijnCourteaux: " Todos los artículos en Internet sobre VAO muestran que vincular un VAO vincula automáticamente al VBO " . No, no lo hacen. El OpenGL Wiki en la especificación de vértice no. De hecho, muéstrame un solo artículo en Internet que diga que cualquier glBindBufferestado excepto GL_ELEMENT_ARRAY_BUFFER se cambia al vincular un VAO.
Nicol Bolas
La otra respuesta explica bien cómo funciona el método glVertexAttribPointer. Utiliza el VBO enlazado en ese momento. ¡Tienes razón! Gracias, entiendo ahora mismo.
Martijn Courteaux