Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Silly questions and confusion by transformation matrices in OpenGL  (Read 3067 times)
0 Members and 1 Guest are viewing this topic.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Posted 2013-02-01 16:14:26 »

Here we go!

After reading this article, I am left thinking that I should be moving the "camera" around, instead of the world around it.

I understand that we have three matrices to work with in OpenGL, those being view, model and projection.

Until now, I've been using doing this, for movement:
1  
2  
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glTranslatef(float, float, forward!);

However, I do get the impression that this is wrong, and that I should be transforming the view matrix, instead of the model one.

Now, the resources I've checked so far all wants to move the model matrix, so we get the impression the world is moving around me. Is that technically the correct way to do it? I mean, it works, but I think it's much more realistic to move the camera instead. I know it has no effect on the application running, but really? Why would I want to logically move the scene, instead of the camera?

Also, it doesn't really appear to be working out for me when I try to move the camera. It works as long as I only move forwards and backwards. However, when I move backwards, away from my model and then start turning, it's not the feeling of my head turning - instead, it's just the model in front of me rotating, even though I set the matrix-mode accordingly:
1  
2  
3  
4  
GL11.glMatrixMode(GL11.GL_VIEWPORT);
if (Keyboard.isKeyDown(Keyboard.KEY_Q)) {
   GL11.glRotated(0.5f, 0.0f, 1.0f, 0.0f);
}

If someone with experience could expand on how to think of the camera in OpenGL, that would be neat-o.  Smiley

Offline Danny02
« Reply #1 - Posted 2013-02-01 16:46:43 »

just remember young padawan, every thing is relative^^

so it doesn't make a difference if you move the model or the camera Cheesy


When I recall correctly, the old OpenGL doesn't have a view matrix. Only the combination of the model and view matrix is accesible as the modelview matrix.

As a training, you could calculate all the matrix math on your own, take for example the matrix classes from lwjgl. And then after finishing everything you can upload them to OpenGL.

Something like:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
Matrix4 view,model;
...
//setup view
view.translate(0, 0, 5);
view.invert();

//setup model
...

Matrix4 modelView = view.multiply(model);

glMatrixMode(GL_MODELVIEW)
glLoadMatrix(modelView.getArray());


inverting the view matrix is very imported. Say you want to place the camera 5 units back (z + 5), you have to move the world to the front (z -5). so do all the camera placment as u want and in the end invert the matrix to get this behavior.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #2 - Posted 2013-02-01 16:53:09 »

When and how to do I want to use anything other than the modelview matrix?

Would I even leave that matrix, after this is setup?
1  
2  
3  
4  
5  
6  
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();  
gluPerspective((float) 30, 800f / 600f, 0.001f, 10000);
     
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_DEPTH_TEST);

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online Spasi
« Reply #3 - Posted 2013-02-01 16:58:43 »

The GL_VIEWPORT matrix is NOT the camera matrix. Some definitions first:

v: The vertex coordinates in local (model) space.
M: The model matrix. Transforms local coordinates to world coordinates.
V: The view matrix. Transforms world coordinates to eye coordinates.
P: The projection matrix. Transforms eye coordinates to clip coordinates.
VP: The viewport matrix. Transforms normalized device coordinates to window coordinates.

So, this is what happens conceptually:

v -> (transformed by M) -> world -> (transformed by V) -> eye -> (transformed by P) -> clip -> (divide by w) -> normalized device -> (transformed by VP) -> window coordinates.

What you care about in the vertex shader (or with the fixed-function transformations) is the first 3 transforms. Mathematically, this is what actually happens:

clip space vertex = P * (V * (M * v))

This is the vertex shader output. But it's 3 matrix-vector multiplications so, for performance reasons, in practice what we actually use is the ModelViewProjection matrix, or the MVP:

MVP = P * (V * M)

so, clip space vertex = MVP * v

Now, we're free to do the above however we like in a vertex shader, but with fixed-function OpenGL there are fixed mappings to the above concepts:

VP = GL_VIEWPORT
P = GL_PROJECTION
MV = GL_MODELVIEW (there's no M or V!)
MVP = calculated on the fly, you don't have to worry about it

VP and P are simple, you set them usually once when you load your scene and don't have to change them again. But the MV matrix has to change per draw-call. How do you avoid having to set the camera transformation for each one of your models? It's easy, because of how the gl<Transform> calls work. If you do a glTranslatef followed by a glRotatef, what actually happens is that the vertex is first rotated and then translated, i.e., in the opposite order of the transformation calls you made. So, all you have to do is:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// apply camera transformation (the V matrix)

for ( model : models ) {
    glPushMatrix();
    // apply model transformation ( the M matrix)
    // render model
    glPopMatrix();
}


The above code ensures that the M matrix will always be applied before the V matrix, for all your models.
Offline Danny02
« Reply #4 - Posted 2013-02-01 17:48:47 »

there are of course better ways to do matrix stuff in old OpenGL, like Spasi pointed out.

I thought, I should show you something which you can be used in the future and isn't bound to the old way stuff was done in OpenGL.

For example in old OpenGL you would have to create the model matrix on each drawcall. And to do this store the position, rotation, scale and other things for each game object. I think it is much better to just store one matrix in each game object. Transform it at will and just upload it before it gets drawn.

Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #5 - Posted 2013-02-01 18:00:29 »

That does make it a little clearer. I think I will have to do a lot more testing and playing around before I will get this completely. Thank you for the help very much though.  Smiley Much appriciated!

Offline sproingie

JGO Kernel


Medals: 202



« Reply #6 - Posted 2013-02-01 18:09:51 »

If you do a glTranslatef followed by a glRotatef, what actually happens is that the vertex is first rotated and then translated, i.e., in the opposite order of the transformation calls you made.

That's the effect seen, but it's a weird way of describing it, suggesting an order of operations not actually performed.  I'd suggest going with the visualization of transforming the coordinate system, even though it's harder to see at first.  I'd do a lousy job at explaining it any better than the venerable old red book does:

http://www.glprogramming.com/red/chapter03.html#name2

And yes, the immediate mode transformations like glRotate and glTranslate are long deprecated, but even in modern gl, you'll still think in terms of composing transformations; you just have to calculate and pass in the matrix that the transformations turn into. 
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #7 - Posted 2013-02-01 18:53:11 »


Quote
Click to Play
Too bad their visualisation is exactly what does not happen...

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #8 - Posted 2013-02-01 18:58:14 »


Because they're executed in a back-to-front manner? Would the visual make sence, if they had switched around rotate and translate?

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2013-02-01 19:01:19 »

No, there is a diagonal translate.

And please forget about 'operations applied in opposite order', it is incredibly misleading.
It's a transformed coordinate frame.

Meaning: if you rotate, you rotate all future operations, like translate.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline matheus23

JGO Kernel


Medals: 114
Projects: 3


You think about my Avatar right now!


« Reply #10 - Posted 2013-02-01 19:03:40 »

Too bad their visualisation is exactly what does not happen...

Are you sure? I mean... I'm not someone who could say whether it's true or not, but are you sure the opengl reference book is wrong?

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #11 - Posted 2013-02-01 19:04:08 »

Yes.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline sproingie

JGO Kernel


Medals: 202



« Reply #12 - Posted 2013-02-01 19:05:31 »

Bah, that first diagram in the red book is indeed screwed.  The next two diagrams are much better at describing what happens (and the text is better too).  I did look around for a youtube video that would show these operations on an animated set of axes, but I might just have to make one.

And yes the first edition of the red book (the free one online) is full of errata.  It's in its eighth edition now (and no longer red)
Online Spasi
« Reply #13 - Posted 2013-02-01 19:10:03 »

The reference book isn't wrong and I insist on what I said about the reverse order.

That picture above from the book, is what you want to happen. For example, the get the result on the left, you have to first rotate and then translate. In order to achieve this in OpenGL, you have to do:

1) glTranslate
2) glRotate

i.e. in the reverse order. That's because, mathematically, the new transform in applied to the current matrix from the right side:

glLoadIdentity => I
glTranslate => I * T
glRotate => I * T * R

When you multiply this matrix with a vertex, you multiply from the left side:

I * T * R * v

Which results in what you want to achieve in the first place: T * (R * v), i.e. you first rotate and then translate.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #14 - Posted 2013-02-01 19:22:51 »

You can insist that everything happens in reverse order, but you're only going to confuse people new to matrix transformations.

The more matrix operations you perform, the harder it is to wrap your mind around 'everything happens in reverse order', especially as these operations are spread over multiple methods.

It is much, much easier to visualize a transformed coordinate frame, as suddenly all operations are 'in order' again.


The images in the OpenGL redbook visualize what happens if the origin is never transformed. And all operations are applied to the origin of the identity matrix, instead of the current matrix. This is the reason you have to explain it using the 'reverse' analogy.

I explained matrix operations to many people, and when I explained the transformed reference frame, it immediately clicked. For them everything happens 'in order', just like everything else in their code.

As an example, let somebody visualize:
   translate(x,y,x)
   rotY(ry)
   rotX(rx)
   rotZ(rz)
   translate(x2,y2,z2)

And then some more, with nested transforms if you will. I can guarantee that somebody visualizing is as transformed coordinate frames will end up with a good grasp on why you end up with the transform (including exact rotation over the axis into the screen), without having to visualize doing everything in reverse order. That's exactly why matrices seem like magic to so many people, and they end up doing trial-and-error to get to the right transform. How can a CPU do anything in the reverse order, without remembering all steps? Answer: it doesn't, because it can't.

Once that's clear (to the people I explained it to), they easily grasp the more advanced matrix operations too, without them second guessing themselves when writing every transform they do.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline sproingie

JGO Kernel


Medals: 202



« Reply #15 - Posted 2013-02-01 19:28:25 »

The mathematical interpretation is probably more useful for modern OpenGL.  What with all its statefulness, the visual one makes a better explanation for immediate mode.

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #16 - Posted 2013-02-01 19:46:11 »

The mathematical interpretation is probably more useful for modern OpenGL.  What with all its statefulness, the visual one makes a better explanation for immediate mode.

Hm... I don't see the difference between:
1  
2  
3  
glLoadIdentity();
glTranslate3f(...);
glRotatef(angle, x,y,z);


and

1  
2  
3  
4  
5  
Matrix4 mat = new Matrix4();
mat.identity();
mat.translate(...);
mat.rotateAxisAngle(angle, x,y,z);
// set a uniform


The benefits of using the 'in order' visualization of the (transformed) coordinate frames are there, regardless of the API you're working with.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Online Spasi
« Reply #17 - Posted 2013-02-02 13:10:17 »

Hm... I don't see the difference between:

You'd never do that in real code anyway. You'd animate a quaternion and a position vector and you'd build the final matrix from those two in a single step (then use either LoadMatrix or UniformMatrix4x4). For someone new to OpenGL though, using the fixed functionality without a vecmath library, I think it's much easier to get them started with "whatever it is you've visualized in your head, write the code in reverse".

I appreciate your mental model and I really liked what you said about "every transform you apply transforms all other future transforms". But I think it gets confusing when you have a combined MODELVIEW matrix like in OpenGL. Let me explain:

a) The reverse model. You always pretend you're in local space and want to apply some transforms. When writing the code for it, you reverse the order. Continuing with the above flowerpot example:

We start in the flowerpot-local space and then

  • We apply a rotation to tilt the flowerpot to the left (glRotate)
  • We apply a translation to move it to the right (glTranslate)

We don't care what happened before getting to this model, when writing the code for this, we simply reverse the order:

  • glTranslate
  • glRotate

b) The transformed coordinate frame model. You start at the origin (0, 0, 0). If you want to apply a local transform (the rotation), you first need to transform the global coordinate frame so that is matches the local coordinate frame:

We start in global space and then

  • We apply a translation to move the origin to our flowerpot (glTranslate)
  • We apply a rotation to tilt the flowerpot to the left (glRotate)

This is nice, since it exactly matches the code we have to write (same as above):

  • glTranslate
  • glRotate

What's the problem then? Well, you never start at the origin, because there's always the VIEW transform that has been applied before getting to our flowerpot. If glLoadIdentity resets everything and we're at the origin (0, 0, 0), what's the new coordinate frame when you apply the view transform? It's something weird most of the time, isn't it? Now you have to worry about how to get from that coordinate frame to your flowerpot. Which is not something you need to do, you have to pretend that we're still at the origin, facing down the z-axis. With the reverse model on the other hand, there's no inconsistency, you always go from local to global to view.

Anyway, this is just wankery and I guess you can choose whatever works best for you. Personally the reverse thing helped me when I was getting started, because I was used to the local vs global transformations from 3D modelling apps (and OpenGL only has global really). Either way, it only becomes crystal clear when you work out the math.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2013-02-02 17:38:46 »

It seems we still have different visualizations of my approach - the transformed coordinate frame:
b) The transformed coordinate frame model. You start at the origin (0, 0, 0). If you want to apply a local transform (the rotation), you first need to transform the global coordinate frame so that is matches the local coordinate frame:

We start in global space and then

  • We apply a translation to move the origin to our flowerpot (glTranslate)
  • We apply a rotation to tilt the flowerpot to the left (glRotate)

you first need to transform the global coordinate frame so that is matches the local coordinate frame:
you first need to transform the local space relative to its origin
  • We apply a translation to move the origin to our flowerpot (glTranslate)
  • We apply a translation to move our flowerpot to our new origin (glTranslate)

It seems similar, but it is very different. You don't need to 'match' coordinate frames, instead your stack transforms from the root of the coordinate system, moving objects around, not trying to find them. Mathematically it's all the same, but conceptually very different.




What's the problem then? Well, you never start at the origin, because there's always the VIEW transform that has been applied before getting to our flowerpot. If glLoadIdentity resets everything and we're at the origin (0, 0, 0), what's the new coordinate frame when you apply the view transform? It's something weird most of the time, isn't it?
MOVELVIEW is indeed 'problematic', but only because it merges two significantly different concepts (the model and the view). In my code (and mental visualization) I separate them.

First I create the VIEW matrix, without inverting it's operations (btw: inverting is not to be confused with in-order / reverse-order). So positioning the camera is done through mat.translate(x,y,z), not mat.translate(-x,-y,-z), like you see in every tutorial, and barely any newbie grasps, especially when it comes to view rotations, it's normally trial-and-error. So once I placed the camera in global space, I invert its (final) transform and make it current (or multiply it with the identity matrix, if you will).
After that, the MODEL (identity) matrix (transform) is still global space, upon which we can stack transformations.

By separating MODEL and VIEW you separate two distinct concepts which in my opinion should never have been merged, just like Direct3D never merged them. IMHO it was premature optimization, inspired by a mathematical shortcut, which doesn't have an analogy in reality) by the OpenGL designers and (therefore) shouldn't be part of this discussion.



What it boils down to is whether you look at transformations top-down or bottom-up. Let's imagine we have an astronaut on the Moon, orbiting Earth, orbiting the Sun. Let's assume that the Sun is at the origin of the global space.

  • Top-down (in order): start with the Sun, transform the coordinate system so that the center of the Earth is at the origin, transform the coordinate system so that the center of the Moon is at the origin. transform the coordinate system so that the surface of the Moon (= position of the astronaut) is at the origin. With each step you know where each origin (Sun, Earth, Moon, astronaut) is immediately.
  • Bottom-up: (reverse order):start with the astronaut, in it's own local space. To figure out his global coordinates, we act as if we already applied the coordinate transformation of the astronaut relative to the Moon. Now we have the astronaut in local space, relative to the center of the Moon. To figure out where the Moon actually is, we have to act as if we already applied the coordinate transformation of its transform, relative to the Earth. The origin is now as the center of the Earth. To figure out where the Earth actually is, we have to act as if we already applied the coordinate transformation of the Earth relative to the Sun. Then we arrive at global space.

I guess it's just a matter of preference, But to my mind, 'in order', especially in programming, is preferable, especially as everybody previously confused by the 'reverse order magic' of matrices, immediately grasped it after I explained how to visualize it 'in order'.

We can agree to disagree, but luckily mathematically it's all the same.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Roquen
« Reply #19 - Posted 2013-02-02 17:58:30 »

Indeed:

1) I was translated, then rotated:

P'=R(P+T)

2) I was rotated, then translated:

P'=RP+T

back to (1)..what I said that backwards!

P'=R(P+T) = RP+RT

and you can do the same with (2)
Online Spasi
« Reply #20 - Posted 2013-02-02 18:08:28 »

As I said, I can see how thinking in-order can be more intuitive. But I have a problem with this:

You don't need to 'match' coordinate frames, instead your stack transforms from the root of the coordinate system, moving objects around, not trying to find them. Mathematically it's all the same, but conceptually very different.

There's a conflict between what you describe and the actual math. Say the flowerpot rests at +10 on the x-axis. If I were moving objects around, I'd do a glTranslatef(-10.0f, 0.0f, 0.0f). Instead, I have to do a glTranslatef(10.0f, 0.0f, 0.0f), that is, I'm moving the origin to the object and not the object to the origin. Not sure if I explain to correctly, but you're still visualizing one thing and writing code that does the opposite.

I too prefer to think in terms of what happens to the object, inside its parent coordinate frame. With your model I have to think about what happens to the coordinate frame instead, the math forces me to.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #21 - Posted 2013-02-02 18:17:53 »

Apparently I fail to explain it properly.

When I said I move the flowerpot around, I do that in its local space. Which means that I really move it +10 units over the (local!) x-axis, when performing a translate(10,0,0) operation.

Hence in the mental visualization, I don't bring the origin to the flowerpot, I move the flowerpot and make that the new origin.

There is no conflict between that model and the math.



'moving the origin to an object' has no analogy in reality. It's an abstract concept. I try to avoid that, as most people struggle to grasp it. I either explain it using a solar system, or a robot arm (which is more complex, as there are more axes to rotate around). To move from the joint of a the origin robot arm to the joint at the end of it, I do mat.translate(armLength, 0, 0) and that's where the origin of the next (child) robot arm is, which can be rotated, followed by another translate, which creates the origin for the next arm, etc. Nowhere are we 'moving the origin to an object', no, that would indeed mean a negative translate, which is what I'm trying to explain now for 3 posts, is nowhere near what I am saying, and doesn't conflict with the math - or it wouldn't work, obviously.



I guess I'll have to make a video to explain my trivial mental model. Smiley

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline jonjava
« Reply #22 - Posted 2013-02-02 18:42:17 »

Hey Riven, , long posts color clip weirdly.

On a related note, Matricisies™ are non-intuitive and REQUIRE trial and error to get a feel for them imho.

It's all about points in space and how we can manipulate them in useful ways after all.

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #23 - Posted 2013-02-02 18:54:09 »

Something only requires trial and error if you do not grasp the underlying concepts (which ever way you visualize them).

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline jonjava
« Reply #24 - Posted 2013-02-02 19:30:15 »

You say that as if it has any relevance in anything other than to scare newbies :V

Offline Roquen
« Reply #25 - Posted 2013-02-03 07:13:09 »

As a said somewhere else recently, I think people are better off learning basics of coord frames & vectors first.  Otherwise your skipping a step.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (30 views)
2014-12-15 09:26:44

Mr.CodeIt (23 views)
2014-12-14 19:50:38

BurntPizza (50 views)
2014-12-09 22:41:13

BurntPizza (84 views)
2014-12-08 04:46:31

JscottyBieshaar (45 views)
2014-12-05 12:39:02

SHC (59 views)
2014-12-03 16:27:13

CopyableCougar4 (57 views)
2014-11-29 21:32:03

toopeicgaming1999 (123 views)
2014-11-26 15:22:04

toopeicgaming1999 (114 views)
2014-11-26 15:20:36

toopeicgaming1999 (32 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!