It almost seems like the OpenGL consortium were given a limited set of words (
index) to define modern OpenGL technology and API. It is no wonder that many spend so much time trying to figure of these nuanced (cryptic) API and descriptions. The concept itself is not that difficult but the API makes it more challenging than it should be.
Basically OpenGL requires the following to render.
- Vertex data like coordinates, connectivity, color, normal, texture etc.
- Memory on the GPU to store the vertex data
- Shader program to process the vertex data
Before looking at how these are specified, a few terms have to be understood as it can lead to confusion.
The above mentioned vertex data are called vertex attributes. It includes coordinates and connectivity (shape) and color, normal, texture, etc. (properties).
Generic Vertex Attribute
In legacy OpenGL there were specific functions like
glColorPointer etc. to specify vertex attributes and its data layout. These are replaced with generic vertex attributes with an identifier (called
index in function
glVertexAttribPointer) that associates to a shader variable (by its attribute
location in the
program for coordinates, color etc.) that process the attribute.
Setting something as current (or active) in OpenGL is often referred to as binding (e.g.
glBindBuffer). This implies that subsequent function calls will operate on the bound object. Sometimes it could also mean a relation or association (e.g.
OpenGL is a state machine. You put it into various states (or modes) that then remain in effect until you change them. All subsequent API calls are based on, or applied to this state. For example,
- in legacy OpenGL, the current color is a state which applies to all rendering primitives until changed.
- in modern OpenGL, the current buffer (VBO) is a state to which all buffer operations are applied.
Name and Index
Name and Index are used quite interchangeably. Name does not mean a string identifier. Index does not mean that it has to be in a sequence. All these are just a means to uniquely identifying certain objects with a
GLunit. Many calls to bind or associate are done using the name/index but is very subtle.
Putting it all together
The initial steps are reasonably straight forward. Step (5) is key and the most subtle and confusing.
- Initialize the shader. The program has attribute variables which process the vertex data to produce the desired output. Each of the attribute variables are associated to a generic vertex attribute index with
glBindAttribLocation. The actual data for these variables are specified in (5).
- The client vertex array is defined in standard C/C++ language in the application CPU memory.
- Generate Vertex Buffer Objects (VBOs). Note that this only generates the “buffer names” which is just a
- Bind the buffer with
glBindBufferand copy the vertex data from the client array to the VBO with
- Create a generic vertex attribute with
glVertexAttribPointerto the bound VBO to define the data layout. Additionally it does something very subtle. The
indexof this generic vertex attribute should match the appropriate attribute variable
locationof the shader
glGetAttribLocation, as this sets up the relation for the program to access the attribute data.
Code snippet for the above steps are taken from OpenGL-VBO, Shader, VAO which discusses modern OpenGL in detail.
// Define a generic attribute id for coordinates GLuint VERTEX_ATTR_COORDS = 1; // Shader code "attribute vec3 aCoords" // Associate vertex attribute id to the attribute variable during shader init glBindAttribLocation(program, VERTEX_ATTR_COORDS_ID, "aCoords"); // Generate VBOs vboIds = new GLuint; glGenBuffers(4, vboIds); // Copy data from client memory to VBO glBindBuffer(GL_ARRAY_BUFFER, vboIds); // coordinates glBufferData(GL_ARRAY_BUFFER, sizeof(ave), ave, GL_STATIC_DRAW); // Get the id associated in the shader attribute variable // The association is set by glBindAttribLocation during shader init GLint coordsId = glGetAttribLocation(program, "aCoords"); // Create a vertex attribute that connects shader attribute variable to VBO glVertexAttribPointer(coordsId, nCoordsComponents, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(coordsId);
Whatever the reasons are for the poor and confusing terminology, we just have to deal with it. Hope this helps clarify some of those nuances. If you have any questions please post a comment.