________________________________________
The first part of this is to be able to view some geometry, which starts with glew and glfw. I'm not really into openGL, but I will try to explain the difference (at least in my eyes). glew is your direct connection to openGL. When you need to send some data to openGL, glew is the thing that handles that. glfw, on the other hand, sort of handles the "front end" of an openGL application. If you use glut, glfw is extremely similar. glfw allows you to open windows and handle key and mouse input.
If you're reading this and plan on programming something with glew and glfw, here are some few tips that may save you some time:
- You must include glew.h before glfw.h.
- You must initialize glfw before glew (ie you need to call glfwInit() before glewInit())
- glew needs an existing context before it can be initialized. That means that you need make a window and call glfwMakeContextCurrent(your openGL window) before you call glewInit()
Someone that knows more about this can correct me if any of that is incorrect, but from my experience that seems to be the case. I should probably investigate it more, but frankly I'm just not that interested.
________________________________________
Now that we know a little bit about the setup, we can get to some of the more interesting things. 3D modeling is the basis for a lot of different things in graphics, so it's usually a good place to start. Let's say we want to view a mesh that you built in Maya (a commercial modeling software) in openGL. Something like this:
The most common way to output what is called an obj file of that model. Obj files contain a lot of information about a model, but we're going to focus on a few of them. Here is an example of an obj file for a cube:
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
f 1/1/1 2/2/2 3/3/3
f 3/3/3 2/2/2 4/4/4
f 3/3/5 4/4/6 5/5/7
f 5/5/7 4/4/6 6/6/8
f 5/5/9 6/6/10 7/7/11
f 7/7/11 6/6/10 8/8/12
f 7/7/13 8/8/14 1/9/15
f 1/9/15 8/8/14 2/10/16
f 2/2/17 8/11/18 4/4/19
f 4/4/19 8/11/18 6/12/20
f 7/13/21 1/1/22 5/14/23
f 5/14/23 1/1/22 3/3/24
Keep in mind that I've omitted some information, but this is pretty simple once you understand what all of these numbers mean. And you can also imagine how long obj files can get. Anyways, each row that begins with a "v" is a vertex of the model. Generally, if a model is built well, vertices are where edges meet or cross.
So once you have those vertices, you need to connect them into faces. In the case of this cube, there are 12 faces, which all happen to be triangles. If you look at the lines tat begin with "f" you can see 3 groups of 3 numbers on each line. In our case, we're only worried about the first number of each of the groups. So, for a line
a/b/c d/e/f g/h/i
We want to look at a, d, and f. Each face is made of a number of vertices, and which vertices make up a particular face are indicated by these numbers. So the first face of our is made of vertices 1, 2, and 3. Now you might wonder how do you know which vertex is 1 and so on. That number corresponds to the order of the vertices (ie, the first line that begins with "v" is vertex 1).
With that, you can load an obj file into what is colloquially called "triangle soup". That is, we know all of the face for the model, and which vertices correspond to each face, but there is no overall structure to the mesh. Triangle soup is enough for many different needs, but I like to have a little bit more structure, which bring us to the next part of this post - the half edge data structure.
________________________________________
I first learned about the half edge data structure in cis277. It's a pretty convenient way to order a mesh. It takes the triangle soup data (vertices and faces), and connects them with "half-edges". It's a bit hard to explain in text, so I'm going to show a diagram.
It's a bit complicated at first glance, but we'll take it slow. If you find A2 and B1, you can see where the half edge structure gets its name. Those two half edges make up that edge on the cube. Such a structure is called a "symmetric pair". Other examples of symmetric pairs are A3/D2, F1/E2, and E3/C1. These pairs connect the triangle soup that we got from just loading in the obj file.
The structure also stores some other information. For instance, you can see that each half edge, D1 for instance, is pointing to a vertex. D1 is pointing at the vertex near the center of the image. Each half edge stores what vertex it points to. Each half edge also stores a "next" half edge. On all of the faces, you can see that the arrows go a in counter-clockwise manner. So D1's next would be D2, whose next is D3, whose next is D1.
Now we have a good structure for our mesh, but we can't see it yet. That brings us to the dreaded vertex buffer object.
The structure also stores some other information. For instance, you can see that each half edge, D1 for instance, is pointing to a vertex. D1 is pointing at the vertex near the center of the image. Each half edge stores what vertex it points to. Each half edge also stores a "next" half edge. On all of the faces, you can see that the arrows go a in counter-clockwise manner. So D1's next would be D2, whose next is D3, whose next is D1.
Now we have a good structure for our mesh, but we can't see it yet. That brings us to the dreaded vertex buffer object.
________________________________________
Lol coming soon.
______________________________
Note: I write a lot of these blog posts for my friends and family outside of the graphics world. So if you know me from within that world and are wondering why I'm explaining seemingly simple stuff, that's because it's not so simple looking in!
--Jeremy
--Jeremy