Parte de la terminología es un poco fuera:
- A
Vertex Array
es sólo un array (típicamente un float[]
) que contiene datos de vértice. No necesita estar obligado a nada. No debe confundirse con un VAO Vertex Array Object
o, lo que voy a ir más tarde
- Un
Buffer Object
, comúnmente conocida como Vertex Buffer Object
al almacenar vértices, o VBO, para abreviar, es lo que está llamando a un Buffer
.
- No se guarda nada en la matriz de vértices,
glVertexAttribPointer
funciona exactamente como glVertexPointer
o glTexCoordPointer
funciona, solo en lugar de atributos con nombre, se obtiene un número que especifica su propio atributo. Pasa este valor como index
. Todas sus llamadas al glVertexAttribPointer
se ponen en cola para la próxima vez que llame al glDrawArrays
o al glDrawElements
. Si tiene un VAO encuadernado, el VAO almacenará la configuración para todos sus atributos.
El problema principal aquí es que está confundiendo los atributos de los vértices con los VAO. Los atributos de vértice son simplemente la nueva forma de definir vértices, texcoords, normales, etc. para dibujar. Estado de la tienda VAO. Estoy primero va a explicar cómo funciona el dibujo con atributos de vértices, a continuación, explicar cómo se puede reducir el número de llamadas a métodos con VAOS:
- debe habilitar un atributo antes de poder utilizarlo en un shader.Por ejemplo, si desea enviar vértices a un sombreado, lo más probable es que lo envíe como el primer atributo, 0. Por lo tanto, antes de procesar, debe habilitarlo con
glEnableVertexAttribArray(0);
.
- Ahora que un atributo está habilitado, debe definir los datos que va a utilizar. Para hacerlo, debe vincular su VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- Y ahora podemos definir el atributo -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. En orden de parámetro: 0 es el atributo que está definiendo, 3 es el tamaño de cada vértice, GL_FLOAT
es el tipo, GL_FALSE
significa no normalizar cada vértice, los últimos 2 ceros significan que no hay zancada ni desplazamiento en los vértices.
- dibujar algo con él -
glDrawArrays(GL_TRIANGLES, 0, 6);
- La siguiente cosa que dibuje no puede utilizar el atributo 0 (de manera realista lo hará, pero este es un ejemplo), por lo que puede desactivarlo -
glDisableVertexAttribArray(0);
Wrap que, en glUseProgram()
llamadas y tiene un sistema de renderizado que funciona con sombreadores correctamente. Pero digamos que tiene 5 atributos diferentes, vértices, texcoords, normales, color y coordenadas de mapa de luz. En primer lugar, harías una sola llamada a glVertexAttribPointer
para cada uno de estos atributos, y tendrías que habilitar todos los atributos de antemano. Digamos que defines los atributos 0-4 como los tengo enumerados. Se podría permitir a todos ellos, así:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
Y entonces habría que unir diferentes OISCIV para cada atributo (a menos que todos ellos almacenar en una VBO y el uso compensaciones/paso), entonces usted necesita para hacer 5 diferentes glVertexAttribPointer
llamadas, desde glVertexAttribPointer(0,...);
hasta glVertexAttribPointer(4,...);
para vértices a coordenadas de mapa de luz, respectivamente.
Afortunadamente ese sistema solo tiene sentido. Ahora voy a pasar a los VAO para explicar cómo usarlos para reducir el número de llamadas a métodos al hacer este tipo de renderizado. Tenga en cuenta que usar un VAO no es necesario.
A Vertex Array Object
o VAO se utiliza para almacenar el estado de todas las llamadas glVertexAttribPointer
y las VBO que se identificaron cuando se realizaron las llamadas glVertexAttribPointer
.
Generas uno con una llamada al glGenVertexArrays
. Para almacenar todo lo que necesita en un VAO, conéctelo con glBindVertexArray
, luego realice una llamada completa al
. Todas las llamadas al enlace
son interceptadas y almacenadas por el VAO. Puede desenlazar el VAO con glBindVertexArray(0);
Ahora, cuando se desea dibujar el objeto, no es necesario volver a llamar a todos los une la VBO o los glVertexAttribPointer
llamadas, sólo tiene que obligar a la VAO con glBindVertexArray
luego llamar glDrawArrays
o glDrawElements
y dibujará exactamente lo mismo que si estuviera haciendo todas esas llamadas a métodos. Es probable que desee desvincular el VAO después también.
Una vez que desvincula el VAO, todo el estado vuelve a ser como era antes de vincular el VAO. No estoy seguro de que se mantengan los cambios que realice mientras se guarda el VAO, pero eso se puede resolver fácilmente con un programa de prueba. Creo que se puede pensar en glBindVertexArray(0);
como la unión a la VAO "por defecto" ...
Actualización: Alguien trajo a mi atención la necesidad de que la llamada de estirado real.Resulta que, en realidad, no necesitas hacer una LLAMADA COMPLETA cuando configuras el VAO, solo todas las cosas vinculantes. No sé por qué pensé que era necesario antes, pero ahora está arreglado.
"Objeto de búfer de vértice, o VBO (a veces denominado solo un Objeto de búfer)" A veces se lo llama así porque así es como se lo llama. Es solo un objeto de búfer, no diferente de cualquier otro objeto de búfer que pueda usar para bloques uniformes, transferencia de píxeles, comentarios de transformación o cualquier otro uso. La especificación de OpenGL * nunca * se refiere a algo como un "objeto de búfer de vértice"; incluso la [especificación de extensión original] (http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt) nunca lo llama así. –
Editado para que coincida con el nombre adecuado, gracias. –
Excelente respuesta. ¡Gracias por tomarte el tiempo de escribir esto! Sin embargo, hay un par de preguntas de seguimiento: (1) Usted dijo "antes de renderizar, y antes de definir el atributo, necesita habilitarlo con glEnableVertexAttribArray (0)" - ¿está seguro de que debe habilitarse antes de la llamada a ' glVertexAttribPointer'? En mis pruebas, el orden no parece importar. (2) Si lo entiendo correctamente, los atributos de vértice son globales, y solo su estado activado/desactivado se guarda en el VAO actualmente encuadernado. – mpen