Sign in to follow this  

Simple world space rotation?

This topic is 4831 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'm trying to write a board game where the player has to move balls around. The board is shown from above. The balls can only move in 2D (up, down, left and right). So I'm storing a X and Z rotation value for every ball. To draw them I use this code: glRotatef( mBalls[i].mRotX, 1, 0, 0 ); glRotatef( mBalls[i].mRotZ, 0, 0, 1 ); gluSphere( mSphere, 6.0f, 15, 15 ); glRotatef( -mBalls[i].mRotZ, 0, 0, 1 ); glRotatef( -mBalls[i].mRotX, 1, 0, 0 ); But the problem is that the second (Z) rotation is dependand on the first one. The rotations aren't in world space but rather object space...if you know what I mean... Only when the first roation is exactly 90 degrees the second one works correct. And that's not the effect I want to have. Is there an easy way to change the above code so that the roation will take place in WORLD space? Thanks a lot in advance!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I hope this is what you are searching for:

-firstly you need an orthogonal matrix to rotate around x and another for the z axis.


| cos(teta) sin(teta) 0 |
Rz= |-sin(teta) cos(teta) 0 |
| 0, 0, 1 |

| 1 0 0 |
Rx= | cos(alfa) sin(alfa) 0 |
| -sin(alfa), cos(alfa)0 |



M=Rz*Rx; The matrix for rotating around both axis

Multiply the current position(vertex coord v=(vx,vy,vz))
with M to get the new position

v'=M*v;


I hope it works!





Share this post


Link to post
Share on other sites
Allright, I've done it that way. Here's the code:



glPushMatrix();
float matrix[16] = { 1, 0, 0, 0,
0, cos(DEG2RAD(xx)), sin(DEG2RAD(xx)), 0,
0, -sin(DEG2RAD(xx)), cos(DEG2RAD(xx)), 0,
0, 0, 0, 1 };

float matrix2[16] = { cos(DEG2RAD(zz)), 0, sin(DEG2RAD(zz)), 0,
0, 1, 0, 0,
-sin(DEG2RAD(zz)), 0, cos(DEG2RAD(zz)), 0,
0, 0, 0, 1 };

glMultMatrixf( matrix ); // Multiply with first matrix
glMultMatrixf( matrix2 ); // Multiply with secondmatrix

gluSphere( mSphere, 6.0f, 15, 15 ); // Draw sphere

glPopMatrix();







But sadly the problem remains exactly the same. Have I done something wrong??

Share this post


Link to post
Share on other sites
Moving the balls is no problem. But when a ball moves it should not slide...it should roll! (looks better).

@KulSeran

Actually that makes no sense to me! ;-)

Doing one rotation, drawing the ball, clearing the matrix, doing the other rotation, drawing the abll again...????? I don't get it :-(

Share this post


Link to post
Share on other sites

float m[16];

glLoadIdentity();
glRotatef(angle_x, 1, 0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX, m);

glLoadIdentity();
glRotatef(angle_z, 0, 0, 1);

glMultMatrix(m);
glGetFloatv(GL_MODELVIEW_MATRIX, m);

glLoadIdentity();

glTranslatef(x,y,z);
glMultMatrix(m);




i dont know if that will work, can you try it out and tell me?
i'll try msg back when i get home. cheers.

Share this post


Link to post
Share on other sites
Ahhh, I see. Well, one solution is to work with quaterions. Every rotation is just a quaternion vector multiplication, so it is very simple to do multiple rotations. The problem with euclidian vectors is that once you rotate along one axis, the next rotation is dependent on the first because you have in effect altered your coordinate system.

There's lots of good tutorials, and if you don't want to mess with the math, you can just grab some code and use it w/out worrying too much about the underlying principles involved.

Share this post


Link to post
Share on other sites
@VanKurt:If I understand correctly,you are in top-down view,that means the ball moves in (X,Z) axis.And you want the ball to spin while it moves.All you have to do is first rotate it around the x-axis(spinning),and then rotate it around the y-axis(orientation).This will happen in inverse order,because of the way math works:


glPushMatrix();
glTranslatef(ball.x,ball.y,ball.z);//Place the ball
glRotatef(ball.RotY,0,1,0);//Orientation
glRotatef(ball.RotX,1,0,0);//Spin the ball
DrawBall();
glPopMatrix();


Share this post


Link to post
Share on other sites
AAAAAAAARGH!!! I'm getting crazy! ;-)

Now I changed the whole System to quarternions to avoid the problem ("gimbal lock"???). But guess what? NOTHING CHANGED :-(

Here's the code:


glPushMatrix();

CQuaternion q1( mBalls[i].mRotX, CVector3(0,0,1) );
CQuaternion q2( -mBalls[i].mRotZ, CVector3(0,1,0) );

q1.Normalize();
q2.Normalize();

CQuaternion q3;
q3 = q1*q2;
q3.Normalize();

float matrix[16];
q3.CreateMatrix(matrix);
glMultMatrixf( matrix );
gluSphere( mSphere, 6.0f, 15, 15 );

glPopMatrix();



Did I do something wrong? I thought with quaternions everything would work [crying]

Share this post


Link to post
Share on other sites
CQuaternion q1( mBalls[i].mRotX, CVector3(0,0,1) );
CQuaternion q2( -mBalls[i].mRotZ, CVector3(0,1,0) );

this is a problem. Although you are using quaternions, you are still storing you angles as mRotX and mRotZ, you just convert them to quaternions before converting them into matrices. Effectively you are still using Eulers
Its been a while since I've done this so I may be off, you'll have to play around. What you want to do is store the rotation of the ball as a single quaternion ie

mBalls[i].rotation

then whenever the ball moves apply the appropriate rotation to that. This way you are storing the rotation as a quaternion rather than as an Euler angle.

Share this post


Link to post
Share on other sites
Urks! That sounds right to me ;-)

But to be honest that goes completely beyond my logic... It is so simple to handle, imagine and visualize the ball's rotation as X and Z values...how could these two be convertet to ONE quaternion???

Share this post


Link to post
Share on other sites
I dunno if I'm late on this, or if this is even what you're asking, but here's what I do:


glRotatef(world.xangle(), 1.0, 0, 0);
glRotatef(world.yangle(), 0, 1.0, 0);
glRotatef(world.zangle(), 0, 0, 1.0);

glTranslatef(model.xoffset, model.yoffset, model.zoffset);

glTranslatef(world.xoffset, world.yoffset, world.zoffset);

glRotatef(model.xangle, 1.0, 0, 0);
glRotatef(model.yangle, 0, 1.0, 0);
glRotatef(model.zangle, 0, 0, 1.0);

model.draw();

Share this post


Link to post
Share on other sites
Vankurt,I'm sorry,but I just can't understand why my approach doesn't work.Ok,let's see if I got things straight:
1)This is a 2D top-down game.
2)The ball moves in the XZ plane.That means you will place the ball with commands like glTranslatef(ball.x,0,ball.z).
3)You want the ball to spin while it moves.

Correct?

Share this post


Link to post
Share on other sites
The problem is pretty simple and its a common one. Because the rotations that opengl uses are cumulative by rotating on the x-axis you also change the direction of the z-axis. This means that simulating rolling is tricky. You can get the rotation around one axis perfectly, but the other axis ends up pointing in some awkward direction so that your rotation looks weird.
The commonly offered solution is to use quaternions or use matrices. These are both potential solutions to the problem. However, as I explain above you have to use them correctly. The way you are currently using quaternions is equivalent to an Euler representation, that is you store a quaternion for the x rotation and a quaternion for the z rotation. This suffers from the exact same limitations as before because at some point you still call
glMultMatrix(x rotation stuff)
glMultMatrix(z rotation stuff)
and this is identical to what you had before. The solution is to realize that quaternions don't just represent an angle, they represent an angle around an axis. Thus it is possible to code the entire rotation of the ball into a single quaternion ie
quaternion BallRot;
then you simple call
glMultMatrix(BallRot.Matrix());
or the equivalent commands.
In order to change this rotation you need to calculate a quaternion containing the change in the balls rotation. For example if the ball rolls right, thus rolling about the z axis you have something like
quaternion Rot(angle, 0,0,1);
then you concatenate that rotation with the existing rotation of the ball - something like
BallRot*=Rot;
this won't work exactly because I don't know how you quaternion class is set up - you may have to do something like
BallRot = Rot*BallRot*Rot'
and even then it may be backwards since quaternion multiplication is commutative.
In short, the calculations here are not exactly correct and will not work as I have typed them. However, they express the basic idea of what you need to do. If I have a chance I may be able to write out some working functional code, but at the moment I am a bit short on time.

I hope this helps.

Share this post


Link to post
Share on other sites
Just for a sanity check,I wrote this small piece of code following my suggestion(minor change:I used z-axis for spinning) and it worked fine.Left/right change orientation and UP moves the ball.


float orient=0.0;
float spin=0.0;
double ox=0;
double oy=0;
double oz=0;
double eyex=0;
double eyey=8;
double eyez=0;
GLUquadricObj *sphere;

void RenderScene()
{
glClearColor(1,0,0,0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glViewport(0,0,RES_X,RES_Y);
GL_SetFrustum(fov,0.1,100);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(90.0,1,0,0);
glTranslatef(-eyex,-eyey,-eyez);

gluQuadricTexture(sphere,1);
glPushMatrix();
glTranslatef(ox,oy,oz);
glRotatef(orient,0,1,0);
glRotatef(spin,0,0,1);
gluSphere(sphere,0.5,10,10);
glPopMatrix();

if (GetAsyncKeyState(VK_RIGHT)<0) orient=orient-2.0;
if (GetAsyncKeyState(VK_LEFT)<0) orient=orient+2.0;

if (GetAsyncKeyState(VK_UP)<0)
{
ox=ox+0.05*cos(degtorad(orient));
oz=oz-0.05*sin(degtorad(orient));
spin=spin-1;
}

}




Hope that helps.

Share this post


Link to post
Share on other sites
But you are taking advantage of the behavior that is causing the problem. You have the lines

glRotatef(orient,0,1,0);
glRotatef(spin,0,0,1);


which rely on the fact that the spin rotation depends on the orient rotation. It does indeed avoid the problem but doesn't solve it.
I think what VanKurt wants to do (and if I'm wrong forgive me, its been a long day) is to to use the right, left, up and down arrows to move the ball in the appropriate direction. In this case you need independent rotations around the world X and Z axis, and the best way I know of to do this is not to use Euler angles to store the ball's rotation.

edit - its [ source ] not [ code ]

Share this post


Link to post
Share on other sites
Yep, that's right! And now it works!!!! :-D
Thanks soooo much, guys! You're great!!!

Having one quat per ball and changing this from frame to frame (not generating a new one every time) did the job.

Man, that feels so good ;-)

Share this post


Link to post
Share on other sites

This topic is 4831 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this