• Advertisement

Archived

This topic is now archived and is closed to further replies.

how to rotate a quad in OpenGL (2D)

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

high, im working on a top down futuristic 2d RPG in c++ / OpenGL. im currently working on the combat system. how it works is, the player / enemey will "lock on" a target, and when they fire it will auto-aim and fly towards that target.. so far i only have made a SMG, a pistol, and a flamethrower. the bullet (for smg/pistol) and particle effect (for flamethrower) are small and pretty much seamless. however, i want to add a rocket launcher to the game. it will be bigger, slower, and of course blow the shit out of things ... anyway, since the bullet and flamethrower images were so small, i didnt have to rotate them. no matter what direction/angle they were shot in, it would look right. but lets say i make a rocket image that looks like this : === well, this is how it should look going completely strait left or right, but how would i go about making it look nice going north, south, ne, se, and basically any angle possible (since i calcualte a strait path it could go on any angle really). also, i would have have to somehow angle the texture also to make it look right, im thinking. please keep in mind i dont have very good math knowledge, which i realize this is about. i dont know what sin or cos are, but im thinking this is where ill need it. i only know very basic algabra (up to logarithms in math 178 in college).. thanks for any help!! and if you give a forumla, please try to explain how it works a little. thanks!!

Share this post


Link to post
Share on other sites
Advertisement
Once you learn some trig (sin, cos, etc.) this problem will be a lot easier for you. But in the meantime...

First of all, you don''t have to worry about rotating the texture. If you rotate the quad, the texture coordinates will rotate with it and you''ll be fine.

When you render your rocket, you''ll want to push the current matrix onto the stack (which saves it), translate and rotate appropriately, render the rocket, then pop the matrix back off (which restores it). Something like:

glPushMatrix();
glTranslate(rocket.x, rocket.y, rocket.z);
glRotate(rocket.angle);
DrawObject(rocket);
glPopMatrix();

(I think I got the translation and rotation in the right order...)

So your problem is to figure out the appropriate angle based on your player position and target position.

Now that I''ve written all this, I realize I''m actually not sure about the trig required to do this in 2d. But I''ll go ahead and guess and let someone else correct me if necessary.

If you subtract your player position from your target position, you get a vector from your player to your target. The delta x and delta y of this vector are the lengths of two sides of a right triangle whose hypotenuse is the vector itself. These two lengths can also be thought of as the sin and cos of an angle, scaled by the length of the hypotenuse.

Then, there''s a trig function (arccos2? atan2?) that (I think) takes a sin and cos as arguments and returns an angle. I think that''s what you want.

Also, remember that you will get the angle in radians, but you need to convert it to degrees before submitting it to OpenGL.

Now, somebody please fill in the gaps/corret the mistakes in my explanation!

Share this post


Link to post
Share on other sites


[and if any of that is wrong, please correct me]

If you don't know basic trig, it would be very beneficial for these types of things for you to go to the library and get a basic easy to read math book or scour the internet and try to get the basic concepts down. You'll run into it quite a bit as you go along.

The easiest thing to do would be to get the angle when the missile is launched and store it, calculate the normalized vector and store that too, then just inch it forward every frame until it makes contact. This is how i work my laser shots, moving objects, and particles (my particles do not store their vectors though - yet).

If you store the angle, you can easily rotate the quad it's drawn onto with the process jyk gave you. if you store the vector, you don't have to recompute it every frame, and if you want a heat-seeking missile, you'll have to reacquire the the angle and vector every frame (expensive if you have many of them)

[edited by - leiavoia on June 11, 2004 12:26:41 PM]

Share this post


Link to post
Share on other sites
Seeing as how you''re using OpenGL, you can use it to do all of the rotating and stuff insteading having to calculate it yourself.
quote:

glPushMatrix();
glTranslate(rocket.x, rocket.y, rocket.z);
glRotate(rocket.angle);
DrawObject(rocket);
glPopMatrix();

(I think I got the translation and rotation in the right order...)


Don''t you have to rotate it before you translate it? I''m just going off on a hunch here, because from what I remember OpenGL rotates an object around the origin, so doing that would move the object to its position and then rotate it around the origin; although I don''t know how opengl handles translating and rotating in ortho mode.

Share this post


Link to post
Share on other sites
Your right about the rotation/translation.

But you still need to calculate the angle and such since the missile will ultimately need to know where it is and where it is going in true World Space. And that Rotate() function still needs to know how much to rotate by.

Share this post


Link to post
Share on other sites
im really confused why the first post wasnt mine...just go here: http://nehe.gamedev.net he'll explain rotating and such...its a simple function that takes up one line in code. Not saying your answer will be one line but sin/cos arent very practical in this case IMHO

"Carpe Diem!"





[edited by - redrabbit on June 11, 2004 2:43:18 PM]

Share this post


Link to post
Share on other sites
btw sin and cos are acronyms for SINE and COSINE (pronounced "sign" and "cosign") just FYI...

Share this post


Link to post
Share on other sites
"Don''t you have to rotate it before you translate it?"

True. Although I think the way OpenGL matrices are set up, the transformations actually happen in reverse order. So if you say:

glTranslate()
glRotate()

It actually rotates first and translates second.

Once again, I''m not positive about this :-)

Share this post


Link to post
Share on other sites
ok, let me get this strait (bear in mind im very very poor at math)

first step is find the "slope" of the 2 objects. this is done by
(X2 - X1, Y2 - Y1)

first off, why is this the slope of the line? in school, they told us the slope of a line is Y2 - Y1 / X2 - X1, so which is right?

ok, so now i have the slope, then i just find the distance by doing sqrt(sx*sx + sy * sy);

ok, so now i have the distance in pixels. now i just have to 'normalize' the vector. well, that page didnt explain normalizing at all... BUT, i actually do this in my game when i fire a bullet / other projectile, so that it will fire in a strait path. i got the formula to do this off the board, didnt understand it, just copied and pasted to make my bullets fire strait

anyway, all i do to normalize the vector is do

float normaled = 1 / distance; ?

now, to set the velocity to this projectile (over time, where Time_Passed is the time since last frame, and xVel and yVel are just hard-coded as 1000 or something (for my bullets, also remember sx/sy are slope x/y), i do:

yVelocity = sy * (normaled*yVel * time.Time_Passed);
xVelocity = sx * (normaled*xVel * time.Time_Passed);

ok, so now i know my velocity to travel. all i do is move at this velocty each frame, and my bullet will sail to its target...

ok, now on to rotating the rockets -

"If you subtract your player position from your target position, you get a vector from your player to your target. The delta x and delta y of this vector are the lengths of two sides of a right triangle whose hypotenuse is the vector itself. These two lengths can also be thought of as the sin and cos of an angle, scaled by the length of the hypotenuse."

what do you mean "delta x and delta y of the vector" ???

looking at leai's drawing, all i have to do is

float angle = tan( deltaX / deltaY);
angle = RadToDeg(angle);
glRotate(angle);
DrawMyRocket();

so does this look right at all to you? thanks for anymore help!!!

[edited by - graveyard filla on June 11, 2004 7:29:27 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by jyk
"Don't you have to rotate it before you translate it?"

True. Although I think the way OpenGL matrices are set up, the transformations actually happen in reverse order. So if you say:

glTranslate()
glRotate()

It actually rotates first and translates second.

Once again, I'm not positive about this :-)


It depends on your view, if you take a grand fixed coordinate system approach, transformations work in reverse, if you take a multiple coordinate system approach (where each object has coordinate system attach to it & can be relative to others) transformations work in natural order which what OpenGL's real view of it but you can still use grand fixed coordinate view.

[edited by - snk_kid on June 11, 2004 7:44:17 PM]

Share this post


Link to post
Share on other sites
quote:

looking at leai''s drawing, all i have to do is

float angle = tan( deltaX / deltaY);
angle = RadToDeg(angle);
glRotate(angle);
DrawMyRocket();

so does this look right at all to you? thanks for anymore help!!!



you need to insert glTranslate in there as well or you''ll rotate around 0,0,0 and be wayyyyy out of place. Rotate first, then translate.

You also need to move the rocket before you draw it.

Share this post


Link to post
Share on other sites
but overall i was right on what i was talking about? and how do i find the X and Y thats in your drawing to calculate the radian... ie what is the delta x / delta y of "the difference between the target and the player" (i put it in quotes because im not sure if its called a slope or now, especailly since in school i wsa taught a slope was y2-y1/x2-x1)

also, could you explain what the push, pop, and rotate do? ive googled but cant get much help, usually you explaining things makes a lot more sence

anyway, i dont understand what a matrix is (that probably sounds bad, but im only using 2d ortho mode and drawing quads)

this is what im thinkig:

glPopMatrix() // im moving the world around, so save what it looks like

glRotate() // move the world around now

do_stuff_now_in_rotated_world(); //draw my rocket but since the world is rotated it looks like its rotated...

glPushMatrix() //go back to the way the world was before rotation

so this gives the illusion of something rotating, when really your just "saving the screen", rotating the entire world?, and then "restoring the screen?". and since i only Draw_Rocket() from inside of the glPop() glRotate() /glPush() calls, it will appear that only my rocket is rotating?

also, leai when you told me that i didnt have to subtract the screen offsets to "cast" my world coordinate into screen coordinates, is this how you do it? something like:

glPushMatrix();

//somehow (translate?) move your world over x_Screen_Offset amount on the x
// and y_Screen_Offset amount on the y

Draw_Object() //now we are in screen space ??

glPopMatrix() //back to the world view we go

its hard to envision how this all works in my head, and im probably wrong, the part i really dont understand is, what happends when i call translate or rotate? i mean, what does this do? does it move my camera around, the world itself around leaving the camera in the same position, or what? also, do i have to translate when i rotate the rocket, or will rotating be fine enough?

thanks for all your help!!

[edited by - graveyard filla on June 12, 2004 1:20:44 AM]

[edited by - graveyard filla on June 12, 2004 1:31:56 AM]

Share this post


Link to post
Share on other sites
"and how do i find the X and Y thats in your drawing to calculate the radian... ie what is the delta x / delta y of "the difference between the target and the player""

Delta just means difference or ''change in''. So:

deltaX = target.x - player.x;
deltaY = target.y - player.y;

If you care about the slope, then that''s deltaY / deltaX. But you really don''t need that information. What you care about is that deltaY and deltaX are proportional to the sin and cos of the angle. So you can call atan(deltaY, deltaX) and find your angle.

(At least I''m pretty sure that will work. But I''ve never actually done it that way before...)

"also, could you explain what the push, pop, and rotate do?"

Your description is pretty much correct, although you have the ''push'' and the ''pop'' backwards. You push to save, pop to restore.

"anyway, i dont understand what "the matrix" is"

Google it, check out the articles/tutorials on this site, or try the book ''3D Math Primer'' or any other good graphics book. In short, though, it''s a mathematical construct that can be used in computer graphics to describe a coordinate system''s position and orientation.

"its hard to envision how this all works in my head, and im probably wrong, the part i really dont understand is, what happends when i call translate or rotate? i mean, what does this do? does it move my camera around, the world itself around leaving the camera in the same position, or what? also, do i have to translate when i rotate the rocket, or will rotating be fine enough?"

It can be confusing. There''s a section in the OpenGL red book that addresses your questions directly. The answer is yes, you''re moving the camera around, and yes, you''re leaving the camera in one spot and moving the world around. It just depends on how you look at it. I''m sure you''ll get your head around it soon enough, though.

Share this post


Link to post
Share on other sites
do you know what i could be doing wrong? when i fire a rocket, i cant see it. i think it has something to do with the screen offsets, because i can see it if i go to the top left corner of the map (ie the screen offsets are 0). but its not working right, even at the top left corner, the rocket doesnt start at the player (where its suposed to) and it moves wrong and is buggy.. also, im pretty sure im doing the math wrong (atan and tan both receive only one parameter...). another thing is, i dont understand how to use glRotate(). i send it the angle, but what about the other 3 parameters? the NeHe tutorial explained this a little, but im not sure how to calculate it (how much to rotate i think?). here is what my code looks like so far (inside Rocket::Update())



float angle;
angle = Math::Rad_To_Deg(tan(dy)/tan(dx));
glPushMatrix();
glRotatef(angle,0.0f,0.0f,0.0f);
glTranslatef(xPos,yPos,0);
yPos += (dy * time.Time_Passed);
xPos += (dx * time.Time_Passed);
Render();
glPopMatrix();



Render() will draw a quad starting at xPos - x_offset and yPos - y_offset , where the offsets are how far into the world(map[][]) we are. also, dx and dy are found like this:


 
// calculate slope

dy = dest_y - y;
dx = dest_x - x;

//find the distance between the target the and shooter


float diff = sqrt((float)dy*dy + dx*dx);

// normalize and set velocity

float norm = 1/diff;//((float)dy*dy + dx*dx);


dy *= (invlen*yVel);
dx *= (invlen*xVel);


where dest_y/x are the destination coordinates, and y/x are the starting coordinates...

thanks for any help..

[edited by - graveyard filla on June 12, 2004 2:56:58 AM]

[edited by - graveyard filla on June 12, 2004 2:58:34 AM]

[edited by - graveyard filla on June 12, 2004 2:59:17 AM]

Share this post


Link to post
Share on other sites
"another thing is, i dont understand how to use glRotate(). i send it the angle, but what about the other 3 parameters?"

My browser won''t display your code blocks, but I''ll answer this question for you...

The other three parameters are the x, y, z of the axis of rotation. In 2D, your axis of rotation will always be the same - the axis other than the two that define your plane. If your game takes place in the xy plane, then your axis of rotation is the z axis, [0 0 1]. So try submitting those values as arguments and see how it works.

Share this post


Link to post
Share on other sites
Here, i just did something like this last night, so i''ve already spent and hour trying to figure out the quirks. Here''s the drawing code for my laser fire that now shoots in any direction! The main things to remember are that you DO have to factor in the screen offset when you translate (which is why it looks bad if you''re not in the upper left corner) and you DO have to translate first, rotate second (because OpenGL will unravel that backwards).


// draw rotated quad

glBindTexture( GL_TEXTURE_2D, texture_sheet->ID() );

glPushMatrix();
glLoadIdentity();
// TRANSLATE FIRST, ROTATE SECOND!

glTranslatef( float(Xpos()-gamespace->Xoff()), float(Ypos()-gamespace->Yoff()), 0 );
glRotatef( angle, 0, 0, 1.0 );

glBegin(GL_QUADS);
glColor4f(1,1,1,1);
/* Bottom Left Of The Texture and Quad */
glTexCoord2f( texture_sheet->XStartRatio(sheet_index), texture_sheet->YEndRatio(sheet_index) );
glVertex2f( -32, 8 );
/* Bottom Right Of The Texture and Quad */
glTexCoord2f( texture_sheet->XEndRatio(sheet_index), texture_sheet->YEndRatio(sheet_index) );
glVertex2f( 32, 8 );
/* Top Right Of The Texture and Quad */
glTexCoord2f( texture_sheet->XEndRatio(sheet_index), texture_sheet->YStartRatio(sheet_index) );
glVertex2f( 32, -8 );
/* Top Left Of The Texture and Quad */
glTexCoord2f( texture_sheet->XStartRatio(sheet_index), texture_sheet->YStartRatio(sheet_index) );
glVertex2f( -32, -8 );
glEnd();
glPopMatrix();
[/sourse]

Share this post


Link to post
Share on other sites
glRotatef(angle,X,Y,Z);

Basicly, the first number id the angle,simple.
Now forthe X,Y, and Z. If u wanted to rotate your object so that it span like a frisbee you would type glRotatef(angle,0,1,0); beacuse a frisbee spins streight and its axis of rotation is Y. For a wheel it would be X, for instance.

Share this post


Link to post
Share on other sites
ok, i think i figured out the problem. (but its still not working...)

apparently, when you translate to the rockets coordinates, the origin of the world is now at those coordinates? so this is what translate does? it just changes the origin to wherever you translate to? you see, i was translating to the rockets coordinates, then drawing the rocket AT ITS COORDINATES, NOT at 0,0

ok, so that part is solved, now my rocket is fireing, no matter where i am on the screen, BUT the rotation isnt working!!! the rocket moves in the way its suposed to, but it doesnt rotate AT ALL. also, after mucho googling, i THINK i figured out how to calculate the angle. its atan(dy/dx). where dy/dx is the delta y /x of the difference between the destination and the target... (IE, the atan of the slope should = the angle in degree''s, no?)

so why isnt it working then? heres my newly updated code (ps, i cant figure out what glLoadIdentity() does, and google seems to give me the same 10 pages that describe it the same way using a single sentence that makes no sence to me (seems like google does this with any GL command..)

once again, this is the constructor to Rocket. only this time i calculate the angle only once, in this constructor. (angle is now a member).. it looks like this:


// calculate dx/dy of the difference between target / source

dy = dest_y - y;
dx = dest_x - x;

//calculate the angle in degree, IE the atan of the slope

angle = atan(dy/dx);

//find the distance between the target the and shooter

float diff = sqrt((float)dy*dy + dx*dx);

// normalize and set velocity ???

float norm = 1/diff;

//not sure what this does but it works lol

dy *= (norm*yVel);
dx *= (norm*xVel);


ok, so now i have the angle, plus the dy/dx (IE the velocity to move each frame)... now, i just do this each frame via Rocket::Update();


//first we will move the rocket

yPos += (dy * time.Time_Passed);
xPos += (dx * time.Time_Passed);

glBindTexture(GL_TEXTURE_2D,texture);

glPushMatrix();

glLoadIdentity();
glTranslatef(xPos - scroll_x,yPos - scroll_y,0);
glRotatef(angle,0.0f,0.0f,1.0f);

glBegin(GL_QUADS);

glColor4f(1,1,1,1);
/* Bottom Left Of The Texture and Quad */
glTexCoord2f(0.0f,1.0f);
glVertex2f(0.0f,h);

/* Bottom Right Of The Texture and Quad */
glTexCoord2f(1.0f,1.0f);
glVertex2f(w,h );

/* Top Right Of The Texture and Quad */
glTexCoord2f(1.0f,0.0f );
glVertex2f(w,0.0f);

/* Top Left Of The Texture and Quad */
glTexCoord2f(0.0f,0.0f);
glVertex2f(0.0f,0.0f);
glEnd();


glPopMatrix();


ok, so i translate to the rockets position, i rotate it by the angle on the Z axis, then i draw the rocket quad with the rocket texture starting at the top left corner (0,0)

this makes my rocket fire, just how its suposed to, only the quad never rotates! it looks exactly the same. also, im not positive how the texture is suposed to look, but i have the texture image looking as if it would be fireing completely strait going north ie

^
|
|

thanks for any help!!

Share this post


Link to post
Share on other sites
sorry but can someone just tell how to caluclate the angle? i thought it would be atan(dy/dx), but apparently thats not working. if i hard-code, say 45.0f as the angle, then the rocket DOES rotate at a 45 degree angle. so can someoen tell me what im doing wrong? the code is still the same (read above) thanks

also, i sort of got it working by doing tan(slope) and then converting from radians to degree's... but this still doesnt look right, only looks right from a certain angle....

[edited by - graveyard filla on June 13, 2004 2:40:21 PM]

Share this post


Link to post
Share on other sites
might help: remember that opengl''s glRotate() angles go counter clockwise.

Share this post


Link to post
Share on other sites
are you sure they go counter clockwise? i just tried experiamenting, hard coding in 45, 90, 270, etc... it seems like its going clockwise to me...

still though, i must be doing something wrong with the math! this is driving me crazy!! how do i find the proper angle to rotate, based on the starting coordinates and the destination coordinates??? is it the arc tangeant of the slope? or is it the tangeant of the slope converted to degree''s? thanks for any help!

Share this post


Link to post
Share on other sites
you can use either arcsin, arccos, or arctan to the same effect, all three will require a conditional that checks either for either a positive x or y diference, because the range of all the arc functions is 180, and youll probably want a full 360.

for arc tan, itd look something like this. (although i think either arcsin/cos would be more efficient processor wise. (only if you already had the distance calulated that is))

angle=arctan(diference_in_y/diference_in_x);
if(diference_in_x<0)
angle+=pi;

EDIT: whoa sry, its y/x (sin/cos)

EDIT: forgot to mention, +=180º would be if your represnting your angle in degrees as apposed to radians, but in that code i obviosly shoudlve used pi. (radian equivalent of 180º)

[edited by - unliterate on June 13, 2004 5:50:15 PM]

Share this post


Link to post
Share on other sites
so then could you explain how to find the angle then please? how would i do checks? do i find the ABS of the slope before i send it to the atan() function, or what? thanks for any help

Share this post


Link to post
Share on other sites

  • Advertisement