OpenGL Programming
Buffer objects
Vertex Array Objects (VAO)
Contain attribute pointer information for a number of VBO and a single EBO.
When a VAO is bound, all vertex attribute calls will be stored in it, which means that we can quickly restore vertex attributes parameters to configure VBO and EBO. With this, we can quickly swich different vertex data and attributes by just binding a different VAO.
Vertex Buffer Objects (VBO)
Contain information that will be passed to the vertex shader. Normally we would like to send vertex positions, as well as color information or UV coordinates to be used for a given vertex.
The VBO is just a buffer of raw memory, to interpret the contents in the buffer, we need the vertex attributes glVertexAttribPointer
. Vertex attributes contain information about the size of the elements in the buffer, the number of elements per vertex, the type and the stride of those elements. OpenGL guarantees that per shader we can have at least 16 4-dimensional vertex attributes (16 * 4 * sizeof(float)
). Some hardware might allow for more, and if so you can query this with: glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &n_vertex_attribs);
Element Buffer Objects (EBO)
Using EBO, we can index vertices in a VBO to remove redundant vertices and extra overhead.
- Create with
glGenBuffers(1, &EBO)
- Bind with
glGenBuffers(GL_ELEMENT_ARRAY_BUFFER, EBO)
- Send index data with
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW)
- Draw with
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glDrawElements(GL_TRIANGLES, N_VERTICES, GL_UNSIGNED_INT, 0)
Projection matrices
A point or vertex goes through several transformation before ending up in the screen. First the model and projection matrices move the point to clip space. Clipping occurs on the on the unit cube, leaving a certain “guard band”. When clipping, new triangles may be generated to keep the overall geometry of the mesh. The resulting points after clipping will be moved to screen coordinates, where rasterization will happen.
No perspective (Model coordinates in NDC).
Mat4 model = vm_identity();
Mat4 view = vm_identity();
Mat4 projection = vm_identity();
Orthographic projection.
- Model is 100x100 units, with origin/center on the lower left corner.
- View translates the model so that the bottom corner is located at the lower left corner.
- Projection matrix is an orthogonal canvas of 400x400 units.
Mat4 model = vm_scale(vm_identity(), (Vec3){100.0f, 100.0f, 1.00f});
Mat4 view = vm_translate(vm_identity(), (Vec3){50.0f, 50.0f, 0.0f});
Mat4 projection = vm_ortho(0.0f, 400.0f, 0.0f, 400.0f, 0.0f, 1.0f);
Perspective projection.
- Model in NDC is rotated -55 degrees around the X axis. Because OpenGL is right handed, a negative rotation in this case means that we are ‘titling’ the plane ‘backwards’ (Further away on the top).
- View translates the model backwards slightly so that we can see it properly after the perspective projection.
- Projection matrix is a perspective frustrum with a fovy of 45 degrees, aspect ratio of 4:3, and near far plane at 100.0.
// Y
// |
// |
// |---------- X
// /
// /
// Z
Mat4 model = vm_rotate(vm_identity(), (float)glfwGetTime() * 50.0f, (Vec3){0.5f, 1.0f, 0.0f});
Mat4 view = vm_translate(vm_identity(), (Vec3){0.0f, 0.0f, -3.0f});
Mat4 projection = vm_perspective(45.0f, 800.0f/600.0f, 0.1f, 100.0f);
OpenGL command buffers
To provide a cohesive abstraction layer for graphics between different APIs, we need to be able to map lower level concepts to higher level APIs. Unfortunately OpenGL doesn’t have access to command buffers, but emulation should be possible.