Chapter 04 - Render a quad
Last updated
Last updated
In this chapter we will continue talking about how OpenGL renders things. We will draw a quad instead of a triangle and set additional data to the Mesh, such as a color for each vertex.
You can find the complete source code for this chapter here.
As we said at the beginning, we want to draw a quad. A quad can be constructed by using two triangles as shown in the next figure.
As you can see each of the two triangles is composed of three vertices. The first one formed by the vertices V1, V2 and V4 (the orange one) and the second one formed by the vertices V4, V2 and V3 (the green one). Vertices are specified in a counter-clockwise order, so the float array to be passed will be [V1, V2, V4, V4, V2, V3]. Thus, the data for that shape could be:
The code above still presents some issues. We are repeating coordinates to represent the quad. We are passing twice V2 and V4 coordinates. With this small shape it may not seem a big deal, but imagine a much more complex 3D model. We would be repeating the coordinates many times, like in the figure below (where a vertex can be shared between six triangles).
At the end we would need much more memory because of that duplicate information. But the major problem is not this, the biggest problem is that we will be repeating processes in our shaders for the shame vertex. This is where Index Buffers come to the rescue. For drawing the quad we only need to specify each vertex once this way: V1, V2, V3, V4). Each vertex has a position in the array. V1 has position 0, V2 has position 1, etc:
V1 | V2 | V3 | V4 |
---|---|---|---|
0 | 1 | 2 | 3 |
Then we specify the order in which those vertices should be drawn by referring to their position:
0 | 1 | 3 | 3 | 1 | 2 |
---|---|---|---|---|---|
V1 | V2 | V4 | V4 | V2 | V3 |
So we need to modify our Mesh
class to accept another parameter, an array of indices, and now the number of vertices to draw will be the length of that indices array. Keep in mind also that now we are just using three floats for representing the position of a vertex, but we want to associate the color of each one. Therefore, wee need to modify the Mesh
class like this.
After we have created the VBO that stores the positions, we need to create another VBO which will hold the color data. After that we create another one for the indices. The process of creating that VBO is similar but the previous ones but notice that the type is now GL_ELEMENT_ARRAY_BUFFER
. Since we are dealing with integers we need to create an IntBuffer
instead of a FloatBuffer
. The VAO will contain now three VBOs, one for positions, the other one for colors and another one that will hold the indices and that will be used for rendering.
After that, we need to change the drawing call in the SceneRender
class to use indices:
The parameters of the glDrawElements
method are:
mode: Specifies the primitives for rendering, triangles in this case. No changes here.
count: Specifies the number of elements to be rendered.
type: Specifies the type of value in the indices data. In this case we are using integers.
indices: Specifies the offset to apply to the indices data to start rendering.
Now we can just create a new Mesh with the extra vertex parameters (colors) and the indices in the Main
class:
Now we need to modify the shaders, not because of the indices, but to use the color per vertex. The vertex shader (scene.vert
) is like this:
In the input parameters, you can see we receive a new vec2
for the color and we just return that to be used the fragment shader (scene.frag
) which is like this:
We just use the input color parameter to return the fragment color. It is important to notice, that the color value will be interpolated when using in the fragment shader, so the result will be something like this.