Jump to content
  • Advertisement
Sign in to follow this  
hig

OpenGL Thinking in OpenGL

This topic is 3025 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

Hi folks, I'm a relatively experienced programmer and I'm trying to get my head around some opengl concepts. I have a moderate math background and I think I understand the basics of the principles at work. I'd really appreciate a short conversation with some of the opengl gurus here to clarify a few points. Briefly, I'm trying to understand how to implement relative movement. I've seen a number of tutorials that use the familiar sin and cos operations to calculate coordinates after a movement along a specified angle. However, it was my understanding that due to the way the coordinate system works, it is not necessary to do this manually in opengl. If the object is rotated around its own axes, then merely translating along the desired axis is all that is necessary. Is this correct or am I barking up the wrong tree here? I have been able to load a model, rotate on own axes and display. The problem comes when I try to move the object "forward" in the scene, followed by further rotations. 1. Rotate object to "point" a specified direction in the scene. [works] 2. Move the object "forward" [works] 3. Rotate again - this time the rotation occurs around the center of the screen and not the model space. I am thinking that somehow I have to translate to the center of the model before rotating, and the first rotations work by coincidence because before any movement: center of model == center of screen. However, regardless of the order I issue the transformations, I just can't seem to get it right. When the rotation is always around the model axes then the translation is not in the direction the model is facing and vice versa. Here's my draw function:
    //  this sets the model position for the new frame
    model->Update();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glLoadIdentity();   
    
    //  rotate the model to orientate correctly
    glRotatef(-90, 1, 0, 0);
    glRotatef(180, 0, 0, 1);

    //  rotations derived from user input
    glRotatef(model->rotation.x, 1, 0, 0);
    glRotatef(model->rotation.y, 0, 1, 0);
    glRotatef(model->rotation.z, 0, 0, 1);

    //  move the object to its current position
    glTranslatef(model->position.x, model->position.y, model->position.z);

    // draw the vertices
    model->Draw();

    glPopMatrix();
    glutSwapBuffers();


Any pointers would be greatly appreciated! FYI the model is a spacecraft and I am trying to get it to fly in the direction it is pointing.

Share this post


Link to post
Share on other sites
Advertisement
Try this:


// this sets the model position for the new frame
model->Update();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();

// move the object to its current position *been moved
glTranslatef(model->position.x, model->position.y, model->position.z);

// rotate the model to orientate correctly
glRotatef(-90, 1, 0, 0);
glRotatef(180, 0, 0, 1);

// rotations derived from user input
glRotatef(model->rotation.x, 1, 0, 0);
glRotatef(model->rotation.y, 0, 1, 0);
glRotatef(model->rotation.z, 0, 0, 1);



// draw the vertices
model->Draw();

glPopMatrix();
glutSwapBuffers();







The order of matrix multiplications matter. You want to rotate on the origin first, but by translating you moved it off the origin, and then rotated it.

The matrix multiplications are associative. e.g. (a*b)*c = a(b*c) or a*(b*(c*d)) = ((a*b)*c)*d

You should look it up if you don't know what it is, as it will help you understand the multiplications.

Edit:

To fly in the direction, it would be easier to have a vector pointing the direction, and just add that to the model->position.

Also think of the lowest matrix calls acting first, e.g. rotating or translating etc.

[Edited by - andrew111 on April 30, 2010 11:10:32 AM]

Share this post


Link to post
Share on other sites
Hey thanks for such a quick reply. That is exactly what I had tried. With the translation called first, yes the model always rotates correctly on its axes - but then it always moves "down" the screen regardless of its rotation! (I guess because the translation is now relative to the world coordinate system and not the model)

I feel a "d'oh!" moment coming on. I'm sure I must be doing something stupid!

Share this post


Link to post
Share on other sites
Here are a few bits of information that might be helpful...

First of all, the problems you're talking about aren't really OpenGL-specific. It's understandable why one might think they are, but this is really just math that we're talking about, which is essentially the same regardless of what API you're using (OpenGL, Direct3D, etc.).

There are some (sort of) API-specific things that can hang people up though, and one of these is the way in which OpenGL's 'transform' functions operate. Before I continue though, let me point out that the functions you're using are actually deprecated and are more or less irrelevant in modern OpenGL code (typically, you would instead build these transforms yourself and then pass them in as shader parameters).

In any case, one of the most common causes of confusion when working with OpenGL is transform order. As I'm sure you know, matrix multiplication is not commutative, and the order in which a sequence of transforms is applied matters. For example, a rotation followed by a translation will generally have a different result than a translation followed by a rotation. Anytime someone says that they're expecting a model to rotate about its own origin but it instead appears to be rotating about some other point, you can bet that they're applying the transforms in the wrong order, and looking at the bit of code you posted, that appears to be the case here.

I think if you move the glTranslatef() call to before the calls to glRotatef(), you'll find that the behavior is correct (or at least closer to what you're expecting).

I'm sure someone's already pointed that out by now (in fact, after refreshing, I see that they have :), but I'll go ahead and elaborate a bit on this.

You may already know this, but the order in which matrices must be multiplied to yield a given effect depends on whether row or column vectors are being used. In short, when row vectors are used, the matrix product A*B applies the transforms in the order A->B, and when column vectors are used, the transforms are applied in the order B->A.

OpenGL (or the OpenGL fixed-function pipeline at least) has traditionally been thought of as using column vectors, although I don't know whether this really has any practical significance. What is significant though is that the most recent transform command issued is 'closest to' the vector to which it is to be applied, so to speak. This means that transforms are actually applied in the reverse of the order in which they appear in your code, and is why the translation actually needs to come first in your example in order to have the effect of a rotation followed by a translation.

As mentioned previously though, this really isn't the way things are done anymore. In modern OpenGL, you would typically build these transforms yourself, and then simply upload them to OpenGL as shader parameters. On your side of things, you can use whatever convention you want (e.g. row or column vectors), so long as the matrix data ends up in a form that OpenGL can understand.

Share this post


Link to post
Share on other sites
As for your follow-up post, can you post your revised rendering code, along with the code you're using to update the object's position?

Share this post


Link to post
Share on other sites
Hi thanks for the info. I'm certainly no math expert but I do understand the concepts you are raising. And I understand that the gl functions are merely helpers to construct a matrix, which is then applied to the vertices. I had read that they are now depreciated and the modern approach is to construct your own transformation matrices, however I thought it could still be a good approach to learn the basics.

I altered my drawScene function precisely as suggested by the poster above, and my code to update the model position merely increases its "position.y". The reason for that is because in the local model coordinate system, it "points" along its y axis and therefore I concluded that "forward" for the model is along the y axis. This is probably my problem, right? Although I can't quite get my head around why.

I'm assuming then that I have to do something a little more sophisticated to the model position vector?

Many thanks for the help, greatly appreciated!

Share this post


Link to post
Share on other sites
Quote:
Original post by hig
Hi thanks for the info. I'm certainly no math expert but I do understand the concepts you are raising. And I understand that the gl functions are merely helpers to construct a matrix, which is then applied to the vertices. I had read that they are now depreciated and the modern approach is to construct your own transformation matrices, however I thought it could still be a good approach to learn the basics.
Oops - well I guess that post was mostly redundant then :)
Quote:
I altered my drawScene function precisely as suggested by the poster above
I suggested that as well.
Quote:
and my code to update the model position merely increases its "position.y". The reason for that is because in the local model coordinate system, it "points" along its y axis and therefore I concluded that "forward" for the model is along the y axis. This is probably my problem, right? Although I can't quite get my head around why.

I'm assuming then that I have to do something a little more sophisticated to the model position vector?
Right, that won't do what you're expecting. Why it won't do what you're expecting is actually a little tricky to explain, but here goes.

To keep things simple, let's assume that your model transform only incorporates rotation and translation (which is fairly common, and appears to be the case here, judging from your code).

These two transforms (rotation and translation) are typically applied in the order rotation->translation. If you hold some object in your hand (e.g. a toy car, spaceship, or whatever), you can visualize this by starting at a 'default' position and orientation ('identity' in matrix terms), then rotating it to the orientation that you want, and then translating it to the position that you want.

Note that because the rotation occurs first, the translation is unaffected by the rotation. If the translation is +5 along the y axis, then the model will be first rotated to the desired orientation, and then moved 5 units along the (world) y axis.

In order to get the model positioned where you want, your position variable (model->position in your code) needs to represent the object's actual position in world space. If all you ever do is move this position vector along the y axis, then your model will always be positioned somewhere along the (world) y axis (it won't, in general, move 'forward' based on the object's orientation).

To get the kind of motion you want, you need to translate the position vector not along the y axis (or whatever), but rather along the object's current direction vector(s).

There are a few ways to get these direction vectors, but the easiest way is probably to build a transform matrix for the object and then extract the direction vectors from the first three rows or columns of the matrix. (This can be done using OpenGL functions, but it's more straightforward if you use your own math code or a third-party math library for this.)

Share this post


Link to post
Share on other sites
That helps a lot, thanks. My main misconception was that opengl inherently handles this "relative" movement internally, knowing the "local" orientation of the vertices being drawn.

Is it then analogous to the operations required in 2d space to translate at an angle? i.e sine and cosine calculations? I assume it must be, only performed directly with matrices?

Although you're right, and the discussion is moving further away from opengl and more towards independent math topics!

But I now know the specific area that I need to investigate more is the general math behind it and not specifically the opengl API.

Thanks again.

Share this post


Link to post
Share on other sites
Quote:
My main misconception was that opengl inherently handles this "relative" movement internally, knowing the "local" orientation of the vertices being drawn.
Yup, no such luck :) OpenGL neither knows nor cares about that stuff - it has no concept of 'object motion', 'local orientation', or anything of that sort. In the fixed-function pipeline, it just applies a series of transforms in matrix form to the input data (the programmable pipeline doesn't even do that much - with the PP, transforming of the input data is entirely up to you).
Quote:
Is it then analogous to the operations required in 2d space to translate at an angle? i.e sine and cosine calculations?
Yes, it can be. In 2-d, you typically see something like this (or a vector version thereof):
x += cos(angle) * speed * dt;
y += sin(angle) * speed * dt;
If you're dealing with Euler or spherical angles, you can do something similar in 3-d as well.
Quote:
I assume it must be, only performed directly with matrices?
You can use either matrices or angles in both 2-d and 3-d. In 3-d especially, using matrices is more straightforward, IMO, and is the approach I'd recommend. (What I'm referring to here is building a transform matrix for the object, and then extracting the direction vectors from the matrix. Note that once you have the transform matrix, it can be uploaded directly to OpenGL via glLoad/MultMatrix*(), allowing you to bypass convenience functions such as glRotate*() entirely.)

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!