Rotating a quad around its own center (OpenGL)

Started by
4 comments, last by GunGrave12 14 years, 5 months ago
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.
Advertisement
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.
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.
I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. I watched C-beams glitter in the dark near the Tannhauser gate. All those moments will be lost in time, like tears in rain. Time to die.
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)
I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. I watched C-beams glitter in the dark near the Tannhauser gate. All those moments will be lost in time, like tears in rain. Time to die.
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!
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();

This topic is closed to new replies.

Advertisement