Sign in to follow this  

Rotating a quad around its own center (OpenGL)

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

Hey all, I've been going at this for 1-2 days now and cannot seem to get this to work correctly. What I'm trying to do, is simply make a textured quad rotate about the z axis in reference to its own center. From what I've gathered, I need to do 3 things... Translate the quad to (0,0) Rotate the quad Translate it back to where ever it was: (x,y) So this is what I pretty much have..
glTranslatef( -static_cast<float>(sprite.getScreenCoords()->x), -static_cast<float>(sprite.getScreenCoords()->y), 0.0f );
glRotated(angle,0,0,1);
glTranslatef( sprite.getScreenCoords()->x, sprite.getScreenCoords()->y, 0.0f );	

This makes the quad rotate, but definitely not about its own center. And I'm not sure what I'm doing wrong =/. Here are some more snippets of code so you can have a better grasp as to how i'm doing things.. Code that draws my sprite:
void Player::updateRengerLogic(unsigned int curTime, const PlayerInfo& playerInfo )
{
	
	//Calc angle from ships front to mouse
	float deltaX( playerInfo.mouseCoords.x - sprite.getScreenCoords()->x );
	float deltaY( playerInfo.mouseCoords.y - sprite.getScreenCoords()->y );
	double aimArrowAngle( atan(deltaY/deltaX) );
	if ( deltaX < 0 )
		aimArrowAngle += PI;
	aimArrowAngle *= (180/PI);

	//Draw main ship
	glPushMatrix();
	
	glTranslatef( -static_cast<float>(sprite.getScreenCoords()->x), -static_cast<float>(sprite.getScreenCoords()->y), 0.0f );
	glRotated(angle,0,0,1);
	glTranslatef( sprite.getScreenCoords()->x, sprite.getScreenCoords()->y, 0.0f );	

	glVertexPointer(2, GL_FLOAT, 0, sprite.getScreenCoords() );
	glTexCoordPointer(2, GL_FLOAT, 0,  sprite.getUVCoords() );
	glBindTexture(GL_TEXTURE_2D,  sprite.getTex() );
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glPopMatrix();


	//Draw aim arrow
	glPushMatrix();

	
	glTranslatef( aimArrow.getScreenCoords()->x+xVel, aimArrow.getScreenCoords()->y+yVel, 0.0f );	
	glRotated(aimArrowAngle,0,0,1);
	glTranslatef( -static_cast<float>(aimArrow.getScreenCoords()->x), -static_cast<float>(aimArrow.getScreenCoords()->y), 0.0f );
	
	glVertexPointer(2, GL_FLOAT, 0, aimArrow.getScreenCoords() );
	glTexCoordPointer(2, GL_FLOAT, 0,  aimArrow.getUVCoords() );
	glBindTexture(GL_TEXTURE_2D,  aimArrow.getTex() );
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glPopMatrix();

}

Code that moves the sprite and determines the angle it should face...
void Player::runAILogic(PlayerInfo &playerInfo)
{
	playerInfo.playerCoords.x = sprite.getScreenCoords()->x;
	playerInfo.playerCoords.y = sprite.getScreenCoords()->y;


	if ( (playerInfo.keysDown[SDLK_UP] && playerInfo.keysDown[SDLK_LEFT]) )
	{
		//xVel -= speed/2;
		//yVel -= speed/2;
		sprite.setScreenCoords(-speed/2,-speed/2);
		aimArrow.setScreenCoords(-speed/2,-speed/2);
		if ( angle < 225 )
			angle += 10;
		if ( angle > 225 )
			angle -= 10;
	}
	else if ( (playerInfo.keysDown[SDLK_UP] && playerInfo.keysDown[SDLK_RIGHT]) )
	{
		//xVel += speed/2;
		//yVel -= speed/2;
		sprite.setScreenCoords(speed/2,-speed/2);
		aimArrow.setScreenCoords(speed/2,-speed/2);
		if ( angle < 315 )
			angle += 10;
		if ( angle > 315 )
			angle -= 10;
	}
	else if ( (playerInfo.keysDown[SDLK_DOWN] && playerInfo.keysDown[SDLK_LEFT]) )
	{
		//xVel -= speed/2;
		//yVel += speed/2;
		sprite.setScreenCoords(-speed/2,speed/2);
		aimArrow.setScreenCoords(-speed/2,speed/2);
		if ( angle < 135 )
			angle += 10;
		if ( angle > 135 )
			angle -= 10;
	}
	else if ( (playerInfo.keysDown[SDLK_DOWN] && playerInfo.keysDown[SDLK_RIGHT]) )
	{
		//xVel += speed/2;
		//yVel += speed/2;
		sprite.setScreenCoords(speed/2,speed/2);
		aimArrow.setScreenCoords(speed/2,speed/2);
		if ( angle < 45 )
			angle += 10;
		if ( angle > 45 )
			angle -= 10;
	}
	else if( playerInfo.keysDown[SDLK_UP] )
	{
		//yVel -= speed;
		sprite.setScreenCoords(0,-speed);
		aimArrow.setScreenCoords(0,-speed);
		if ( angle < 270 && angle >= 180 )
			angle += 10;
		if ( angle < 270 && angle <= 180 )
			angle -= 10;
		if ( angle > 270 )
			angle -= 10;
	}
	else if( playerInfo.keysDown[SDLK_DOWN] )
	{
		//yVel += speed;
		sprite.setScreenCoords(0,speed);
		aimArrow.setScreenCoords(0,speed);
		if ( angle > 90  )
			angle -= 10;
		if ( angle < 90  )
			angle += 10;
	}

	
	else if( playerInfo.keysDown[SDLK_RIGHT] )
	{
		//xVel += speed;
		sprite.setScreenCoords(speed,0);
		aimArrow.setScreenCoords(speed,0);
		if ( angle > 0 && angle <= 180 )
			angle -= 10;
		if ( angle > 0 && angle >= 180 )
			angle += 10;
	}
	else if( playerInfo.keysDown[SDLK_LEFT] )
	{
		//xVel -= speed;
		sprite.setScreenCoords(-speed,0);
		aimArrow.setScreenCoords(-speed,0);
		if ( angle < 180 )
			angle += 10;
		if ( angle > 180 )
			angle -= 10;
	}

	if ( angle > 360 )
		angle = 0;
	if ( angle < 0 )
		angle = 360;
}

Sorry if I'm posting too much code at once, it just that this seems like it should be such a simple task and I can't get it to work >_<. Thanks in advance for any help.

Share this post


Link to post
Share on other sites
It's easier to never modify the vertices you draw at all, but always have them centered about the origin. Then you just rotate without translating first, and then translate to the real position. That way, when you move your quad, you only need to keep track of the models position as a single point, and not bother with the actual vertices of the model, which can be centered in the models local space.

Share this post


Link to post
Share on other sites
Can I see your code here:
sprite.getScreenCoords()?


I guess you do not correctly center it on axis, maybe you have to change:

glTranslatef( sprite.getScreenCoords()->x, sprite.getScreenCoords()->y, 0.0f );

by

glTranslatef( sprite.getScreenCoords()->x-sprite.width*0.5, sprite.getScreenCoords()->y-sprite.height*0.5, 0.0f );

I can reply you better after reading getScreenCoords or explain in which positions you created your vertices.

Share this post


Link to post
Share on other sites
By the way, I realise you have a serious mistake:

Transformations are applied in a inverted order (because matrix multiplication) so change this:

Translate the quad to (0,0)
Rotate the quad
Translate it back to where ever it was: (x,y)

by:

Translate it back to where ever it was: (x,y)
Rotate the quad
Translate the quad to (0,0)

Share this post


Link to post
Share on other sites
Quote:
Original post by Erik Rufelt
It's easier to never modify the vertices you draw at all, but always have them centered about the origin. Then you just rotate without translating first, and then translate to the real position. That way, when you move your quad, you only need to keep track of the models position as a single point, and not bother with the actual vertices of the model, which can be centered in the models local space.


Interesting....I'll definitely fiddle with this idea. I'm real new to opengl, so I'm not sure how to go about doing many things.




Quote:
Original post by ricardo_ruiz_lopez
Can I see your code here:
sprite.getScreenCoords()?


I guess you do not correctly center it on axis, maybe you have to change:

glTranslatef( sprite.getScreenCoords()->x, sprite.getScreenCoords()->y, 0.0f );

by

glTranslatef( sprite.getScreenCoords()->x-sprite.width*0.5, sprite.getScreenCoords()->y-sprite.height*0.5, 0.0f );

I can reply you better after reading getScreenCoords or explain in which positions you created your vertices.


Here is my entire Sprite class (I'm embarrassed to show it :-p )



#pragma once
#include "Common.h"
#include <string>

class Sprite {
public:
Sprite(const std::string& fileName, float x, float y, unsigned width, unsigned height);
void setUVCoords( const Quad& uvCoords );
void setScreenCoords( const Quad& screenCoords );
void setScreenCoords( float x, float y);

Quad* getScreenCoords();
Quad* getUVCoords();

virtual void bindTextureByFileName( const std::string& fileName );
GLuint getTex() const;

virtual ~Sprite();

protected:
Quad screenCoordinates;
Quad uvCoordinates;
GLuint textureID;

};



#include "Sprite.h"
#include "Common.h"

using namespace std;

Sprite::Sprite(const std::string& fileName, float x, float y, unsigned width, unsigned height)
{
//x and y should be the center of the sprite.
screenCoordinates.one.x = x - (width/2);
screenCoordinates.one.y = y - (height/2);

screenCoordinates.two.x = x - (width/2);
screenCoordinates.two.y = y + (height/2);

screenCoordinates.three.x = x + (width/2);
screenCoordinates.three.y = y - (height/2);

screenCoordinates.four.x = x + (width/2);
screenCoordinates.four.y = y + (height/2);

screenCoordinates.x = x;
screenCoordinates.y = y;

Quad tex( 0, 1, 0, 0, 1, 1, 1, 0 );
uvCoordinates = tex;

bindTextureByFileName(fileName);

}

Sprite::~Sprite()
{
glDeleteTextures(1, &textureID);

}

void Sprite::setUVCoords( const Quad& uvCoords )
{
uvCoordinates = uvCoords;
}
void Sprite::setScreenCoords( const Quad& screenCoords )
{
screenCoordinates = screenCoords;
}

void Sprite::setScreenCoords( float x, float y)
{
screenCoordinates.x = x;
screenCoordinates.y = y;

screenCoordinates.updateQuadPoints(x,y);

}

Quad* Sprite::getScreenCoords()
{
return &screenCoordinates;
}

Quad* Sprite::getUVCoords()
{
return &uvCoordinates;
}

GLuint Sprite::getTex() const
{
return textureID;
}

void Sprite::bindTextureByFileName( const string& fileName )
{
textureID = SOIL_load_OGL_texture
(
fileName.c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB
);
}




and this is the Quad struct it uses:


typedef struct Quad {
Quad( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4 ) : one(x1, y1), two(x2,y2), three(x3,y3), four(x4, y4) {}
Quad() {}
Point2D one;
Point2D two;
Point2D three;
Point2D four;

unsigned width;
unsigned height;
float x;
float y;

bool operator==(const Quad& rhs)
{
if ( (one.x == rhs.one.x) && (one.y == rhs.one.y) &&
(two.x == rhs.two.x) && (two.y == rhs.two.y) &&
(one.x == rhs.one.x) && (three.y == rhs.three.y) &&
(one.x == rhs.one.x) && (four.y == rhs.four.y) )
return true;

return false;
}

void updateQuadPoints(float x, float y)
{
one.x += x;
two.x += x;
three.x += x;
four.x += x;

one.y += y;
two.y += y;
three.y += y;
four.y += y;
}
} Quad;





Vertex one is the top left corner, two the bottom left, three the top right, and four the bottom right.

Thanks again =D!

Share this post


Link to post
Share on other sites
Quote:
Original post by ricardo_ruiz_lopez
By the way, I realise you have a serious mistake:

Transformations are applied in a inverted order (because matrix multiplication) so change this:

Translate the quad to (0,0)
Rotate the quad
Translate it back to where ever it was: (x,y)

by:

Translate it back to where ever it was: (x,y)
Rotate the quad
Translate the quad to (0,0)


Sorry for the double post...

I changed things like you said, seems the same things happen though. This the updated portion of the code..



//Draw main ship
glPushMatrix();


glTranslatef( sprite.getScreenCoords()->x, sprite.getScreenCoords()->y, 0.0f );
glRotated(angle,0,0,1);
glTranslatef( -static_cast<float>(sprite.getScreenCoords()->x), -static_cast<float>(sprite.getScreenCoords()->y), 0.0f );

glVertexPointer(2, GL_FLOAT, 0, sprite.getScreenCoords() );
glTexCoordPointer(2, GL_FLOAT, 0, sprite.getUVCoords() );
glBindTexture(GL_TEXTURE_2D, sprite.getTex() );
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glPopMatrix();


//Draw aim arrow
glPushMatrix();

glTranslatef( aimArrow.getScreenCoords()->x, aimArrow.getScreenCoords()->y, 0.0f );
glRotated(aimArrowAngle,0,0,1);
glTranslatef( -static_cast<float>(aimArrow.getScreenCoords()->x), -static_cast<float>(aimArrow.getScreenCoords()->y), 0.0f );

glVertexPointer(2, GL_FLOAT, 0, aimArrow.getScreenCoords() );
glTexCoordPointer(2, GL_FLOAT, 0, aimArrow.getUVCoords() );
glBindTexture(GL_TEXTURE_2D, aimArrow.getTex() );
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glPopMatrix();


Share this post


Link to post
Share on other sites

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