I want to use the function sprite.rotate() and sprite.setrotation() but sfml takes into account the top-right point of the sprite. How to set this point to sprite center?
If you want to set the rotation center you have to use sprite.setOrigin() function which sets the center for position and rotation.
For example:
sf::Texture texture;
if (!texture.loadFromFile("texture.png"))
exit(-1);
sf::Sprite sprite;
sprite.setOrigin((sf::Vector2f)texture.getSize() / 2.f);
Or if you are changing the texture rect of the sprite:
sprite.setOrigin(sf::Vector2f(sprite.getLocalBounds().width, sprite.getLocalBounds().height) / 2.f);
Related
I'm trying to make a 2D game using DirectX 11 and I get distortion issues when I rotate the camera
By rotating the camera I mean rotating it about its Z axis with the X axis being left/right on the screen, the Y axis being up/down on the screen, and the Z axis protruding from the screen. so when I rotate the camera, the rest of the world should appear to be orbiting around the center of the screen
Here I have a perfectly square sprite
and when I rotate the camera it becomes stretched
note this doesn't happen when I rotate the sprite itself, only the camera
my current setup with my camera is
void Camera::SetOrthoMatrix(float width, float height, float nearZ, float farZ) //called when initializing the camera
{
orthoMatrix=XMMatrixOrthographicOffCenterLH(0.0f, width, 0.0f, height, nearZ, farZ);
}
void Camera::UpdateMatrix() //called whenever the camera's position or rotation changes
{
worldMatrix = XMMatrixTranslation(-pos.x, -pos.y, 0.0f) * XMMatrixRotationZ(rot);
}
XMMatrix Camera::GetViewMatrix()
{
return orthoMatrix * worldMatrix
}
My sprite class just takes it's own world matrix and multiplies it by camera.GetViewMatrix() and then I draw the sprite. I'm fairly certain that the distortion is caused by the orthographic matrix, but I can't figure out a way to fix it.
I figured it out by changing XMMatrixOrthographicOffCenterLH to XMMatrixOrthograpghicLH. then reordering the matrix multiplication from sprite, orthographic, camera to sprite, camera, orthographic.
this changes the coordinate system a little, before I had 0,0 be the bottom left corner of the screen but with XMMatrixOrthograpghicLH the origin is at the center of the screen. It's not quite what I wanted but it's a minor inconvenience.
I am trying to map screen pixels to openGL coordinates. Basically I have a 3D sphere drawn at position Vector3f(0,0,0) and radius=1 using glut.
glutSolidSphere(radius/*1*/,50,50);
This sphere, rather than appearing at the center of the screen appears in the top left quadrant of the screen. My goal is to convert a mouse click's location to openGL coordinates to find out what object on screen was clicked. I followed the link here to calculate the openGL coordinates using the formula
converted_x = 2.0f/screen_width*mouse_x - 1.0f
converted_y = 2.0f/screen_width*mouse_y - 1.0f
When I try to click on the center of the sphere, I get the click position (converted_x,converted_y) as (-0.62185,-0.607500) i.e., pixel location (mouse_x, mouse_y) is (242, 157). My screen resolution is 1280*800. I am not able to figure how I can use this information to figure out that the sphere was clicked. Any help is much appreciated.
Currently this is the code I have in reshape(), taken from an existing project.
void reshape(int w, int h)
{
// Adjust the viewport if the user resizes the window
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (h==0)
gluPerspective(80,(float)w,1.0,5000.0);
else
gluPerspective (80,( float )w /( float )h,1.0,5000.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
I have a scene which is basically a square floor measuring 15x15 (a quad with coordinates (0,0,0) (0,0,15) (15,0,15) (15,0,0) ).
I 've set the center-of-scene to be at (7.5,0,7.5). Problem is I can't figure out how to rotate the camera horizontally around that center of scene (aka make the camera do a 360 horizontal circle around center-of-scene). I know you need to do something with sin and cos, but don't know what exactly.
Here is the code (plain C):
//set camera position
//camera height is 17
GLfloat camx=0, camy=17, camz=0;
//set center of scene
GLfloat xref=7.5, yref=0, zref=7.5;
gluLookAt(camx, camy, camz, xref, yref, zref, 0, 1, 0);
//projection is standard gluPerspective, nothing special
gluPerspective(45, (GLdouble)width/(GLdouble)height, 1, 1000);
You need to modify the camx and camz variables.
The points you want to walk through lie on the circle and their coordinates are determined by x = r*sin(alpha) + 7.5, z = r*cos(alpha) + 7,5, where r is the radius of the circle and alpha is the angle between xy plane and the current position of your camera.
Of course the angle depends on the rotation speed and also on the time from the beginning of the animation. Basically, the only thing you need to do is to set the right angle and then calculate the coordinates from the expressions above.
For more info about the circle coordinates, see Wiki : http://en.wikipedia.org/wiki/Unit_circle
I think there are two ways you can use:
You can use sin/cos to compute your camx and camz position. This picture is a good example how this works.
An alternative would be to move the camera to 7.5, 0, 7.5, then rotate the camera with the camera angle you want. After that you move the camera by -7.5, 0, -7.5.
I'm having little trouble whit trying to compare rotated 2D Quads coordinates to rotated x and y coordinates. I'm trying to determine if mouse was clicked inside the quad.
1) the rot's are this classes objects: (note : the operator << is overloaded for the use of the rotate coords func)
class Vector{
private:
std::vector <float> Vertices;
public:
Vector(float, float);
float GetVertice(unsigned int);
void SetVertice(unsigned int, float);
std::vector<float> operator <<(double);
};
Vector::Vector(float X,float Y){
Vertices.push_back(X);
Vertices.push_back(Y);
}
float Vector::GetVertice(unsigned int Index){
return Vertices.at(Index);
}
void Vector::SetVertice(unsigned int Index,float NewVertice){
Vertices.at(Index) = NewVertice;
}
//Return rotated coords:D
std::vector <float> Vector::operator <<(double Angle){
std::vector<float> Temp;
Temp.push_back(Vertices.at(0) * cos(Angle) - Vertices.at(1) * sin(Angle));
Temp.push_back(Vertices.at(0) * sin(Angle) + Vertices.at(1) * cos(Angle));
return Temp;
}
2) Comparasion and rotation of the coordinates THE NEW VERSION
Vector Rot1(x,y),Rot3(x,y);
double Angle;
std::vector <float> result1,result3;
Rot3.SetVertice(0,NewQuads.at(Index).GetXpos() + NewQuads.at(Index).GetWidth());
Rot3.SetVertice(1,NewQuads.at(Index).GetYpos() + NewQuads.at(Index).GetHeight());
Angle = NewQuads.at(Index).GetRotation();
result1 = Rot1 << Angle; // Rotate the mouse x and y
result3 = Rot3 << Angle; // Rotate the Quad x and y
//.at(0) = x and .at(1)=y
if(result1.at(0) >= result3.at(0) - NewQuads.at(Index).GetWidth() && result1.at(0) <= result3.at(0) ){
if(result1.at(1) >= result3.at(1) - NewQuads.at(Index).GetHeight() && result1.at(1) <= result3.at(1) ){
when i run this it works perfectly at 0 angle but when you rotate the quad, it fails.
and by failing I mean the activation area seem to just disappear.
am I doing the rotation of the coordinates correctly? or is it the comparison?
if it's the comparison how would you do it properly, I have tried changing the if's but whit out any luck...
edit
the drawing of the quad(Happens before the testing):
void Quad::Render()
{
if(!CheckIfOutOfScreen()){
glPushMatrix();
glLoadIdentity();
glTranslatef(Xpos ,Ypos ,0.f);
glRotatef(Rotation,0.f,0.f,1.f); // same rotation is used for the testing later...
glBegin(GL_QUADS);
glVertex2f(Zwidth,Zheight);
glVertex2f(Width,Zheight);
glVertex2f(Width,Height);
glVertex2f(Zwidth,Height);
glEnd();
if(State != NOT_ACTIVE)
RenderShapeTools();
glPopMatrix();
}
}
basicly I'm trying to test if mouse was clicked inside this quad:
Image
There is more than one way to achieve what you want, But from the image you posted I assume you want to draw to a surface the same size as your screen (or window) using only 2D graphics.
As you know in 3D graphics we talk about 3 coordinate references. The first is the coordinate reference of the object or model to be drawn, the second is the coordinate reference of the camera or view and the third is the coordinate reference of the screen.
In OpenGL the first two coordinate references are established through the MODELVIEW matrix and the third is achieved by the PROJECTION matrix and the viewport transformation.
In your case you want to rotate a quad and place it somewhere on the screen. Your quad has it's own model coordinates. Let's assume that for this specific 2D quad the origin is at the center of the quad and it has the dimensions of 5 by 5. Also let's assume that if we look to the center of the quad then the X axis points to the RIGHT, the Y axis points UP and the Z axis points towards the viewer.
The unrotated coordinates of the quad will be (from bottom left clockwise): (-2.5,-2.5,0), (-2.5,2.5,0), (2.5,2.5,0), (2.5,-2.5,0)
Now we want to have a camera and projection matrices and viewport so to simulate a 2D surface with known dimensions.
//Assume WinW contains the window width and WinH contains the windows height
glViewport(0,0,WinW,WinH);//Set the viewport to the whole window
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, WinW, WinH, 0, 0, 1);//Set the projection matrix to perform a 2D orthogonal projection
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();//Set the camera matrix to be the Identity matrix
You are now ready to draw your quad an this 2D surface with dimensions WinW, WinH. In this context if you just draw your quad using it's current vertices you will have the quad drawn with it's center at the bottom left of the window with each side measuring 5 pixels so you will actually see only quarter of a quad. If you want to rotate and move it you will do something like this:
//Prepare matrices as shown above
//Viewport coordinates range from bottom left (0,0) to top right (WinW,WinH)
float dX = CenterOfQuadInViewportCoordinatesX, dY = CenterOfQuadInViewportCoordinatesY;
float rotA = QuadRotationAngleAroundZAxisInDegrees;
float verticesX[4] = {-2.5,-2.5,2.5,2.5};
float verticesY[4] = {-2.5,2.5,2.5,-2.5};
//Remember that rotate is done first and translation second
glTranslatef(dX,dY,0);//Move the quad to the desired location in the viewport
glRotate(rotA, 0,0,1);//Rotate the quad around it's origin
glBegin(GL_QUADS);
glVertex2f(verticesX[0], veriticesY[0]);
glVertex2f(verticesX[1], veriticesY[1]);
glVertex2f(verticesX[2], veriticesY[2]);
glVertex2f(verticesX[3], veriticesY[3]);
glEnd();
Now you want to know whether the click of the mouse was within the rendered quad.
Whereas the viewport coordinates start from the bottom left the window coordinates start from the top left. So when you get the mouse coordinates you have to translate them to viewport coordinates in the following way:
float mouseViewportX = mouseX, mouseViewportY = WinH - mouseY - 1;
Once you have the mouse location in viewport coordinates you need to transform it to model coordinates in the following way (Please double check the calculations since I generally use my own matrix library for that and don't calculate it by hand):
//Translate the mouse location to model coordinates reference
mouseViewportX -= dX, mouseViewportY -= dY;
//Unrotate the mouse location
float invRotARad = -rotA*DEG_TO_RAD;
float sinRA = sin(invRotARad), cosRA = cos(invRotA);
float mouseInModelX = cosRA*mouseViewportX - sinRA*mouseViewportY;
float mouseInModelY = sinRA*mouseViewportX + cosRA*mouseViewportY;
And now you can finally check if the mouse falls within the quad - as you can see this is done in quad coordinates:
bool mouseInQuad = mouseInModelX > verticesX[0] && mouseInModelY < verticesX[1] &&
mouseInModelY > verticesY[0] && mouseInModelY < verticesY[1];
Hope I didn't make too many mistakes and this puts you on the right track. If you want to deal with more complex cases and 3D then you should have a look at gluUnproject (maybe you will want to implement your own) and for even more complex scenes you may need to use a stencil or depth buffers
I have a main scene centered on the center of the viewport
in addition to that I want another small object to be displayed on the corner of the viewport.
The trouble is that when I draw the small object, it is transformed by the main projection transformation and appears slanted. I want the small object to have its own vanishing point centered in its center.
Is this possible which just transformations?
You want your main scene to be projected in one way and your corner object to be projected in another way. This directly leads you to the solution:
void render() {
glMatrixMode(GL_PROJECTION);
setUpMainProjection();
glMatrixMode(GL_MODELVIEW);
drawMainObject();
glMatrixMode(GL_PROJECTION);
setUpCornerProjection();
glMatrixMode(GL_MODELVIEW);
drawCornerObject();
}
Perhaps you're wondering how to implement setUpCornerProjection. It would look something like this:
// let's say r is a rect, which, in eye space, contains the corner object and is
// centered on it
glFrustum(r.left, r.right, r.bottom, r.top, nearVal, farVal);
// let's say p is the rect in screen-space where you want to
// place the corner object
glViewport(p.x, p.y, p.width, p.height);
And then in setUpMainProjection() you'd need to also call glFrustum and glViewport.