2012-01-02 20 views
86

Sólo quiere asegurarse de que entiendo esto correctamente (me gustaría pedir el SO de chat, pero es muerto ahí!):glVertexAttribPointer aclaración

Tenemos una matriz de Vertex, lo que hacemos "actual" por enlazándolo
entonces tenemos un buffer, que unen a una diana
entonces llenar ese objetivo a través de la cual glBufferData rellena esencialmente todo lo que se une a ese objetivo, es decir, nuestra Buffer
y luego llamamos glVertexAttribPointer que describe cómo se distribuyen los datos: los datos están vinculados a GL_ARRAY_BUFFER yt su descriptor se guarda en nuestro Vertex Array original

(1) ¿Es correcto mi entendimiento?
El documentation es un poco escaso sobre cómo se correlaciona todo.

(2) ¿Hay algún tipo de matriz Vertex predeterminada? Porque olvidé/omití glGenVertexArrays y glBindVertexArray y mi programa funcionó bien sin él.


Editar: me perdí un paso ... glEnableVertexAttribArray.

(3) es el vértice Attrib atado a la matriz de Vértice en el momento glVertexAttribPointer se llama, y ​​luego podemos activar/desactivar a través de glEnableVertexAttribArray attrib que en cualquier momento, independientemente de la matriz de Vertex está obligado actualmente?

O (3b) es el vértice Attrib ligado a la matriz de Vértice en el momento glEnableVertexAttribArray se llama, y ​​por lo tanto podemos añadir el mismo vértice Attrib a múltiples matrices Vertex llamando glEnableVertexAttribArray en diferentes momentos, cuando diferentes matrices de vértices están unidos, ?

Respuesta

195

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:

  1. 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);.
  2. 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);.
  3. 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.
  4. dibujar algo con él - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 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.

+9

"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í. –

+0

Editado para que coincida con el nombre adecuado, gracias. –

+3

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

2

La terminología y la secuencia de API a llamar es bastante confusa. Lo que es aún más confuso es cómo se asocian los distintos aspectos: el búfer, el atributo genérico de vértice y la variable de atributo de sombreado. Vea OpenGL-Terminology para una explicación bastante buena.

Además, el enlace OpenGL-VBO,shader,VAO muestra un ejemplo simple con las llamadas API necesarias. Es particularmente bueno para aquellos que pasan del modo inmediato a la tubería programable.

Espero que ayude.

Editar: Como puede ver en los comentarios a continuación, las personas pueden hacer suposiciones y sacar conclusiones precipitadas. La realidad es que es bastante confuso para principiantes.

+0

"* Consulte OpenGL-Terminology para obtener una explicación bastante buena. *" En menos de 1 minuto buscando, ya encontré una información errónea: "Estos se reemplazan con atributos genéricos de vértices con un identificador (llamado índice) que se asocia a una variable de sombreado (para cooordinates, color, etc.) que procesa el atributo ". No se llaman "índices"; son "ubicaciones". Esa es una distinción muy importante porque los atributos de los vértices [* también * tienen "índices"] (https://www.opengl.org/wiki/Program_Introspection#Attributes), que es * muy diferente * de las ubicaciones. Ese es un sitio web muy terrible. –

+1

Es un comentario justo pero no del todo exacto. Si observa la API OpenGL para definir un atributo genérico [glVertexAttribPointer] (https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml), 'void glVertexAttribPointer (índice GLuint, tamaño GLint, GLenum tipo, GLboolean normalizado, GLsizei stride, const GLvoid * puntero) ', el identificador se conoce como' index'. El mismo identificador en el contexto del programa se llama 'ubicación' en la API [glGetAttribLocation] (https://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml). –

Cuestiones relacionadas