• Advertisement
Sign in to follow this  

OpenGL OpenGL Matrices, explanation?

This topic is 3470 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I tried to read this (http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html), but it's very confusingly written in my opinion. For example, he writes, "Well, if we neglect the translation part (the bottom row)", and the very next thing he writes is "After that, you just add the translation onto each point so that: " but he doesn't add the bottom row, he adds something else. And stuff like that seems to be abundant on that page... So I was wondering, could someone give me an example of how to use it?

Share this post


Link to post
Share on other sites
Advertisement
IMHO the author of the cited article will say the following:

A (affine) transformation matrix as used by OpenGL has a principle layout like

[ x_x y_x z_x t_x ]
[ x_y y_y z_y t_y ]
[ x_z y_z z_z t_z ]
[ 0 0 0 1 ]
. If only rotation and translation is used, then those x_x ... z_z denote the rotation, and those t_x ... t_z the translation. (BTW: Scaling and shearing will also be encoded into the x_x ... z_z.)

Then the author claims that such a matrix can be split into the rotational part and the translational part this way:

[ x_x y_x z_x t_x ] [ 1 0 0 t_x ] [ x_x y_x z_x 0 ]
[ x_y y_y z_y t_y ] == [ 0 1 0 t_y ] * [ x_y y_y z_y 0 ]
[ x_z y_z z_z t_z ] [ 0 0 1 t_z ] [ x_z y_z z_z 0 ]
[ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ]

And due to a mathematical rule that says
( M1 * M2 ) * M3 == M1 * ( M2 * M3 )
one can interpret that splitted matrix T * R, although being applied to a point p in a single step
( T * R ) * p
as a two-step transformation
== T * ( R * p )
that rotates the point (i.e. R * p ) and translates the result (i.e. translates the rotated point). The order of effects if important.

Share this post


Link to post
Share on other sites
O_O

Well, thanks. I did not understand that though. Could you give me an example of how to use it in a program?

Share this post


Link to post
Share on other sites
I'm not exactly an expert when it comes to matrices, but this is my take on the page;

In most programming, you would expect an array of 9 elements (lets say int array[9]) to be laid out (if you were using it as a square), like so;

[0][1][2]
[3][4][5]
[6][7][8]

So basically, your data is stored in what is known as row-centric order. This just means that address 1 is next to address 2.

Most mathematicians, and OpenGL, treat the data like so;

[0][3][6]
[1][4][7]
[2][5][8]

which is called a column-centric matrix. Notice the way the data is laid out differently to the row-centric matrix.

Now, a 3x3 matrix, like above, only allows you to rotate, scale and shear your object.

To keep the math as simple as possible, the matrix needs to be kept as a square, but we need some way to store the position of the object in the matrix. To do this, we make the matrix 4x4, which gives us (keeping the OGL format);

[0] [4] [8] [12]
[1] [5] [9] [13]
[2] [6] [10] [14]
[3] [7] [11] [15]


In this way, the translation goes in elements [3],[7] and [11], as x,y and z respectively.

Have a look at the matrix the writer shows you. It looks something like this;

[1][0][0]
[0][1][0]
[0][0][1]
[0][0][0] <-- this is the part you need to notice


The author has made the matrix a 4x3 matrix, rather than keep to the 4x4 matrix he used earlier. When he says to add the translation onto each point, he means take each value of the new position, and add it to the relevant value in the last line of the matrix. I hope this helps with some of your confusion about this.

Share this post


Link to post
Share on other sites
I know that matrix math isn't that easy to understand, but ifyou understand it you have much less problems interpreting how 3D works. Trust me. So please forgive me, but the following is again some matrix math ;)

If you compose a transformation matrix with OpenGL's API on OpenGL's so-called MODELVIEW matrix stack, you do something like
glLoadIdentity();
glTranslatef(tx,ty,tz);
glRotatef(alpha,ax,ay,az);

If you wonder why I use glLoadIdentity: It is useful to initiate OpenGL's matrix stack with a defined value. All those glRotate and glTranslate routines are ever _multiplying_ self onto what is already onto the stack; see below.

Mathematically this is described by composing a transformation matrix
( I * T(tx,ty,tz) ) * R(alpha,ax,ay,az) =: M
Herein I denotes the identity matrix, R the rotation resulting from glRotatef, and T the translation resulting from glTranslatef.

Notice the order of matrices in the formula from left to right and the order of API calls from top to bottom is the same!

Then you push a vertex into the API, e.g. (using the immediate mode)
glBegin(GL_TRIANGLES);
glVertex3f(px,py,pz);
glEnd();
with the above transformation being active that is hence applied to the vertex position, yielding in the transformed vertex position (I'm dropping the transformation arguments from here on since I'm too lazy to write them down, okay?)
p' := M * p == ( ( I * T ) * R ) * p

What does this mean? It means that OpenGL has a transformation on its stack, namely a composition of a translation and a rotation. This composed transformation is applied as a whole (notice the parantheses) to the vertex position.

Now let us inspect the effect of the transformation. Multiplying the identity matrix with another matrix has no effect, so that
== ( T * R ) * p

We already know that the parantheses play no role w.r.t. the result (see my previous post), so that we can _interpret_ the result (although it is not being applied in this way) as
== T * ( R * p )
what means nothing else than that the vertex position is rotated, and the rotated result is translated. Voila.

Now, isn't it the same as translating the vertex and rotating the result (i.e. the other order)? No, it isn't (in general)! You can simply construct an example: Say, you use
glTranslatef(0,1,0);
glRotatef(90,1,0,0);
glBegin(GL_TRIANGLES);
glVertex3f(0,1,0);
glEnd();
Using what is written above, OpenGL does
rotating [ 0,1,0 ] by 90 degrees around the x axis, yielding in [ 0,0,1 ]
translating [ 0,0,1 ] by [ 0,1,0 ] yielding in [ 0,1,1 ]

The other way
glRotatef(90,1,0,0);
glTranslatef(0,1,0); // <-- EDIT here was an error
glBegin(GL_TRIANGLES);
glVertex3f(0,1,0);
glEnd();
does
translating [ 0,1,0 ] by [ 0,1,0 ] yielding in [ 0,2,0 ]
rotating [ 0,2,0 ] by 90 degrees around the x axis, yielding in [ 0,0,2 ]
what obviously differs from the first result.

However, sometimes you apply a transformation that is already composed, using
glMultMatrixf(...);
instead of the particular transformations glRotatef, glTranslatef, ... Then, and that is the stuff of my previous post, one can decompose the transformation matrix and interpret it as
T * R
and that is, with the above explanations in mind, equivalent to
glTranslatef(...);
glRotatef(...);

_That_ is what the article said, as far as belonging to the cited section.

[Edited by - haegarr on August 10, 2008 1:17:01 PM]

Share this post


Link to post
Share on other sites
@webwraith: You're mainly correct, but not totally.

Considering that OpenGL uses column vectors, and furthur uses the 4th scalar of a (homogeneous) vector as the homogeneous co-ordinate, the translation must be in the right-most column but not in the bottom row. Hence, if using a 4x4 matrix, it looks like
[ 1  0  0  t_x ]
[ 0 1 0 t_y ]
[ 0 0 1 t_z ]
[ 0 0 0 1 ]
and for a 4x3 matrix, it looks like
[ 1  0  0  t_x ]
[ 0 1 0 t_y ]
[ 0 0 1 t_z ]

Share this post


Link to post
Share on other sites
Math is tricky. You must choose a methodological approach or you'll get lost in nowhere land in a blink of an eye. Chances are you give up learning math altogether if you choose the wrong approach in the beginning because in doing so, you'll eventually get to a point that you conclude "Well, Math is not my thing!". It is your thing my friend, but you need to choose a slow methodological approach or you'll get lost sooner than you expect it. You can't expect to learn 3D math (or any other field of science) by reading a tutorial or two, because Math is no picnic. You can't rush it. You need to invest a lot of time in learning it. It's tough, I know, but so is life and there is no easy way around either of them!

My apologies if that doesn't apply to you, in which case you can skip this post altogether, but if it does, please take a moment to consider it for your own good.

I don't care what those tutorials are advertising, but there is no fast way to learn Math or programming or any other scientific field. I hold a BSc. in Computer Science, have read a lot of math related books during the years and I do enjoy thinking about mathematical problems, so I'm neither the lazy guy nor do I lack proper trainings, but even I get stuck at math quite a lot, because as I said, math is no picnic.

I strongly suggest that you pick up a copy of "3D Math Primer for Graphics and Game Development" by Fletcher Dunn and Ian Parberry from your favorite library or bookstore and start reading it right away. It's the best elementary book on 3D math that I've come by. There IS a difference between reading 400 pages of 3D math and skimming over a couple of tutorials: you'd be much more knowledgeable when you invest more time and choose the right approach.

... and no, I'm not affiliated with the authors of this book in any way, shape or form. [smile]

Good luck!

[Edited by - Ashkan on August 10, 2008 7:28:14 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by haegarr
and for a 4x3 matrix, it looks like
[ 1  0  0  t_x ]
[ 0 1 0 t_y ]
[ 0 0 1 t_z ]


Minor detail: That's a 3x4 matrix.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prefect
Quote:
Original post by haegarr
and for a 4x3 matrix, it looks like
[ 1  0  0  t_x ]
[ 0 1 0 t_y ]
[ 0 0 1 t_z ]


Minor detail: That's a 3x4 matrix.


I disagree. :)
Col x Row.

Share this post


Link to post
Share on other sites
Quote:
Original post by haegarr
@webwraith: You're mainly correct, but not totally.
...

Thank you for pointing that out, but the example on the page is the same as the 4x3 matrix that you can see in my post. Perhaps the confusion then lies in whether the author of that page is using row- or column-centric matrices at that point?

[Edited by - webwraith on August 17, 2008 2:37:39 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
I disagree. :)
Col x Row.
Every reference I've ever seen on the topic uses the convention RowXCol. I'm pretty sure this convention is used more or less without exception, but if you can provide an example to the contrary I'd be interested to see it.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Quote:
Original post by Rasmadrak
I disagree. :)
Col x Row.
Every reference I've ever seen on the topic uses the convention RowXCol. I'm pretty sure this convention is used more or less without exception, but if you can provide an example to the contrary I'd be interested to see it.


This is also the form I have been taught, a matrix which has 4 rows (m) and 3 columns (n) is denoted an m*n or a 4*3 matrix.

Share this post


Link to post
Share on other sites
Quote:
Original post by webwraith
Do your references include OpenGL? :)
I assume this is in reference to my post? If so, then yeah, of course they include OpenGL :)

Again, I've never come across a reference (OpenGL or otherwise) that uses the convention Col-Row when referring to matrix dimensions or to individual matrix elements. Can you point me to a reference that contradicts this? (And I'm not being snide - if there is such a reference, I would really like to be aware of it!).

Just to eliminate potential confusion, note that we are talking here about a specific aspect of mathematical notation: whether the row or column is listed first when describing matrix dimensions or specifying a matrix element.

Note that vector notation (row or column) and matrix storage (row- or column-major) are entirely separate and unrelated issues. (I'm guessing this is where you're getting confused...)

Share this post


Link to post
Share on other sites
I didn't intend to derail this thread in such a way, but since it's at least partially on-topic... the choice of the Rows*Cols notation is not arbitrary.

Say you have two matrices A and B, where A is an m*n matrix and B is a k*l matrix. Then the matrix product A*B is defined iff n = k. When you write it down on paper, you'll see
 A * B
m*n k*l

It gets even more obvious when multiplying more than two matrices. The rule is sometimes formulated as "the inner dimensions of a matrix product must agree". So once you're used to it, everything flows naturally because the definitions are very consistent. [Also, think about how this works with vector-matrix or matrix-vector multiplication.]

Hope this helps in memorizing how things work.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By LifeArtist
      Good Evening,
      I want to make a 2D game which involves displaying some debug information. Especially for collision, enemy sights and so on ...
      First of I was thinking about all those shapes which I need will need for debugging purposes: circles, rectangles, lines, polygons.
      I am really stucked right now because of the fundamental question:
      Where do I store my vertices positions for each line (object)? Currently I am not using a model matrix because I am using orthographic projection and set the final position within the VBO. That means that if I add a new line I would have to expand the "points" array and re-upload (recall glBufferData) it every time. The other method would be to use a model matrix and a fixed vbo for a line but it would be also messy to exactly create a line from (0,0) to (100,20) calculating the rotation and scale to make it fit.
      If I proceed with option 1 "updating the array each frame" I was thinking of having 4 draw calls every frame for the lines vao, polygons vao and so on. 
      In addition to that I am planning to use some sort of ECS based architecture. So the other question would be:
      Should I treat those debug objects as entities/components?
      For me it would make sense to treat them as entities but that's creates a new issue with the previous array approach because it would have for example a transform and render component. A special render component for debug objects (no texture etc) ... For me the transform component is also just a matrix but how would I then define a line?
      Treating them as components would'nt be a good idea in my eyes because then I would always need an entity. Well entity is just an id !? So maybe its a component?
      Regards,
      LifeArtist
    • By QQemka
      Hello. I am coding a small thingy in my spare time. All i want to achieve is to load a heightmap (as the lowest possible walking terrain), some static meshes (elements of the environment) and a dynamic character (meaning i can move, collide with heightmap/static meshes and hold a varying item in a hand ). Got a bunch of questions, or rather problems i can't find solution to myself. Nearly all are deal with graphics/gpu, not the coding part. My c++ is on high enough level.
      Let's go:
      Heightmap - i obviously want it to be textured, size is hardcoded to 256x256 squares. I can't have one huge texture stretched over entire terrain cause every pixel would be enormous. Thats why i decided to use 2 specified textures. First will be a tileset consisting of 16 square tiles (u v range from 0 to 0.25 for first tile and so on) and second a 256x256 buffer with 0-15 value representing index of the tile from tileset for every heigtmap square. Problem is, how do i blend the edges nicely and make some computationally cheap changes so its not obvious there are only 16 tiles? Is it possible to generate such terrain with some existing program?
      Collisions - i want to use bounding sphere and aabb. But should i store them for a model or entity instance? Meaning i have 20 same trees spawned using the same tree model, but every entity got its own transformation (position, scale etc). Storing collision component per instance grats faster access + is precalculated and transformed (takes additional memory, but who cares?), so i stick with this, right? What should i do if object is dynamically rotated? The aabb is no longer aligned and calculating per vertex min/max everytime object rotates/scales is pretty expensive, right?
      Drawing aabb - problem similar to above (storing aabb data per instance or model). This time in my opinion per model is enough since every instance also does not have own vertex buffer but uses the shared one (so 20 trees share reference to one tree model). So rendering aabb is about taking the model's aabb, transforming with instance matrix and voila. What about aabb vertex buffer (this is more of a cosmetic question, just curious, bumped onto it in time of writing this). Is it better to make it as 8 points and index buffer (12 lines), or only 2 vertices with min/max x/y/z and having the shaders dynamically generate 6 other vertices and draw the box? Or maybe there should be just ONE 1x1x1 cube box template moved/scaled per entity?
      What if one model got a diffuse texture and a normal map, and other has only diffuse? Should i pass some bool flag to shader with that info, or just assume that my game supports only diffuse maps without fancy stuff?
      There were several more but i forgot/solved them at time of writing
      Thanks in advance
    • By RenanRR
      Hi All,
      I'm reading the tutorials from learnOpengl site (nice site) and I'm having a question on the camera (https://learnopengl.com/Getting-started/Camera).
      I always saw the camera being manipulated with the lookat, but in tutorial I saw the camera being changed through the MVP arrays, which do not seem to be camera, but rather the scene that changes:
      Vertex Shader:
      #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 TexCoord; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); TexCoord = vec2(aTexCoord.x, aTexCoord.y); } then, the matrix manipulated:
      ..... glm::mat4 projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); ourShader.setMat4("projection", projection); .... glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); ourShader.setMat4("view", view); .... model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); ourShader.setMat4("model", model);  
      So, some doubts:
      - Why use it like that?
      - Is it okay to manipulate the camera that way?
      -in this way, are not the vertex's positions that changes instead of the camera?
      - I need to pass MVP to all shaders of object in my scenes ?
       
      What it seems, is that the camera stands still and the scenery that changes...
      it's right?
       
       
      Thank you
       
    • By dpadam450
      Sampling a floating point texture where the alpha channel holds 4-bytes of packed data into the float. I don't know how to cast the raw memory to treat it as an integer so I can perform bit-shifting operations.

      int rgbValue = int(textureSample.w);//4 bytes of data packed as color
      // algorithm might not be correct and endianness might need switching.
      vec3 extractedData = vec3(  rgbValue & 0xFF000000,  (rgbValue << 8) & 0xFF000000, (rgbValue << 16) & 0xFF000000);
      extractedData /= 255.0f;
    • By Devashish Khandelwal
      While writing a simple renderer using OpenGL, I faced an issue with the glGetUniformLocation function. For some reason, the location is coming to be -1.
      Anyone has any idea .. what should I do?
  • Advertisement