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?
Respuestas:
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á
porque necesita vincular VBO para especificar ubicaciones de atributos.
Entonces, deberías hacerlo así:
Puede cambiar los datos de VBO cuando lo desee, pero debe vincularlos antes.
Y el dibujo debería verse así:
Como te habrás dado cuenta, eliminé
unbind
llamadas 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.fuente
gl{Enable|Disable}VertexAttribArray()
), sus valores predeterminados (glVertexAttrib*()
), su modo de instancia (glVertexAttribDivisor()
) y probablemente algo más.Solo almacena el enlace de vértice y el enlace del búfer de índice
Esos son todos los parámetros de
glVertexAttribPointer
más el búfer ligado a Vertex_Array_buffer en el momento de la llamada aglVertexAttribPointer
y 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.
fuente
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
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
fuente