¿Qué estado se almacena en un objeto OpenGL Vertex Array Object (VAO) y cómo utilizo el VAO correctamente?

25

Me preguntaba qué estado se almacena en un OpenGL VAO. He entendido que un VAO contiene estados relacionados con las especificaciones de vértices de vértices almacenados (qué atributos están en los almacenamientos intermedios y qué almacenamientos están vinculados, ...). Para comprender mejor el uso correcto de los VAO, me gustaría saber exactamente qué estado tienen.


Cómo supongo que se deben usar VAO

A partir de ejemplos simples, he entendido que el uso correcto de VAO es el siguiente:

Preparar

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

Representación

Bind VAO
---- Draw
Unbind VAO

A partir de esto, supongo que al menos los enlaces de búfer de vértices y las especificaciones de atributos de vértice se almacenan en el VAO. Sin embargo, no estoy seguro de cómo este patrón de uso se extiende a situaciones donde entran en juego texturas (múltiples) y (múltiples) sombreadores. ¿El programa de sombreado activo está almacenado en el VAO? ¿Y los enlaces de textura (con sus configuraciones de muestreo / ajuste ) también se almacenan en el VAO? Lo mismo para los uniformes ?


Por lo tanto, mis preguntas son:

  • ¿Qué estado exacto se almacena en un OpenGL VAO ? (Enlaces de VBO, especificaciones de atributos, programa de sombreado activo, enlaces de textura, ajustes de muestreo / ajuste de textura, uniformes ...?)
  • ¿Cómo uso correctamente los VAO en una configuración de renderizado más compleja en la que intervienen texturas (múltiples) con configuraciones de muestreo / ajuste asociadas, (múltiples) programas de sombreado y uniformes?
Jelle van Campen
fuente
1
VAO almacena datos sobre ubicaciones de atributos de vértices. También almacena ID de VBO en los que están contenidos estos atributos. No necesita vincular VBO cuando dibuja algo, debe vincularlo antes de llamar a glVertexAttribPointer () cuando crea VAO.
HolyBlackCat

Respuestas:

18

VAO almacena datos sobre ubicaciones de atributos de vértices. (Y algunos otros datos relacionados con ellos) no
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms"tienen relación alguna con ellos .

Puede preguntar por qué no recuerda el enlace VBO. Debido a que no necesita vincular VBO para dibujar algo, solo necesita vincularlo al crear VAO: cuando llama glVertexAttribPointer(...), VAO recuerda qué VBO está vinculado actualmente. Y VAO tomará atributos de estos VBO cuando lo dibujes, incluso si estos VBO no están vinculados actualmente.


Además, los VAO y VBO deben usarse de manera ligeramente diferente:

Esto no funcionará

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

porque necesita vincular VBO para especificar ubicaciones de atributos.

Entonces, deberías hacerlo así:

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

Puede cambiar los datos de VBO cuando lo desee, pero debe vincularlos antes.

Y el dibujo debería verse así:

Bind VAO
Draw


Como te habrás dado cuenta, eliminé unbindllamadas de tus listas. Son casi completamente inútiles y ralentizarán un poco su programa, por lo que no veo ninguna razón para llamarlos.

HolyBlackCat
fuente
99
"así que no veo razón para llamarlos". para evitar cambiarlos accidentalmente. Especialmente un problema cuando se usan bibliotecas de terceros.
monstruo de trinquete
Gracias por la gran respuesta! En resumen, el VAO solo almacena las ubicaciones de los atributos de vértice. Los VBO no se recuperan al vincular un VAO, ya que el VAO sabe en qué zonas de almacenamiento intermedio encontrar los atributos. Todos los demás estados están contenidos en el estado global de OpenGL.
Jelle van Campen
@JellevanCampen Sí, correcto. Para su información, también almacena el estado apagado / encendido de los atributos ( gl{Enable|Disable}VertexAttribArray()), sus valores predeterminados ( glVertexAttrib*()), su modo de instancia ( glVertexAttribDivisor()) y probablemente algo más.
HolyBlackCat
@HolyBlackCat ¿está seguro de que el estado predeterminado (glVertexAttrib ()) forma parte del estado VAO? La wiki de OpenGL afirma lo contrario, diciendo que son estados de contexto.
rdb
@ndb No, no estoy seguro. Esperaba que fueran parte del estado de VAO, y no lo comprobé.
HolyBlackCat
4

Solo almacena el enlace de vértice y el enlace del búfer de índice

Esos son todos los parámetros de glVertexAttribPointermás el búfer ligado a Vertex_Array_buffer en el momento de la llamada a glVertexAttribPointery el Element_Array_buffer vinculado.

Los uniformes son parte del programa actual.

Todo lo demás es un estado global.

En caso de duda, puede consultar las tablas de estado en la especificación de la versión que está utilizando.

monstruo de trinquete
fuente
Gracias por la respuesta también! Esto me aclara las cosas.
Jelle van Campen
4

Aquí hay una explicación simple pero efectiva, básicamente un objeto buffer tiene información que puede interpretarse como simples bits de datos sin procesar, que por sí solos no significan nada, por lo que es PURAMENTE los datos que se pueden ver de cualquier manera realmente

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

y la forma en que OpenGL fue diseñado para funcionar es que debe DEFINIR cómo serán los datos que va a pasar a los distintos sombreadores para los sombreadores

en el sentido de que también debe definir cómo leerá esos datos, en qué formato está, qué hacer con ellos y cómo se utilizará y para qué, toda esta información se almacena en el VAO

por ejemplo, puede declarar datos almacenados en una matriz como esta float vbo = {11.0,2.0,3.0,4.0}

lo que se requiere a continuación en este punto es cómo interpretar esos datos del VBO en el VAO, y lo que eso significa es lo siguiente

el VAO se puede configurar para leer 2 flotadores por vértice (lo que lo convertiría en 2 vectores con dos dimensiones x, y) o puede decirle al vao que lo interprete como 1 vector con 4 dimensiones, es decir, x, y, z, w, etc.

pero también otros atributos de esos datos se definen y almacenan en el VAO, como el formato de datos (a pesar de que declaró una matriz de flotante, puede decirle al sombreador que los lea como un entero, por supuesto, el sistema convierte los datos sin procesar en el proceso de flotante a entero y tiene su propio conjunto de reglas sobre qué hacer en tales circunstancias)

Básicamente, el VBO son los datos, y el VAO almacena cómo interpretar esos datos, porque los sombreadores y el servidor OpenGL están diseñados para ser muy curiosos y necesitan saber todo antes de decidir cómo procesarlos y qué hacer con ellos y dónde poner

por supuesto, no es realmente entrometido, en realidad parece ser más eficiente porque necesita almacenar esos datos en la memoria del servidor de gráficos para que obtenga el procesamiento más eficiente y rápido (a menos que decida que no necesita hacer esto si los datos no deben procesarse de esa manera y utilizarse para otra información a la que no se accede con frecuencia), y por lo tanto, los detalles de qué hacer con los datos y cómo procesarlos deben almacenarse en el VAO, por lo que el VAO es como un encabezado y el VBO es como los datos sin procesar puros que el encabezado usa y define (en este caso pasa a los atributos del vértice del sombreador) con la excepción de que el VBO no está limitado solo para ser usado por un VAO, puede usarse y reutilizarse y vincularse a muchos VAO, por ejemplo:

lo que puede hacer es vincular un objeto de búfer a VAO1 y también (por separado) vincular el mismo objeto de búfer a VAO2 con cada uno interpretándolo de manera diferente, de modo que si su sombreador procesa los datos, dependiendo de qué VAO sea el que sea enlazado, procesaría los mismos datos sin procesar de manera diferente al frambuffer (dibujar píxeles en la ventana), lo que daría como resultado una visualización diferente de los mismos datos que se basarían en cómo definió su uso en el VAO

hopjopper
fuente
¡Esta es la mejor respuesta!
CodingMadeEasy