¿Cuál es el papel de glBindVertexArrays vs glBindBuffer y cuál es su relación?


Soy nuevo en OpenGL y Programación Gráfica. He estado leyendo un libro de texto que ha sido muy completo y bien escrito hasta ahora.Sin embargo, he llegado a un punto en el código que no estoy muy entendiendo y me gustaría darle sentido a estas líneas antes de seguir adelante.

GLuint abuffer;

glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

El libro explica que las tres primeras líneas están creando un objeto vertex-array, que se utiliza para agrupar los datos asociados con un vertex array. La segunda línea encuentra un nombre no utilizado (estoy adivinando un identificador entero sin signo almacenado en abuffer) y la tercera línea crea el objeto / lo hace activo.

El libro explica que las líneas 4 a 7 crean un objeto buffer para almacenar nuestros datos, con la línea 5 que nos da un identificador no utilizado (similar a la línea 2 para el objeto de matriz de vértices?), la 6ª línea creando el búfer, y la 7ª línea asignando suficiente memoria en la CPU y creando un puntero a nuestros datos (puntos) para GL_STATIC_DRAW.

¿Qué significa ¿para que el objeto esté activo? ¿Cuándo utilizarías posteriormente abuffer? ¿Qué significa para una matriz de vértices agrupar datos asociados, y cuándo se asociaron los datos con este objeto de matriz de vértices?

Estoy confundido acerca de la relación entre abuffer y buffer. Estoy confundido acerca de cuál es la relación de la matriz de vértices con el objeto buffer, y en qué punto se forma esa relación. No estoy seguro de si están, de hecho, relacionados, pero se presentan en el libro de texto uno inmediatamente después de la otra.

Cualquier ayuda sería apreciada. Gracias.

 60
Author: Vallentin, 2014-02-09

5 answers

Desde una perspectiva de bajo nivel, puedes pensar en un array como si tuviera dos partes: {[14]]}

  • Información sobre el tamaño, la forma y el tipo de la matriz (por ejemplo, números de coma flotante de 32 bits, que contienen filas de vectores con cuatro elementos cada uno).

  • Los datos de la matriz, que es poco más que un gran blob de bytes.

A pesar de que el concepto de bajo nivel en su mayoría se ha mantenido igual, la forma en que se especifican los arrays ha cambiado varias veces año.

OpenGL 3.0 / ARB_vertex_array_object

Esta es la forma en que probablemente debería estar haciendo las cosas hoy. Es muy raro encontrar personas que no pueden ejecutar OpenGL 3.x y aún así tener dinero para gastar en su software.

Un objeto buffer en OpenGL es un gran blob de bits. Piense en el búfer "activo" como solo una variable global, y hay un montón de funciones que utilizan el búfer activo en lugar de usar un parámetro. Estas variables de estado globales son el lado feo de OpenGL (antes de acceso directo del Estado, que se trata a continuación).

GLuint buffer;

// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);

// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
//     opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

Ahora, el sombreador de vértices típico toma vértices como entrada, no una gran masa de bits. Por lo tanto, debe especificar cómo se decodifica el blob de bits (el búfer) en vértices. Ese es el trabajo de la matriz. Del mismo modo, hay una matriz "activa" que se puede pensar como una variable global:

GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
//     type = GL_FLOAT,
//     size = 4,
//     data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);

OpenGL 2.0 (la vieja manera)

En OpenGL 2.x, no había vértice matrices y los datos eran globales. Todavía tenías que llamar glVertexAttribPointer() y glEnableVertexAttribArray(), pero tenías que llamarlos cada vez que usabas un buffer. En OpenGL 3.x, sólo tienes que configurar la matriz una vez.

Volviendo a OpenGL 1.5, en realidad podría usar buffers, pero usó una función separada para enlazar cada tipo de datos. Por ejemplo, glVertexPointer() era para datos de vértices, y glNormalPointer() era para datos normales. Antes de OpenGL 1.5, no había búferes, pero podía usar punteros en su aplicación memoria.

OpenGL 4.3 / ARB_vertex_attrib_binding

En 4.3, o si tiene la extensión ARB_vertex_attrib_binding, puede especificar el formato del atributo y los datos del atributo por separado. Esto es bueno porque le permite cambiar fácilmente una matriz de vértices entre diferentes búferes.

GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
glVertexAttribFormat(loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib,      0);
glVertexAttribBinding(normal_attrib,   0);
glVertexAttribBinding(texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first!  Nice!
glBindVertexBuffer(0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);

OpenGL 4.5 / ARB_direct_state_access

En OpenGL 4.5, o si tiene la extensión ARB_direct_state_access, ya no necesita llamar a glBindBuffer() o glBindVertexArray() solo para establecer las cosas... usted especifica los arrays y buffers directamente. Solo necesita enlazar la matriz al final para dibujarla.

GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.

// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
glVertexArrayAttribFormat(array, loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib,      0);
glVertexArrayAttribBinding(array, normal_attrib,   0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);

// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);

ARB_direct_state_access es bueno por muchas razones. Puede olvidarse de vincular matrices y búferes (excepto cuando dibuja) para no tener que pensar en variables globales ocultas que OpenGL está rastreando por usted. Puede olvidarse de la diferencia entre "generar un nombre para un objeto" y "crear un objeto" porque glCreateBuffer() y glCreateArray() hacen ambas cosas en el a la misma hora.

Vulkan

Vulkan va aún más lejos y te hace escribir código como el pseudocódigo que escribí arriba. Así que verás algo como:

// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0;  // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]
 111
Author: Dietrich Epp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-20 03:54:23

Su interpretación del libro no es completamente correcta. Los objetos Vertex Array no almacenan datos. Son una clase de objetos conocidos como contenedores, como los Objetos Framebuffer. Puede adjuntar / asociar otros objetos con ellos, pero nunca almacenan datos por sí mismos. Como tales, no son un recurso de contexto compartible.

Básicamente los objetos de matriz de vértices encapsulan el estado de matriz de vértices en OpenGL 3.0. A partir de OpenGL 3.1 (en lugar de GL_ARB_compatibility) y OpenGL 3.2+ Perfiles de núcleo, debe tener un VAO distinto de cero enlazado en todo momento para que comandos como glVertexAttribPointer (...) o glDrawArrays (...) funcionen. El VAO enlazado forma el contexto necesario para estos comandos, y almacena el estado persistentemente.

En versiones anteriores de GL (y compatibilidad), el estado almacenado por VAOs era parte de la máquina de estados global.

También vale la pena mencionar que el enlace" actual " para GL_ARRAY_BUFFER es no uno de los estados que VAOs rastrear. Mientras que este enlace es utilizado por comandos como glVertexAttribPointer (...), VAOs no almacene la encuadernación, solo almacene punteros (el GL_ARB_vertex_attrib_binding extensión introducida junto con GL 4.3 complica esto un poco, así que vamos a ignorarlo por simplicidad).

VAOs do recuerde lo que está enlazado a GL_ELEMENT_ARRAY_BUFFER, sin embargo, para que los comandos de dibujo indexados como glDrawElements (...) funcionen como cabría esperar ( por ejemplo, VAOs reutilice el último elemento de matriz de búfer enlazado).

 13
Author: Andon M. Coleman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-08 23:08:34

La relación se crea cuando se llama a glVertexAttribPointer.

Resumen de VertexArrays

GL_VERTEX_ARRAY_BINDING y GL_ARRAY_BUFFER_BINDING son constantes pero pueden apuntar al estado global de la unión. Me refiero al estado no a la constante (naranja) en la imagen. Use glGet para encontrar acerca de diferentes estados globales.

VertexArray es agrupar información(incluido el búfer de matriz) sobre un vértice o muchos vértices paralelos.

Use GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING con glGetVertexAttrib para encontrar qué búfer de matriz de atributos se establece.

GlBindBuffer (GL_ARRAY_BUFFER establece el estado global GL_ARRAY_BUFFER_BINDING

GlBindVertexArray establece el estado global GL_VERTEX_ARRAY_BINDING

 5
Author: Jossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-23 06:22:51

OpenGL es una interfaz con estado. Es malo, anticuado y feo, pero eso es un legado para ti.

Un objeto de matriz de vértices es una colección de enlaces de búfer que el controlador puede usar para obtener los datos para las llamadas de dibujo, la mayoría de los tutoriales solo usan uno y nunca explican cómo usar múltiples VAOs.

Un enlace de búfer le dice a opengl que use ese búfer para métodos relacionados, en particular para los métodos glVertexAttribPointer.

 3
Author: ratchet freak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-06 14:08:24

No hay relación entre VertexArray y VBO.

Una matriz de vértices asigna la memoria en RAM y envía el puntero a la API. VBO asigna la memoria en la tarjeta gráfica-la memoria del sistema no tiene dirección para ella. Si necesita acceder a los datos de vbo desde el sistema, primero debe copiarlos desde vbo al sistema.

Además, en las versiones más recientes de OpenGL, los arrays de vértices se eliminan por completo (depcrecated en 3.0, eliminado en 3.1)

 -2
Author: Gasim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-08 22:47:14