Saturday, July 30, 2016

glBindBuffer





Name
glBindBuffer -bind a named buffer object.

C Specification
void
glBindBuffer(
    GLenum target
    , GLuint buffer
);


Description

glBindBuffer binds a buffer object to the specified buffer binding point. Calling glBindBuffer with target set to one of the accepted symbolic constants and buffer set to the name of a buffer object binds that buffer object name to the target. If no buffer object with name buffer exists, one is created with that name. When a buffer object is bound to a target, the previous binding for that target is automatically broken.



    By Dietrich Epp


From a low-level perspective, you can think of an array as having two parts to it:
  • Information about the size, shape, and type of the array (e.g., 32-bit floating point numbers, containing rows of vectors with four elements each).
  • The array data, which is little more than a big blob of bytes.
Even though the low-level concept has mostly stayed the same, the way you specify arrays has changed several times over the years.

OpenGL 3.0 / ARB_vertex_array_object

This is the way you probably should be doing things today. It is very rare to find people who can't run OpenGL 3.x and yet still have money to spend on your software.
A buffer object in OpenGL is a big blob of bits. Think of the "active" buffer as just a global variable, and there are a bunch of functions which use the active buffer instead of using a parameter. These global state variables are the ugly side of OpenGL (prior to direct state access, which is covered below).
GLuint buffer;
// Create a buffer
glGenBuffers(1, &buffer);
// Make the buffer the active array buffer
// i.e. opengl->array_buffer = buffer
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Upload a bunch of data into the active array buffer
// i.e. opengl->array_buffer = new buffer(sizeof(points), points, STATIC_DRAW)
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
Now, your typical vertex shader takes vertexes as input, not a big blob of bits. So you need to specify how the blob of bits (the buffer) is decoded into vertexes. That is the job of the array. Likewise, there is an "active" array which you can think of as just a global variable:
GLuint array;
// Create an array
glGenVertexArrays(1, &array);
// Make the array the active array
// i.e., opengl->vertex_array = array
glBindVertexArray(array);

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

OpenGL 2.0 (the old way)

In OpenGL 2.x, there weren't vertex arrays and the data was just global. You still had to call glVertexAttribPointer() and glEnableVertexAttribArray(), but you had to call them every timethat you used a buffer. In OpenGL 3.x, you just set up the array once.
Going back to OpenGL 1.5, you could actually use buffers, but you used a separate function to bind each kind of data. For example, glVertexPointer() was for vertex data, and glNormalPointer()was for normal data. Prior to OpenGL 1.5, there weren't buffers, but you could use pointers into your application memory.

OpenGL 4.3 / ARB_vertex_attrib_binding

In 4.3, or if you have the ARB_vertex_attrib_binding extension, you can specify the attribute format and the attribute data separately. This is nice because it lets you easily switch one vertex array between different buffers.
// Create and bind the array.
GLuint array;
glGenVertexArrays(1, &array);
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

In OpenGL 4.5, or if you have the ARB_direct_state_access extension, you no longer need to call glBindBuffer() or glBindVertexArray() just to set things up... you specify the arrays and buffers directly. You only need to bind the array at the end to draw it.
// Create the array, don't bind it.
// Instead of binding it, we pass it to the functions below.
GLuint array;
glGenVertexArrays(1, &array);

// 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(...);
Maybe ARB_direct_state_access is the way of the future, or maybe it's just a temporary stop on the way to something better (Mantle will almost certainly influence the next OpenGL standard). Either way, the ugly global variables are gone.

No comments:

Post a Comment