# Introduction

OpenGL is complicated. Whereas SDL2 is relatively small with a few objects and functions, OpenGL is huge with lots of different elements. Fortunately it’s also very well documented. And, as we saw in the previous part, it’s not hard to get something on the screen ( thanks to SDL2 )

In this part, we’ll first take a look at vertexes before we look at how to draw a simple object.

# Drawing an object in 3D

Now that we’ll be working in 3D, we need to do things a little differently. In SDL2 we only used the position and size of each object. Each object was basically just an image that we drew on the screen and moved around. We never told SDL2 anything about how it looked, how big it was, etc. SDL2 simply took a texture and put it on the screen.

But in OpenGL we’ll be rendering an except shape so that we can view it from any angle, which would be almost impossible in SDL2. It also enables us to color it, apply textures and change the lighting in code. We do this by defining a mesh like you see above. It’s all just a bunch of points in 3D space defined by vectors. A vector in this context is just a simple mathematical unit that defines a position. We’ll be using 3D ones, so they’ll each have three values ( x, y, z ) When we have these vectors we can tell OpenGL the exact shape of an object, and then we can draw it in 3D using OpenGL

### Vertex vs vector

In OpenGL we use something called a vertex. A vertex is a lot like a vector in that in represents a single point. The difference between a vertex and a vector is that a vector is just the position of a single point. But a vertex contains the vector of the point and it can also hold other things at the same time, like the color of that point, and other things we’ll come to in a later part. So, in essence, a vertex contains everything we need to draw one of these points. And when we draw an object, like a dice, we need to give OpenGL one vertex for each point.

The dice about has 8 vertexes :

• left, top, front
• left, bottom, front
• right, bottom, front
• right, top, front
• left, top, back
• left, bottom, back
• right, bottom, back
• right, top, back

Each part of the vertex is usually referred to as an attribute. For instance the vectors/positions is one attribute, colors is another attribute and so on…

### OpenGL programming method

In contrast to other APIs / libraries, OpenGL is not object oriented. There’s really no objects at all, mostly because a lot of the vertex data is stored on the GPU. So instead you need to handle the models, textures, etc on our own.

OpenGL does, however, have some notion of object. But instead of being a concrete struct like SDL_Texture as we have in SDL2, it’s just an ID to a type of data. The only way to refer to this data through OpenGL is by using ID’s. This is mostly because the objects are stored on the GPU, and you want to keep them there without transferring/streaming them back and forth.

So let’s take a look at two of the most important objects we’ll be using in OpenGL.

# VBO – Vertex Buffer Object

The VBO(Vertex Buffer Object) is one of the “objects” of OpenGL. It holds all of a single vertex attributes for an object. Not all vertexes, but all vertexes of one type, like all positions or all colors. So you’ll end up with one VBO for positions, one VBO for colors, etc…

In order to create a VBO, we first need some data. So let’s take a collection of vectors and put them in a VBO. To keep things simple, we’ll just use a square. Our square has four positions, one of each corner. Let’s create a simple array containing all of these points.

That’s the simple part. Now we need to tell OpenGL to create the actual VBO for us. This requires a few steps so let’s look at them one at the time.

### glGenBuffers

This function generates a VBO for us, so that we can store our vertex attribute into it. It also gives us back an ID for this buffer so that we can use it for referring to this VBO later.

Note : GLsizei is simply just an unsigned integer like uint32_t and GLuint is just a signed integer like int32_t

Parameters :

• GLsizei n – the number of buffer we want. One per attribute, so we’ll keep it at 1. But if we were going to add colors, we’d use 2.
• GLuint* buffers – this is were we get the ID’s of our buffers back as an array.

So now, let’s generate our VBOs :

The second line creates an array for holding our ID’s and the third line tells OpenGL to allocate countVBOs VBOs for us. Since arrays works a lot like pointers in C++, we can just pass in vbo, and OpenGL will automatically give us as many IDs as we ask for.

Now we have our VBO and it has the ID stored in vbo[0]

### glBindBuffer

This function is deceptively simple, so it’s important to understand it because it can lead to some confusion. And if you call it at the wrong time or don’t call it, your application will most likely crash!

The function simply sets a buffer as the current buffer. We use it to tell OpenGL that this is the buffer we are working on now.

Parameters :

• GLenum target target – the type of buffer we want this to be. In our case, it’s GL_ARRAY_BUFFER
• GLuint buffer – the ID of the buffer we want to bind / set as active

You might have notices the new type, GLenum. This is just a huge enum that contains all the predefined flags in OpenGL. These flags are used by a lot of different functions for a lot of different things, so I’ll just explain them as they come.

GL_ARRAY_BUFFER is the value we use for vertex data like positions and colors.

Using it is really simple :

### glBufferData

Now that we have bound the buffer, we can tell OpenGL to store this data for us.

Now this might seem complicated, but it’s quite logical when you see what the parameters are for.

Parameters :

• GLenum target n – the type of buffer we want this to be. We’ll use the same as for glGenBuffers : "GL_ARRAY_BUFFER"
• GLsizeiptr size – the size of the data in bytes.
• const GLvoid* data – the data that should be stored
• GLenum usage – how the data should be used. We will just use GL_STATIC_DRAW which means we won’t be modifying it after this, we’ll only be using it for rendering.

The second argument, GLsizeiptr size, might seem a bit weird. First of all, what is a GLsizeiptr? Think of it as a very big integer. It’s basically a special type they used for when you need to store huge numbers. But don’t worry too much about this, we’ll be using it as a standard unsigned int.

The third argument, const GLvoid* data is a pointer to the data. A const GLvoid* ( or simply just void* ) is a pointer that can be pointing to anything. It can be floats, chars, ints, std::strings… Anything! So in reality, it doesn’t know anything about the data at all. This also means it doesn’t know the size either, which is why we need that second argument, GLsizeiptr size

Finally, here is how we’ll use it :

sizeof(GLfloat) simply gives us the size of a single GLfloat. So we just multiply that by the number of individual GLfloats in our array, square.

Here’s the entire code for setting up a VBO so that you can digest it all before moving on to the next part.

Now we have created a VBO but how do we render it? And what if we have more than just one VBO for the same object? Enter VAO, Vertex Array Object

# VAO – vertex array object

A VBO represents a single vertex attribute ( like positions or color ). A VAO is a lot like VBO, they’re used in the same way. The difference is that a VBO represents a single attribute, but a VAO can combine several attributes / VBOs so that we have all the vertex data in a single object. This is a lot simpler when it comes to rendering ; we can simply render the VAO, then move on to the next one without even thinking about the VBOs

We still need a VBO for every attribute though, and we need to put them into the VAO one by one until we have a single object. The VBOs is only needed for creating or updating the VAOs. All other times we just use the VAOs

### glGenVertexArrays

Think of this as glGenBuffers, only for VAOs. It generates a VAO for us to use later.

Here’s the signature :

The parameters are the exact same as for glGenBuffers so I won’t be going into them in any more depth.

Here’s how we’ll use it

### glBindVertexArray

Just like glGenVertexArrays is the VAO equivalent of glGenBuffer, glBindVertexArray is the VAO equivalent of glBindBuffer. So this function sets the VAO as the active one. Note that these are not mutually exclusive, we can have both a VBO and a VAO active at the same time.

Parameters :

• GLuint array – the ID of the vertex array to bind.

As you can see, this signature only has one argument. Why? Well in OpenGL there are several data we can store in a VBO, not just vertex data. But a VAO is more of a wrapper object for vertex data, so there is just one type.

Usage :

### glVertexAttribPointer

Now this is where things get a little complicated. This method is what associates our vertex data from the currently selected VBO with the current VAO. We use it to tell OpenGL were in the VAO the data from the current VBO should be stored.

Parameters :

• GLuint index – An ID we define that refers to this attribute. We’ll need this later so that we can refer to this vertex attribute
• GLint size – the number of values per attribute ( 1 to 4). In our case it’s 3 since our attributes have 3 values (x, y and z)
• GLenum type – the datatype the attributes are in. In our case it’s GL_FLOAT
• GLboolean normalized – whether the data should be normalized ( more on this in a later part. ) For now we’ll use GL_FALSE
• GLsizei stride – specifies an interval between vertex attributes. We don’t use that so we’ll just use 0 here
• const GLvoid * pointer – the starting point of the data to use. We don’t use this either, so we’ll just use 0 here as ell.

As you can see, it’s really not as bad as it looks. The fourth argument, normalized isn’t really important for us now. And the two last ones only deals with cases were we put several vertex attributes in the same array ( like if we put positions and colors ) in the same array.

The important thing here is that it puts a type of vertex attribute data form a VBO into a VAO. It uses the current active VAO and VBO, so we need to call glBindBuffer and glBindVertexArray first.

Here’s how we’ll be using it :

Note that if you haven’t called glBindBuffer() before calling this function, it won’t work properly and your application might crash.

### glEnableVertexAttribArray

After we’ve set up the VBOs and VAOs, we need to enable the attribute within the VAO because, by default, every vertex attribute array ( like our positions. ) are disabled. This means we’ll have to enable every vertex attribute we create and assign with glVertexAttribPointer. In our case, we just need to call it once since we are only enabling positions.

Parameters :

• GLuint index – The index of the vertex attribute array we want to enable.

With all of that out of the way, we can look at an example of how to set up a VBO and VAO :

Hopefully this wasn’t too bad. It’s important that you understand what a VBO is, what a VAO is, what their relation is and how to use them. Knowing this will save you from a lot of confusion and frustration in the future.

I placed the binding of the VAO and VBO in an awkward order to demonstrate the ordering of these functions. The ordering doesn’t matter as long as you bind the VBO before using glBufferData and glBindVertexArray before you call glVertexAttribPointer. Take a look in the code below for a better way of ordering these functions : )

Before we can get anything on the screen, we’ll need a shader. Shaders are small programs that runs on the actual GPU/graphics card. We only have to define a vertex shader. This shader deals with things like moving/rotating/scaling objects. We also have a framgment shader which deals with setting the correct colors.

I won’t be going any deeper into shaders than that this time. But we do need them, which means we also have to set them up properly. So I made a simple helper class that does all of that for us. I’ll post it below with the other code so you can copy it and get the example up and running. The next part will be about sharers and why we need them, so hopefully the code will make a bit more sense then.

# The code

The code consists of three pieces ; the main .cpp file were most of the code is, the Shader.h which is where all of the shader related code is, and the shaders ; the vertex shader ( tutorial2.vert ), and the fragment shader ( tutorial2.frag )

I have added setting of colors to the code, along with an example of glEnableVertexAttribArray. I hope it gives you a good idea of how to use these functions. In the next part we’ll take a close look at the shader, how to set them up and how to write our own.

The code is take from here. Though I have changed it quite a lot.

### main.cpp

Here is our main file :

As you can see, it also sets color. It does this in the same way as it sets positions. I added it to further demonstrate how to bind the buffers correctly.

Here is the shader helper file. Don’t mind it too much, I’ll go into more detail about how it works the next time.

### tutorial2.vert

This is our first shader, the vertex shader. Make sure you name it tutorial2.vert and put it along with the other files

### tutorial2.frag

And finally, the fragment shader. Make sure you name it tutorial2.frag and put it along with the other files

### Compiling

Using clang

clang++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

Using gcc/g++

g++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

# Conclusion

Finally we have something on the screen! The process is a bit tedious and not 3D yet. But we’ll be going into 3D territory soon. And that’s when things get really cool.

I hope this tutorial has helped you understand VBOs and VAOs along with the concept of vertexes. My goal is to go through things thoroughly, giving you a good understanding of how things work. The better you know how things work, the easier it will be to write code.

Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com

## 23 thoughts on “[OpenGL Part 2] Vertexes, VBOs and VAOs”

1. Trym says:

I tried copying your code, but the color data and position data seems to get mixed up. I just get a square in the upper right corner with some dark blue, cyan and violet. If I change the values in the ‘colors’ array I change the positions of the vertexes and if I change values in the ‘diamond’ array I change the colors.

However, if I switch the values of positionAttributeIndex and colorAttributeIndex I get the correct brightly coloured centered square.

Am I doing something terribly wrong, or is there a mixup in the code?

1. olevegard says:

Hello π

That’s weird. I just ran my code again and I got a colored square in the center. Did you copy paste my code, or did you do any changes? What OS are you running on? Might be some OpenGL implementation specific stuff I have overlooked …

1. Trym says:

I copy pasted your code without any changes. My OS is win10, and also I’m using glew 1.13.0 compiled for mingw.

However, I managed to fix it (even though I don’t know exactly what I’m doing as I’m a total beginner to opengl). I found that the mixup seems to happen in the shader, because when I comment out the shader.UseProgram() in the main file it renders the box and square in the correct position (except they are just plain white). So I looked around shader.h, and noticed the BindAttributeLocation function is unused. So I tried adding the following lines in Init() in shader.h, just below shaderProgram = glCreateProgram(); :

BindAttributeLocation(0, “in_Position”);
BindAttributeLocation(1, “in_Color”);

And now it works perfectly! Although I don’t know why I need those lines and you don’t.

1. olevegard says:

Nice catch! IThat was a slip from my part. I was probably testing what happens if you remove those lines. It seems what is happens is that the OpenGL implementation makes assumptions about what locations the attributes are in. So not having those lines is probably some form of undefined behavior.

The reason why you didn’t get any colors after removing  shader.UseProgram() is that since you don’t have any fragment shader, OpenGL doesn’t know what to do with the color.

Anyways; thanks for letting me know and for fixing my bugs for me π

2. Codarth says:

I had to change the version of the tutorial2.frag to 130 in order to make it work.
Error: “‘Precision qualifier’ is not supported proir to GLSL verson 1.30”

1. Lucas says:

Thanks that tip is worth gold!

3. nefarious says:

I am just trying to understand how OpenGL works so really, I Know Nothing :).

I copied and compiled and attempted to run the program and got the following error:

error: c51145: must write to gl_position

I am running on a Jetson TK1 with the code cross compiled from linux. I had to make 2 changes to the LoadXXShader changing char*src to const GLchar *src.

I got your tutorial 1 to work perfectly. Thanks for the awesome work,

4. Sean says:

The Shader compiling and linking seems irreparably borked–even with straight up copy-pasting / forking the repository, shader errors are still abundant–something about not outputting to gl_Position.

5. Yueqing says:

I guess the syntax of GLSL changed?

I can not get those shaders to compile on my mac.

1. Stefan says:

Correct indeed, see my comments, i got it working, compiled as

clang++ tutorial2.cpp -framework OpenGL -lGLEW -lSDL2 -std=c++11 -o Test

on OSX

6. I also had to change the version of tutorial2.frag to 130 to get it to work as expected.

const char* src = str.c_str();

It doesn’t appear that we _do_ actually need a non-const string.

1. Note that I’m running on Ubuntu Linux, so YMMV on other platforms.

7. Stefan says:

Thank you so much for the tutorial, awesome π

Just wanted to note I had to modify it a bit as well,

I decided to use #version 400 instead since it was complaining about syntax error for “attribute” in the shader, which is now deprecated and should instead be “in”.

#version 400

in_Color was bound to attribute index 1
in vec3 in_Position;
in vec4 in_Color;

out vec4 ex_Color;

void main(void) {
gl_Position = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
ex_Color = in_Color;
}

I also needed to modify the fragment shader as follows because “gl_FragColor” is also deprecated.

*** tutorial2.frag:

#version 400
precision highp float;

in vec4 ex_Color;
out vec4 fragColor;

void main(void) {
fragColor = vec4(ex_Color);
}

8. Eric Otoo says:

Hello this is ERIC, Am not new to opengl and i used to do my staffs in glfw but i friend told me SDL is nice but when i tried SDL color part work good but the vertex part is flicking me up. i get NO error but i dont see any shape on the screen. but when i draw that on glfw it works good why

Hey, first thanks very much for the tutorial π
Second, do you have any hints on how to make this shaders compile under macos sierra? If i leave everything as is, i get an “version X is not supported”. I tried with few different versions (130, 150, 140, 400) without any effect. I googled the problem and it seems it has something to do with core profile, however i failed to find good resource to figure out how to fix the problem…

neverming, turns out I was setting opengl attributes (context, version, etc) after creating sdl_window and that caused the problem π

10. Why not just sizeof(diamond) and sizeof(colors)
which they already did these calculations for us, also you could have put all attributes in 1 VBO with glVertexAttribPointer, instead of setting it’s last two values to **zeros** every time, that’s why they exist, NOT to leave them, you should teach your students how to use functions correctly, I’m not that beginner though cause I used to learn OpenGL before, there’s no need for glDisableVertexAttribArray in cleanup() since you’re already quitting and cleaning up the application, why use #version 150?, every PC these days can run at least #version 330 core which is better if you’re worring too much about the behavior of it on different devices, version 3.3 of OpenGL is modern and fixed, I prefer using SDL2 with GLAD anyways.

11. B15HOP says:

Mine compiles but I get a runtime error, without an actual error. Just a not responding after drawing the rectangle with different colour corners.