# Introduction

So far we’ve only been dealing with 2D objects, we’ve also had a look at shaders. But we’ve only done stuff in two dimensions, now it’s time to make the step into the 3D world. In order to do this, there is a few things we need to do. The main thing is moving the object to the correct “space”. The spaces are an important, yet confusing, part of 3D rendering. Think of them as a separate coordinate system or a separate world. Any object has a coordinate in all of the spaces.

### Object space

In this part we’ll be making a cube and rendering it. To make our cube we need 8 coordinates which make up the 8 corners of the cube :

The center of the object is often `[0, 0, 0]`

and each of the vectors is usualy somgething close to zero. In our case, the cube has one corner that’s `[-1, -1, -1]`

and another one that’s `[1, 1, 1]`

and so on…

So basically, this is the coordinate that describe how the model looks.

### World space

Let’s look at the cube again. It needs to have a position that says where it is in the game world, so that it will appear in one specific spot. If you’ve ever used a map editing program, you can see the exact position of every object. This is the world space coordinates. When programming the gameplay elements like collision detection, this is the coordinate system we’ll be using. The idea behind it, is that every obejct has their own position in the world space, and that position is the same no matter how you look at it.

This is an example of a world space that has a cube close to the center and a player to the left of it. The example is for 2D worlds for simplicity, but it would be exactly the same in 3D, only with an extra dimension.

### View space / camera space

Whereas the world space location is universal and the same for everyone, the view/camera space is different. It basically tells where the objects are in relation to the player where the player is looking. It is similar to pointing a camera at an object. The center of the image would have the position

`[0, 0, 0]`

and every other coordinate is defined around that. These are known as camera or view space coordinates.
Compare the previous image with this. In the previous image, the cube ( `[-1, -1] `

) is to the left and behind the player ( `[-2, 0]`

). So if you look at it the world space from above, that’s how it looks. But if you look at it from the view space of the player, the player will be in the center, and the cube ( which is still at ( `[-1, -1]`

in world space ) will be to the right. Note that the object hasn’t moved around in the world and the player hasn’t moved either. All we did was looking at it with the player as the center instead of the center of the world as the center.

Another thing about the camera space is that it’s going to be relative to the direction the player or camera is facing. So imagine the player is looking along the x-axis ( towards the `world space center`

. ) Then the player starts rotating right. Soon he’ll see the object. Since he’s rotating right, he’ll see the object moving to his left. Now imagine him stopping. What he can see, is the world in his own view space. Another player at another location looking at another point would see the world in his own view space.

This might be a bit confusing, but it’ll get clearer soon.

### Projection space

Finally we have the projection space. This is a little different, it describes the final position on the screen the vertex will have. Unlike the other spaces, this is always a 2D coordinate, because the screen

*is*a 2D surface. You can look at this like the lens of the camera. The camera looks at a 3D world and the lens enables it to create a 2D image. You can look at it like the 2d version of the view space. When the camera looks at an object, it sees the view space. But what ends up on the screen is in 2d, and that is what we refer to as the projection space.

Just like cameras can have different lenses, so is there different ways of convert camera space coordinates to projection space. We will look at this later when we look at how to convert from space to space

### An illustration of view and projection space

Below is an illustration of the view and projection space. Hopefully it’ll help make things clearer :

The big pyramid is the view space. It’s all that we can see. In this case it’s just three cubes.

The 2d plane with the 3 cubes represented in 2d is the projection space. As you can see, it’s the exact same as the rest of the view space, only in 2d.

# Matrices

In order to transform the the vectors from one space to another, we use a matrix ( plural : matrices ). A matrix can be used to change an object in various ways, including moving, rotating and scaling. A matrix is a 2 dimensional mathematical structure, quite similar to a table :

\begin{bmatrix} 1\quad0\quad0\quad0 \\0\quad1\quad0\quad0 \\0\quad0\quad1\quad0\\0\quad0\quad0\quad1\end{bmatrix}

This is what’s called an `identity matrix`

. You can look at it like like a skeleton or an “empty” matrix. It won’t change the object at all. So when we intialize a matrix, this is what we initialize it to.

If we had initialized it to just `0`

for all values, it would have changed the object. We’ll look into the math involved for matrices in the next part. For now just remember than an idenity matrix is a default matrix that doesn’t change the object it’s used on.

Instead we’ll look at how to work with matrices. And for that purpose, we use `glm`

.

### glm

In order to do graphics programming, we will eventually need to do more mathematics stuff involving vectors and matrices. We really don’t want to do this manually, because there is lots of operations we’d have to implement ourselves. Instead, we’ll use a tried and tested library that does the mathematics operatiofor us.

`glm`

, or `OpenGL Mathematics`

, is a library made for doing the maths for graphics programming. It’s widely used and does just about everything we need. It is also 100% platform independent so we can use it on Linux, Windows and Mac.
### Installation

The libraries we have been dealing with up until now has required both header files, and library files.

`glm`

however, only requires header files. This makes installation very easy, even on Windows.
#### Linux + Mac ( the automatic way)

Both Linux and Mac might have

`glm`

available from package manager. If that’s the case, the process is the same as for `SDL`

. Just open the terminal and install `glm`

just like you would with any other program or package. If the package is not found, we need to “install” it ourselves.
#### Windows + ( Linux and Mac the slightly harder way)

If you’re on Windows ( or Linux / Mac and the first step didn’t work, ) we need to install the library ourselves. Fortunately this is relatively easy.

##### Downloading

The first step is to download

`glm`

. You can do that here.. Scroll to the bottom and download the format you want ( `.zip`

or `.7`

. ) If you have a tool for dealing with package files, you should have to problems extracting it. Windows has built in support for `.zip`

so choose this if you’re unsure. If none of the options work you can install winrar or 7zip.
##### Installing

Now extract the package anywhere you want and open the folder. You should find another folder name

`glm`

. In it there should be a lot of `.hpp`

files ( think of these as your regular header ( `.h`

) files. )
For Windows :

Take the folder name `glm`

( the one containing the `.hpp`

files ) and copy it to where you put the `SDL2`

header files so that it now contains both the `SDL2`

header file folder and the `glm`

header file folder. Once that’s done, you should be able to use it directly ( since we’ve already specified the folder with all our includes. )

For Linux and Mac:

Take the folder name `glm`

( the one containing the `.hpp`

files ) and copy it to `/usr/include/`

so that you end up with a folder called `/usr/include/glm/`

that contains all the `glm`

header files.

Since this is a system directory, you won’t be able to put them here the regular way. But there is a few options.

If your file browser has a `root`

mode, you can use that ( just be careful! )

If you can’t find it, you need to use the terminal ( after all, you are on Linux! )

You can use the `cp`

command to do this :

1 sudo cp [path_to_glm_folder] /usr/include -r

Most likely you can do it like this

1 sudo cp ~/Downloads/glm/glm /usr/include -r

`sudo`

is short for “Super User DO”. This is needed because it’s a system folder. `sudo`

basically tells the operating system that “I know what I’m doing” Use it with caution!

The `cp`

is the terminal command for copying.

The `-r`

option is short for `recursive`

it makes the `cp`

command also copy all the sub folders and their files ( wihtout it, it’ll only copy the files inside the `glm`

folders but it’d ignore all sub folders )

In order to make sure you got it right, run the command `sudo ls /usr/include/glm`

it should now list the `.hpp`

folders just like in the folder we looked at earlier.

1 sudo ls /usr/include/glm

( Please tell me if this doesn’t work on Mac, I haven’t been able to test it there yet… )

We can now include them in the same way as the `SDL2`

header files : `#include <glm/vec4.hpp>`

. And since `glm`

only uses header files, we don’t need to change our compile command!

# Using glm to do matrix operations

Using the OpenGL Matmetics library (

`glm`

) is quite easy. There’s just a few simple functions we need to do what we want.
First of all, it’s just a mathematics library, so there’s no initialization code. That means we can jump straight to the mathematical functions.

### Matricies and verticies

Fundamentally, vertecies and matricies are very simple constructions in

`glm`

. They’re just arrays with one element for each value. So a 3d vector has 3 elements, a 4d vector has 4 and so on. And similar for matrices.
A 3×3 matrix has a 9 element matrix. It’s arranged in a 2d array like so : `float matr33[3][3]`

and similarly a 4×4 matrix has 16 values and can look like this : `float matr4[4][4]`

. `glm`

uses `float`

types instead of `double`

but this can be changed if you want to.

Let’s have a look at the various functions we can use with the vectors in `glm`

### Creating a vector

The vector object in

`glm`

has several constructors, but we’re just gonna look at the simplest one :

1 glm::vec4(float value);

This will set all the values of the vector to `value`

. So

1 glm::vec4(1.3);

gives you the vector `[1.3, 1.3, 1.3, 1.3]`

### Creating an identity matrix

When it comes to matrices we will be dealing with several different types of matrices. First we’ll look at creating an identity matrix ( like we saw above )

The simplest type of matrix is the identity matrix ( as we saw above. ) There are two simple ways to making them :

12 glm::mat4( 1.0f );glm::mat4( );

Or for 3×3 matrices :

12 glm::mat3( 1.0f );glm::mat3( );

Both of these produce a idenity matrix, which you can look at as a default value for matricies. It can also be used for reseting a matrix.

### translatation matrix

In addition to identity matrix, we’ll be looking at

`translation matrices`

. A `translation matrix`

is used to move an object by a certain amount. Remember above when talking about world space we saw that each object needs its own position in the world space? This is what the translation matrix is for. We use it to move a single object to the position it’ll have in the world space. Every object in your game world needs to have a be moved to a position in the world space, and to move it we use a translation matrix.
In addition to translating ( or moving ) an object, we can also scale and rotate it. All of these operations that works on a single object is called the model matrix. We’ll be using the name model matrix, but wel’ll be looking at rotating and scaling in a later post.

### glm::translate

Here is how we use

`glm`

to create a translation matrix :

1234 glm::mat4 glm::translate(glm::vec3 d);

Parameters :

`glm::vec3 d`

– the distance to move

The `vec3`

vector specifies the distance to move in each direction. So, for instance, `[ 1, 0, -2 ]`

creates a matrix that can move an object

- 1 unit in x direction
- 0 units in y direction
- -2 units in z direction

If you specify the vector `[ 0, 0, 0 ]`

you’ll end up with a matrix that doesn’t translate the object at all. Nor does it change it in any way. So in effect you’ll end up with just a identity matrix.

Let’s look at a very simple example on how to create a translation matrix :

1 glm::mat4 model = glm::translate( glm::vec3( 3, 1, 5) );

So how do we use it? Well that’s a bit more complicated so we’ll look at this later in the post.

### view matrix

Now that we’ve placed the object in world space, we need to place it in the camera/view space. This is a bit more tricky because we need to set both position and where the camera is pointing.

It also has what’s called an up vector. This is used to set which direction is up vector. We’ll just leave it at `[0, -1, 0]`

which is the most common value. Since we won’t use it, it’s not something you need to read. But if you want to know more about it, check out the spoiler text

Think of it as how the camera itself is rotated. For instance, the camera could be turned up and down. Or tilted to the side. Doing so, would also change how the coordinate systems work Which is logical. If you turn the camera upside down, positive x would be towards the left and negative towards the right!

A possible use for this is if the player is hanging upside down. Then you could just change the up vector, which would rotate everything the player sees.

123456 glm::mat4x4 glm::lookAt c(vec3 position,vec3 center,vec3 up)

Parameters :

`glm::vec3 position`

– the position of the camera`glm::vec3 center`

– the direction the camera is facing ( first paragraph )`glm::vec3 up`

– the tilt of the camera ( second paragraph )

Here’s the setup we’ll use :

`position = [ 0, 0, -5 ]`

- x and y is at center, z is 5 units backwards

`eye = [ 0, 0, 0 ]`

- Looking straight ahead

`up = [ 0, -1, 0 ]`

- Upside-down, same as in
`SDL2`

- Upside-down, same as in

And here’s the code for creating that matrix :

123456 glm::mat4 view = glm::lookAt(glm::vec3(0, 0,-5), // Camera is at ( 0, 0, -5), in World Spaceglm::vec3(0, 0, 0), // And looks at the centerglm::vec3(0,-1, 0) // Camera is upside-down);

When we’re rendering the scene, we’ll multiply all vertexes by this matrix. When we do that, things will be moved like we saw above. `[ 0, 0, 0]`

is now what the camera is looking at ( like we saw above )

### projection matrix

The view matrix dictates the position and orientation of the game camera ( what will end up on screen. ) But there is another matrix we need in order to do 3d, the projection matrix.

Just like a camera can have many different lenses, so can a projection matrix be set up in different ways

1234567 mat4 glm::perspective(float const &fov, // Our field of viewfloat const &aspect, // Aspect ratio ( used for stretching the image to fit a screen ration )float const &near, // How far away from the camera things will be renderedfloat const &far // How close to the camera things will be rendered)

Parameters :

`float const &fov`

– the field of view ( how far out to the sides the player can see )`float const &aspect`

– same as screen formats ( 16:9, 16:10, 3:4, etc… ) Changing this will stretch the image.`float const &near`

– the closest to camera something can be. Anything closer will be cut off.`float const &far`

– the furthest away something can be. Anything further away will be cut off.

The `fov`

paramater is said to be spcified in degrees, and that’s what we’ll use. But it seems some have issues with `glm`

wanting radians instead. Radians is just an alternative to degrees. You can read more about it here.. So if it doesn’t work, you can try specifying `3.14 * 0.25 = 0.785`

for 45ยบ.

Tip : if you own Minecraft you can experiment with this by going to options and changing the fov there!

The `near`

and `far`

far arguments will cut whatever is smaller than `near`

or larger than `far`

. It doesn’t cut off whole vertexes, just the pixels than are not between `near`

and `far`

So, even though there are a few parameters here, they are relatively easy to comprehend. We’ll look more into how the actual matrix looks and what different types of projection matrices we can make ( yes, there are others ) in a later post.

Let’s take a look at a simple example

1234567 glm::mat4 projection = glm::perspective(45.0f, // 45ยบ field of view1920.0f / 1080.0f, // 16:9 aspect ratio0.1f, // Only render what's 0.1 or more away from camera100.0f // Only render what's 100 or less away from camera);

### Combining them

We can combine all the matrices into one, so that we only have to multiply each of the vertexes by one matrix instead of all three. But when doing matrix operations it’s important to notice that the operations are

**not**commutative. That means that the order in which you multiply them matters. This is in some cases very useful, but it can also lead to weird behavior.

In general, the order is left to right. The thing you want to happen first, should be the first part of your multiplication chain. Let’s assume we have three matrices. One for moving, one for scaling and one for rotating. If you wanted to scale, then rotate, then move, you’d do `mat = scale * rotate * move`

.

But… When it comes to the transitioning between spaces, it’s opposite! So we start out with the projection, then we multiply by view and then by model.

I won’t go into the details of why ( would take too long time ) but it’s important to remember this for later.

123456789101112131415161718 glm::mat4 model = glm::translate( glm::vec3( 3, 1, 5) );glm::mat4 view = glm::lookAt(glm::vec3(0, 0,-5), // Camera is at ( 0, 0, -5), in World Spaceglm::vec3(0, 0, 0), // And looks at the centerglm::vec3(0,-1, 0) // Camera is upside-down);glm::mat4 projection = glm::perspective(45.0f, // 45ยบ field of view1920.0f / 1080.0f, // 16:9 aspect ratio0.1f, // Only render what's 0.1 or more away from camera100.0f // Only render what's 100 or less away from camera);glm::mat4 modelViewProjection = projection * view * model;

I use the name `modelViewProjection`

because that’s the most common name for this matrix. It is also sometimes shortened to `mvp`

# Shaders and uniforms

Now that we know the basics of the matricies, we can finally have a look at how to use them in order to move objects, do projection and get something 3d on the screen. In order to do this, we must pass our matrix on to the shader. And this is where the benefit of having just one comes in. We can now just send one matrix for each object we are rendering, which means we have to send less to the GPU and the rendering will be faster.

Unifroms are global variables within the shader. It is a constant value so it does not change from rendering call to rendering call. You can’t actually change it from inside your shader at all. Doing so would cause a compiliation error. This is very practical because if there is an issue due to a `uniform`

, we know it’s being changed somewhere in our main source code.

### ID of a uniform

In order to be able to change a

`uniform`

in a shader from the source code, we need to have something to refer to it by. So in `OpenGL`

, your uniforms automatically gets an ID. This is usually just the order in which you declare them. But this again raises a different issue ; how do we get the ID of the `uniform`

on the shader. So we decalre an `uniform`

on the shader, now we need to change it from our source code. How do we get the ID? By using the function `glGetUniformLocation`

. Here’s what it looks like :

12345 GLint glGetUniformLocation(GLuint program,const GLchar *name);

Parameters :

`GLint location`

– The id of the shader program`const GLchar *name`

– The name of the variable in the shader

So if we have a shader that looks like this :

123456 in vec3 in_Position;in vec4 in_Color;uniform mat4 mvp;// ... Other shader stuff

We can get the value like this :

1 int matrixID = glGetUniformLocation(shaderProgramId, "mvp");

Quite simple. And now that we have the ID, we can move on to the next step

### Changing a uniform

A uniform can be any type of variable, a

`bool`

, and `int`

, a `float`

it can also be array type like vectors and matrices and even used defined structs! No matter what type, there is a group of functions we use for setting it, `glUniform*`

. We’ll go into more details about the ones for single values and vectors in a later part. Instead we’ll jump straight into the ones for setting matricies
### glUniformMatrix*

The function for setting a matrix in

`OpenGL`

is `glUniformMatrix`

. There are a lot of varieties of this depending on the type ( whether the induvidual values are ints or floats ) and size ( 4×4, 3×3, 2×3, 4×3, … ). To make this part shorter, we’ll only be focusing on the one we’ll actually be using, `glUniformMatrix4fv`

1234567 void glUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);

Parameters :

`GLint location`

– The location of the matrix ( the result of`glGetUniformLocation`

)`GLsizei count`

– The number of matrices. In most cases this will be`1`

`GLboolean transpose`

– Whether`OpenGL`

should transpose the matrix.See below`const GLfloat *value`

– The actual values of the matrix as an array

#### Matrix transpose

`OpenGL`

expects the matrix in a spcific way. But in some cases, we might have the matrix transposed ( or “rotated” ). So instead of :
\begin{bmatrix} 1\quad3\quad5\quad7 \\2\quad4\quad6\quad8 \\3\quad4\quad5\quad6\\4\quad6\quad8\quad9\end{bmatrix}

It might look like this :

\begin{bmatrix} 1\quad2\quad3\quad4 \\3\quad4\quad4\quad6 \\5\quad6\quad5\quad8\\7\quad8\quad6\quad9\end{bmatrix}

The flag tells `OpenGL`

that it needs to transpose the matrix first. Note : Some versions of `OpenGL`

does not support this operation. In these cases the parameter must be set to false. This applies to `OpenGL`

for mobile devices, `OpenGL ES`

And now for an example

In the `vertex shader`

12345 // ...uniform mat4 mvp;// ...

And in your main source code :

12345678 void SetMatrix(const glm::mat4 mat){// Get the IDint matrixID = glGetUniformLocation(shaderProgram, "mvp");// Set the matrixglUniformMatrix4fv(matrixID, 1, GL_FALSE, &mat[0][0]]);}

Quite simple, and now the matrix is set and we can ( finally ) render 3d!

# The results

So now after all that work, let’s see what we ended up with….

What?! That’s not right, the colors are weird and the front is missing…

### The depth buffer

Remember from my previous part where I talked about the last step of the rendering piepline, per-sample operations?* I mentioned the depth test and how it determines if something is obscured / invisible and should not be rendered. What you see above is the consequence of not enabling the depth test.

( * : It was in there, but I forgot to mention it also checks if something is covered by another object. Sorry about that! )

Let’s take a close look at what’s happening, but this time we render one side of the cube at a time :

This is the front side of the cube. So far it all looks good!

Let’s draw the bottom…

Here’s the back and the bottom, and here’s where it goes wrong. The front should cover the bottom. But here the bottom is covering the front. This is because we don’t have depth test enabled so `OpenGL`

just draws the bottom on top of it.

Let’s look at the next steps and see what happens

Here we’ve added the the next side. If you compare with the inital part, this is what gets covered up. But why just this?

Let’s render the next triangle

Here we’ve added half of the front. From this we can see that it is covering the bottom and right sides.

Let’s render the next triangle ( the second half of the front )

It covers up everything. This is because it’s the last thing we drew, so it gets drawn last, on top of everything.

And if we now draw the sides…

… we end up with what we saw earlier. The back gets drawn and covers everything. Then the top and left sides gets drawn on top of that.

### Enabling depth test

Now let’s look at this with the depth test enabled

Here we’ve everything, including the front drawn the front. It completely covers the cube. It might seem wrong, all we can see is a blue square! But if we just move it a little…

.. we see that it actually IS a 3D object! Finally!

### The depth test

So how does all of this work? It’s quite simple. You can tell

`OpenGL`

to create a buffer ( think of it as a 2d array ) that has one value per pixel that says something about how far that pixel is from the camera.
Each time you draw something, `OpenGL`

checks the value for that pixel in the array. This way, `OpenGL`

can determine if what you’re trying to draw is closer to the camera than what’s already there. If it is, then the new pixel will be draw instead of the old one and the distance value in the buffer will be updated with the value of the new pixel. That way this buffer will always keep a buffer that contains the value of the information about the closest pixel that has been checked so far.

Here’s how it worked when we drew the front ( blue ) over the rest. For every pixel it compares the previous value ( left ) value with the current ( right ) value. In this case, the blue one is closer and is drawn over the yellow. This happens for every single pixel we try to draw. Luckily, `OpenGL`

is pretty quick at this.

### How to enable it

Enabling it is quite simple. There are two functions we need for that :

1234 void glEnable(GLenum cap)

Parameters :

`GLenum cap`

– the`OpenGL`

capability we want to enable. In our case its’s`GL_DEPTH_TEST`

.

This basic function is used for turning `OpenGL`

features on. You can see a full list of the possible values here.

### Setting the depth function

We also need to see how the depth comparison works

1234 void glDepthFunc(GLenum func);

Parameters :

`GLenum func`

– the function to use

Here we tell `OpenGL`

what function to use for depth testing. We will be using `GL_LEQUAL`

, you can find more information about it and the others here.

### Clearing the depth buffer

Finally, we need to tell

`OpenGL`

to clear the depth buffer for us. This is so that we can start we a clean slate every time we render. Without it, the depth test could fail because of leftover values making `OpenGL`

not render something that should have been rendered. We’ll be doing this in our `glClear`

function :

1 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );

The `|`

character is a way of combining the two values so that we clear `GL_DEPTH_BUFFER_BIT`

and `GL_COLOR_BUFFER_BIT`

in one call.

# The source code

For the source code, I’ve taken the liberty of organizing it a little. I made a helper class for shaders, one for rendering in general, and one for dealing with models and their model matrix. In addition, I included a class I use for input ( that uses SDL2. )

### Renderer

In charge of most rendering functionality :

- Creating and initializing windows
- Setting up
`OpenGL`

options - Setting up view and projection matricies

### Shader

A class that keeps track of Shaders.

- Can keep track of one
`shader`

of each type (`vertex`

,`geometry`

,`tesselation`

,`fragment`

. ) - Represents a single, whole
`shader program`

- Does everything needed to create a single
`shader program`

- Also used for setting
`uniforms`

like the`model view projection matrix`

### Model

A class that holds a single object. In our case this is the cube:

- creates VAO and VBO for the object from a file
- Keeps the model matrix, which contains the position / scale and roation of the object
- Keeps a reference to the
`Shader`

that the object uses - Has a Render() function so that it can set all the VAOs and VBOs and render itself

### EventHandler

This is a class I wrote some time for keeping track of

`SDL`

events like quit, button presses, mouse move, mouse position, etc… It is not dirctly related to `OpenGL`

, we just use it to make our interaction with `SDL`

a tiny bit easier.
### Math

A very simple Math helper class. It simply takes an

`EventHandler`

and creates a `vec3`

of the movement based on the arrow keys and `w`

and `s`

. So if you you press left, it’ll create a vector with a negative x value. This means that when we use `glm::translate`

with the vector as the argument, we’ll get a matrix that moves the object left. It’ll be the same for every direction. Pressing `w`

will move the object closer, `s`

will move it away “into the screen”.
### main.ccp

Controls everything.

- Initializes Renderer
- Creates a Shader
- Creates a Model
- Checks for keyboard events and tells Model to update matrix accordingly ( move or reset )
- Renders the Model by calling functions in
`Renderer`

As you can see, `main.cpp`

doesn’t do anything to `OpenGL`

. In fact, it doesn’t even include any `OpenGL`

or `SDL`

stuff. This is completely intentional. `main.cpp`

should only control stuff.

Since the code is quite long and too big to put in this post ( unless you really like scrolling! ) I’ve put it in the Github repo for this code.

I’ve also created a zip file in case you don’t want to deal with git. You can find it here.

### Compiling

Since we have the new

`.cpp`

file, `EventHandler.cpp`

, we need to add it to our compilation call :
For clang :

`clang++ main.cpp EventHandler.cpp -lSDL2 -lGL -lGLEW -std=c++11 -o Part4`

For gcc:

`g++ main.cpp EventHandler.cpp -lSDL2 -lGL -lGLEW -std=c++11 -o Part4`

And NOW we’ve covered everything we need to know in order to do basic 3d rendering. It has taken me a long time to write all of this and it is quite long. But I hope you enjoyed it and that it helps you understand 3d rendering. If not, feel free to ask, I’m happy to help if I can.

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