Parte de la terminología está un poco fuera de lugar:
- A
Vertex Array
es solo una matriz (normalmente a float[]
) que contiene datos de vértice. No necesita estar vinculado a nada. No confundir con a Vertex Array Object
o VAO, que repasaré más adelante
- A
Buffer Object
, comúnmente conocido como Vertex Buffer Object
cuando se almacenan vértices, o VBO para abreviar, es lo que llama simplemente a Buffer
.
- Nada se guarda en la matriz de vértices,
glVertexAttribPointer
funciona exactamente como glVertexPointer
o glTexCoordPointer
funciona, solo que en lugar de atributos con nombre, puede proporcionar un número que especifica su propio atributo. Pasa este valor como index
. Todas sus glVertexAttribPointer
llamadas se ponen en cola para la próxima vez que llame glDrawArrays
o glDrawElements
. Si tiene un VAO vinculado, el VAO almacenará la configuración de todos sus atributos.
El problema principal aquí es que está confundiendo los atributos de vértice con los VAO. Los atributos de vértice son solo la nueva forma de definir vértices, texcoords, normales, etc. para dibujar. Estado de la tienda VAO. Primero voy a explicar cómo funciona el dibujo con atributos de vértice, luego explicaré cómo puede reducir la cantidad de llamadas a métodos con VAO:
- Debe habilitar un atributo antes de poder usarlo en un sombreador. Por ejemplo, si desea enviar vértices a un sombreador, lo más probable es que lo envíe como el primer atributo, 0. Por lo tanto, antes de renderizar, debe habilitarlo con
glEnableVertexAttribArray(0);
.
- Ahora que un atributo está habilitado, debe definir los datos que 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 o desplazamiento en los vértices.
- Dibuja algo con él -
glDrawArrays(GL_TRIANGLES, 0, 6);
- Es posible que lo siguiente que dibuje no use el atributo 0 (de manera realista lo hará, pero este es un ejemplo), por lo que podemos deshabilitarlo:
glDisableVertexAttribArray(0);
Envuelva eso en glUseProgram()
llamadas y tendrá un sistema de renderizado que funciona con sombreadores correctamente. Pero digamos que tiene 5 atributos diferentes, vértices, coordenadas de texto, normales, colores y coordenadas de mapa de luz. En primer lugar, realizaría una única glVertexAttribPointer
llamada para cada uno de estos atributos y tendría que habilitar todos los atributos de antemano. Digamos que define los atributos 0-4 como los tengo enumerados. Los habilitarías a todos así:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
Y luego tendría que vincular diferentes VBO para cada atributo (a menos que los almacene todos en un VBO y use compensaciones / zancadas), luego debe realizar 5 glVertexAttribPointer
llamadas diferentes , desde glVertexAttribPointer(0,...);
hasta glVertexAttribPointer(4,...);
para vértices hasta coordenadas de mapa de luz, respectivamente.
Con suerte, ese sistema solo tiene sentido. Ahora voy a pasar a los VAO para explicar cómo usarlos para reducir la cantidad de llamadas a métodos al realizar este tipo de renderizado. Tenga en cuenta que no es necesario utilizar un VAO.
A Vertex Array Object
o VAO se utiliza para almacenar el estado de todas las glVertexAttribPointer
llamadas y los VBO a los que se dirigió cuando se realizó cada una de las glVertexAttribPointer
llamadas.
Generas uno con una llamada a glGenVertexArrays
. Para almacenar todo lo que necesita en un VAO, vincúlelo con glBindVertexArray
y luego haga una llamada de extracción completa . Todas las llamadas de vinculación de dibujo son interceptadas y almacenadas por VAO. Puede desvincular el VAO conglBindVertexArray(0);
Ahora, cuando desee dibujar el objeto, no necesita volver a llamar todos los enlaces VBO o las glVertexAttribPointer
llamadas, solo necesita vincular el VAO con glBindVertexArray
luego llamar glDrawArrays
o glDrawElements
y estará dibujando exactamente lo mismo que si estaban haciendo todas esas llamadas a métodos. Probablemente también desee desvincular el VAO después.
Una vez que desvincula la VAO, todo el estado vuelve a ser como era antes de vincular la VAO. No estoy seguro de si se mantienen los cambios que realiza mientras la VAO está vinculada, pero eso se puede resolver fácilmente con un programa de prueba. Supongo que se puede considerar glBindVertexArray(0);
vinculante para el VAO "predeterminado" ...
Actualización: Alguien me llamó la atención sobre la necesidad de la llamada de sorteo real. Resulta que, en realidad, no necesita hacer una llamada de extracción COMPLETA al configurar el VAO, solo todas las cosas vinculantes. No sé por qué pensé que era necesario antes, pero ahora está arreglado.