• Homogeneous coordinates
  • Transformation matrices
    • An introduction to matrices
    • Translation matrices
    • The Identity matrix
    • Scaling matrices
    • Rotation matrices
    • Cumulating transformations
  • The Model, View and Projection matrices
    • The Model matrix
    • The View matrix
    • The Projection matrix
    • Cumulating transformations : the ModelViewProjection matrix
  • Putting information technology all together
  • Exercises

The engines don't move the send at all. The ship stays where it is and the engines move the universe effectually it.

Futurama

This is the single well-nigh important tutorial of the whole gear up. Be sure to read it at least 8 times.

Homogeneous coordinates

Until then, we just considered 3D vertices as a (x,y,z) triplet. Let's introduce w. We will now have (x,y,z,w) vectors.

This will exist more clear soon, just for at present, but remember this :

  • If w == 1, then the vector (x,y,z,1) is a position in space.
  • If due west == 0, then the vector (10,y,z,0) is a direction.

(In fact, remember this forever.)

What difference does this make ? Well, for a rotation, it doesn't change anything. When you rotate a signal or a direction, you get the same effect. All the same, for a translation (when you move the point in a certain direction), things are different. What could mean "translate a direction" ? Non much.

Homogeneous coordinates allow us to use a single mathematical formula to deal with these two cases.

Transformation matrices

An introduction to matrices

Simply put, a matrix is an array of numbers with a predefined number of rows and colums. For instance, a 2x3 matrix tin can look like this :

In 3D graphics nosotros will generally utilize 4x4 matrices. They volition permit usa to transform our (x,y,z,westward) vertices. This is done by multiplying the vertex with the matrix :

Matrix x Vertex (in this order !!) = TransformedVertex

This isn't as scary equally information technology looks. Put your left finger on the a, and your right finger on the x. This is ax. Movement your left finger to the side by side number (b), and your right finger to the next number (y). You lot've got by. Once over again : cz. Once again : dw. ax + by + cz + dw. You've got your new ten ! Exercise the same for each line, and you'll get your new (x,y,z,due west) vector.

Now this is quite boring to compute, an nosotros will exercise this often, so let's inquire the figurer to do it instead.

In C++, with GLM:

                          glm              ::              mat4              myMatrix              ;              glm              ::              vec4              myVector              ;              // fill myMatrix and myVector somehow                            glm              ::              vec4              transformedVector              =              myMatrix              *              myVector              ;              // Again, in this order ! this is important.                                    

In GLSL :

                          mat4              myMatrix              ;              vec4              myVector              ;              // fill myMatrix and myVector somehow                            vec4              transformedVector              =              myMatrix              *              myVector              ;              // Yep, information technology's pretty much the same than GLM                                    

( have you cut'n pasted this in your code ? continue, endeavour it)

Translation matrices

These are the most simple tranformation matrices to understand. A translation matrix look like this :

where X,Y,Z are the values that yous want to add to your position.

So if we desire to interpret the vector (10,10,10,1) of 10 units in the Ten management, we get :

(do it ! doooooo information technology)

… and we become a (20,10,10,1) homogeneous vector ! Remember, the 1 means that it is a position, non a direction. And so our transformation didn't modify the fact that we were dealing with a position, which is expert.

Let's now see what happens to a vector that represents a direction towards the -z axis : (0,0,-one,0)

… ie our original (0,0,-1,0) direction, which is bully because as I said ealier, moving a management does not make sense.

So, how does this interpret to code ?

In C++, with GLM:

                          #include <glm/gtx/transform.hpp> // afterwards <glm/glm.hpp>                            glm              ::              mat4              myMatrix              =              glm              ::              interpret              (              glm              ::              mat4              (),              glm              ::              vec3              (              10.0              f              ,              0.0              f              ,              0.0              f              ));              glm              ::              vec4              myVector              (              ten.0              f              ,              10.0              f              ,              ten.0              f              ,              0.0              f              );              glm              ::              vec4              transformedVector              =              myMatrix              *              myVector              ;              // guess the result                                    

In GLSL :

                          vec4              transformedVector              =              myMatrix              *              myVector              ;                      

Well, in fact, you almost never practise this in GLSL. Most of the time, you apply glm::translate() in C++ to compute your matrix, send it to GLSL, and do only the multiplication :

The Identity matrix

This 1 is special. It doesn't practice annihilation. But I mention it considering information technology's as of import every bit knowing that multiplying A by 1.0 gives A.

In C++ :

                          glm              ::              mat4              myIdentityMatrix              =              glm              ::              mat4              (              1.0              f              );                      

Scaling matrices

Scaling matrices are quite like shooting fish in a barrel too :

So if you desire to scale a vector (position or management, it doesn't matter) by ii.0 in all directions :

and the w withal didn't change. You may enquire : what is the meaning of "scaling a direction" ? Well, ofttimes, not much, so you usually don't practise such a affair, merely in some (rare) cases it tin can be handy.

(notice that the identity matrix is only a special case of scaling matrices, with (X,Y,Z) = (1,ane,i). Information technology's also a special case of translation matrix with (X,Y,Z)=(0,0,0), past the fashion)

In C++ :

                          // Use #include <glm/gtc/matrix_transform.hpp> and #include <glm/gtx/transform.hpp>                            glm              ::              mat4              myScalingMatrix              =              glm              ::              scale              (              2.0              f              ,              2.0              f              ,              two.0              f              );                      

Rotation matrices

These are quite complicated. I'll skip the details here, every bit information technology's not important to know their exact layout for everyday utilise. For more information, please take a wait to the Matrices and Quaternions FAQ (popular resources, probably available in your language equally well). Yous can also accept a wait at the Rotations tutorials

In C++ :

                          // Utilise #include <glm/gtc/matrix_transform.hpp> and #include <glm/gtx/transform.hpp>                            glm              ::              vec3              myRotationAxis              (              ??              ,              ??              ,              ??              );              glm              ::              rotate              (              angle_in_degrees              ,              myRotationAxis              );                      

Cumulating transformations

And so at present nosotros know how to rotate, translate, and scale our vectors. It would be smashing to combine these transformations. This is done by multiplying the matrices together, for example :

                          TransformedVector              =              TranslationMatrix              *              RotationMatrix              *              ScaleMatrix              *              OriginalVector              ;                      

!!! BEWARE !!! This lines actually performs the scaling FIRST, and And so the rotation, and THEN the translation. This is how matrix multiplication works.

Writing the operations in another order wouldn't produce the aforementioned result. Try it yourself :

  • make i stride ahead ( beware of your figurer ) and plough left;

  • turn left, and make ane step ahead

As a matter of fact, the order above is what you will usually need for game characters and other items : Calibration information technology showtime if needed; so set its direction, then translate information technology. For instance, given a transport model (rotations have been removed for simplification) :

  • The incorrect way :
    • You interpret the send past (10,0,0). Its eye is at present at x units of the origin.
    • You scale your ship by 2. Every coordinate is multiplied by two relative to the origin, which is far away… Then you stop up with a big ship, just centered at 2*10 = twenty. Which you don't desire.
  • The right way :
    • You scale your send by 2. You get a big send, centered on the origin.
    • Y'all translate your send. Information technology's yet the same size, and at the right distance.

Matrix-matrix multiplication is very similar to matrix-vector multiplication, and so I'll in one case over again skip some details and redirect yous the the Matrices and Quaternions FAQ if needed. For now, we'll just ask the computer to exercise information technology :

in C++, with GLM :

                          glm              ::              mat4              myModelMatrix              =              myTranslationMatrix              *              myRotationMatrix              *              myScaleMatrix              ;              glm              ::              vec4              myTransformedVector              =              myModelMatrix              *              myOriginalVector              ;                      

in GLSL :

                          mat4              transform              =              mat2              *              mat1              ;              vec4              out_vec              =              transform              *              in_vec              ;                      

The Model, View and Projection matrices

For the rest of this tutorial, we volition suppose that nosotros know how to draw Blender's favourite 3d model : the monkey Suzanne.

The Model, View and Projection matrices are a handy tool to split transformations cleanly. Yous may non use this (subsequently all, that's what we did in tutorials 1 and 2). But you should. This is the style everybody does, because it's easier this style.

The Model matrix

This model, just every bit our honey red triangle, is divers past a prepare of vertices. The X,Y,Z coordinates of these vertices are defined relative to the object'southward center : that is, if a vertex is at (0,0,0), it is at the center of the object.

Nosotros'd like to be able to movement this model, maybe because the player controls it with the keyboard and the mouse. Easy, you simply learnt do do then : translation*rotation*scale, and done. You apply this matrix to all your vertices at each frame (in GLSL, not in C++!) and everything moves. Something that doesn't motility will be at the center of the world.

Your vertices are now in Earth Infinite. This is the pregnant of the black arrow in the epitome below : We went from Model Infinite (all vertices defined relatively to the center of the model) to World Infinite (all vertices defined relatively to the heart of the world).

We tin sum this up with the following diagram :

The View matrix

Allow's quote Futurama again :

The engines don't motility the transport at all. The ship stays where information technology is and the engines movement the universe around it.

When you think most it, the same applies to cameras. It you lot want to view a moutain from another bending, yous tin either motility the camera… or move the mount. While not applied in real life, this is really simple and handy in Figurer Graphics.

And then initially your camera is at the origin of the Globe Space. In order to move the world, y'all only introduce some other matrix. Let's say yous want to motility your photographic camera of three units to the right (+10). This is equivalent to moving your whole world (meshes included) 3 units to the LEFT ! (-10). While you lot encephalon melts, permit'southward do it :

                          // Use #include <glm/gtc/matrix_transform.hpp> and #include <glm/gtx/transform.hpp>                            glm              ::              mat4              ViewMatrix              =              glm              ::              translate              (              glm              ::              mat4              (),              glm              ::              vec3              (              -              iii.0              f              ,              0.0              f              ,              0.0              f              ));                      

Again, the image below illustrates this : Nosotros went from Globe Space (all vertices defined relatively to the middle of the globe, as nosotros made and then in the previous section) to Camera Space (all vertices defined relatively to the camera).

Before you head explodes from this, enjoy GLM'south great glm::lookAt function:

                          glm              ::              mat4              CameraMatrix              =              glm              ::              lookAt              (              cameraPosition              ,              // the position of your camera, in world infinite                            cameraTarget              ,              // where you lot desire to wait at, in world space                            upVector              // probably glm::vec3(0,1,0), only (0,-1,0) would make you looking upside-down, which can be peachy too                            );                      

Here's the compulsory diagram :

This is not over yet, though.

The Projection matrix

Nosotros're now in Camera Space. This ways that later all theses transformations, a vertex that happens to accept x==0 and y==0 should exist rendered at the center of the screen. Only we tin can't use but the x and y coordinates to make up one's mind where an object should exist put on the screen : its distance to the camera (z) counts, likewise ! For two vertices with like x and y coordinates, the vertex with the biggest z coordinate will exist more on the centre of the screen than the other.

This is chosen a perspective projection :

And luckily for us, a 4x4 matrix tin represent this projectioni :

                          // Generates a really hard-to-read matrix, but a normal, standard 4x4 matrix nonetheless                            glm              ::              mat4              projectionMatrix              =              glm              ::              perspective              (              glm              ::              radians              (              FoV              ),              // The vertical Field of View, in radians: the amount of "zoom". Think "camera lens". Unremarkably betwixt 90° (extra broad) and 30° (quite zoomed in)                            4.0              f              /              three.0              f              ,              // Aspect Ratio. Depends on the size of your window. Detect that 4/iii == 800/600 == 1280/960, sounds familiar ?                            0.one              f              ,              // Near clipping aeroplane. Go along equally big as possible, or you lot'll get precision issues.                            100.0              f              // Far clipping plane. Keep as niggling every bit possible.                            );                      

One last time :

We went from Camera Space (all vertices defined relatively to the camera) to Homogeneous Space (all vertices defined in a small cube. Everything inside the cube is onscreen).

And the final diagram :

Hither's another diagram so that you empathise better what happens with this Projection stuff. Earlier projection, we've got our blue objects, in Photographic camera Space, and the crimson shape represents the frustum of the camera : the role of the scene that the camera is actually able to come across.

Multiplying everything by the Projection Matrix has the following effect :

In this epitome, the frustum is at present a perfect cube (between -i and 1 on all axes, it'due south a piddling fleck hard to come across it), and all blue objects have been plain-featured in the aforementioned style. Thus, the objects that are nearly the camera ( = about the face up of the cube that we tin can't come across) are big, the others are smaller. Seems like existent life !

Permit's encounter what it looks like from the "behind" the frustum :

Here you become your image ! Information technology's just a fiddling scrap as well foursquare, so some other mathematical transformation is practical (this one is automatic, you lot don't have to do it yourself in the shader) to fit this to the actual window size :

And this is the prototype that is really rendered !

Cumulating transformations : the ModelViewProjection matrix

… Just a standard matrix multiplication as you already dearest them !

                          // C++ : compute the matrix                            glm              ::              mat4              MVPmatrix              =              projection              *              view              *              model              ;              // Remember : inverted !                                    
                          // GLSL : utilize information technology                            transformed_vertex              =              MVP              *              in_vertex              ;                      

Putting information technology all together

  • First pace : include the GLM GTC matrix transform functions:
                          #include <glm/gtc/matrix_transform.hpp>                                    
  • Second step : generating our MVP matrix. This must be done for each model you return.

                                      // Projection matrix : 45° Field of View, four:3 ratio, display range : 0.1 unit <-> 100 units                                    glm                  ::                  mat4                  Projection                  =                  glm                  ::                  perspective                  (                  glm                  ::                  radians                  (                  45.0                  f                  ),                  (                  float                  )                  width                  /                  (                  float                  )                  height                  ,                  0.1                  f                  ,                  100.0                  f                  );                  // Or, for an ortho camera : //glm::mat4 Projection = glm::ortho(-x.0f,10.0f,-ten.0f,10.0f,0.0f,100.0f); // In globe coordinates                                    // Camera matrix                                    glm                  ::                  mat4                  View                  =                  glm                  ::                  lookAt                  (                  glm                  ::                  vec3                  (                  iv                  ,                  3                  ,                  three                  ),                  // Camera is at (4,3,3), in World Space                                    glm                  ::                  vec3                  (                  0                  ,                  0                  ,                  0                  ),                  // and looks at the origin                                    glm                  ::                  vec3                  (                  0                  ,                  ane                  ,                  0                  )                  // Caput is upwards (set up to 0,-1,0 to look upside-down)                                    );                  // Model matrix : an identity matrix (model will exist at the origin)                                    glm                  ::                  mat4                  Model                  =                  glm                  ::                  mat4                  (                  1.0                  f                  );                  // Our ModelViewProjection : multiplication of our 3 matrices                                    glm                  ::                  mat4                  mvp                  =                  Projection                  *                  View                  *                  Model                  ;                  // Remember, matrix multiplication is the other way around                                                
  • Tertiary step : requite it to GLSL

                                      // Get a handle for our "MVP" uniform // Only during the initialisation                                    GLuint                  MatrixID                  =                  glGetUniformLocation                  (                  programID                  ,                  "MVP"                  );                  // Ship our transformation to the currently jump shader, in the "MVP" uniform // This is done in the chief loop since each model will take a dissimilar MVP matrix (At least for the M part)                                    glUniformMatrix4fv                  (                  MatrixID                  ,                  one                  ,                  GL_FALSE                  ,                  &                  mvp                  [                  0                  ][                  0                  ]);                              
  • Fourth pace : apply information technology in GLSL to transform our vertices in SimpleVertexShader.vertexshader

                                      // Input vertex information, different for all executions of this shader.                                    layout                  (                  location                  =                  0                  )                  in                  vec3                  vertexPosition_modelspace                  ;                  // Values that stay constant for the whole mesh.                                    uniform                  mat4                  MVP                  ;                  void                  primary                  (){                  // Output position of the vertex, in clip space : MVP * position                                    gl_Position                  =                  MVP                  *                  vec4                  (                  vertexPosition_modelspace                  ,                  1                  );                  }                              
  • Done ! Here is the same triangle as in tutorial 2, still at the origin (0,0,0), just viewed in perspective from point (4,3,iii), heads up (0,one,0), with a 45° field of view.

In tutorial six you'll larn how to change these values dynamically using the keyboard and the mouse to create a game-like camera, only first, we'll larn how to requite our 3D models some colour (tutorial iv) and textures (tutorial 5).

Exercises

  • Endeavor irresolute the glm::perspective
  • Instead of using a perspective projection, use an orthographic projection (glm::ortho)
  • Change ModelMatrix to translate, rotate, then scale the triangle
  • Do the aforementioned thing, but in different orders. What practise you lot notice ? What is the "best" order that you would want to use for a character ?

Annex