How to move object towards an angle in degrees? (C, C++) - c++

I'm trying to move a bullet object towards a player position. I found this angle function online, and it seems to convert it to those coordinates in the comments. But i can't make the bullet follow in the direction.
float Angle(int p1x, int p1y, int p2x,int p2y)
{
//Make point1 the origin, make point2 relative to the origin so we do point1 - point1, and point2-point1,
//since we dont need point1 for the equation to work, the equation works correctly with the origin 0,0.
int deltaY = p2y - p1y;
int deltaX = p2x - p1x; //Vector 2 is now relative to origin, the angle is the same, we have just transformed it to use the origin.
float angleInDegrees = atan2(deltaY, deltaX) * 180 / PI;
//float angleInRadians = atan2(deltaY, deltaX);
angleInDegrees *= -1; // Y axis is inverted in computer windows, Y goes down, so invert the angle.
//Angle returned as:
// 90
// 135 45
//
// 180 Origin 0
//
// -135 -45
//
// -90
return angleInDegrees;
}
if (bulletsData[3] == STDEACTIVE){ //bulletData: 0 = x, 1 = y, 2 = dir, 3 = state
bulletsData[2] = Angle(bulletsData[0],bulletsData[1], plData[0], plData[1]);
bulletsData[3] = STACTIVE;
}
if (bulletsData[3] == STACTIVE){
if (ardu.everyXFrames(1)){
bulletsData[0] += cos(bulletsData[2]) * 1; //My attempt to move it towards the direction.
bulletsData[1] += sin(bulletsData[2]) * 1;
}
}

You are explicitly calculating angles in degrees, yet sin and cos expect radians, not degrees.
Without analyzing whether or not the Angle function is correct, your code will make more sense if you change the function to return a value in radians. You even have the required line there commented out.
So, something like this perhaps:
float angleInRadians = atan2(deltaY, deltaX);
return -angleInRadians; // Return negative angle to compensate for Y-down

Related

raytracing: why is my sphere rendered as an oval?

I am to write a raytracer, however I already seem to hit my first big problem. For whatever reason, my sphere (which - since I only begin - I simply color white when a ray hits) is rendered as an oval.
Furthermore, it seems that the distortion is getting worse, the farther I am moving the sphere's center away from x = 0 and y = 0
Here's the intersection and main-loop code:
double const Sphere::getIntersection(Ray const& ray) const
{
double t;
double A = 1;
double B = 2*( ray.dir[0]*(ray.origin[0] - center_[0]) + ray.dir[1] * (ray.origin[1] - center_[1]) + ray.dir[2] * (ray.origin[2] - center_[2]));
double C = pow(ray.origin[0]-center_[0], 2) + pow(ray.origin[1]-center_[1], 2) + pow(ray.origin[2] - center_[2], 2) - radius_pow2_;
double discr = B*B - 4*C;
if(discr > 0)
{
t = (-B - sqrt(discr))/2;
if(t <= 0)
{
t = (-B + sqrt(discr))/2;
}
}
else t = 0;
return t;
}
Sphere blub = Sphere(math3d::point(300., 300., -500.), 200.);
Ray mu = Ray();
// for all pixels of window
for (std::size_t y = 0; y < window.height(); ++y) {
for (std::size_t x = 0; x < window.width(); ++x) {
Pixel p(x, y);
mu = Ray(math3d::point(0., 0., 0.), math3d::vector(float(x), float(y), -300.));
if (blub.getIntersection(mu) == 0. ) {
p.color = Color(0.0, 0.0, 0.0);
} else {
p.color = Color(1., 1., 1.);
}
}
}
What I also do not understand is why my "oval" isn't centered on the picture. I have a window of 600 x 600 pixels, so putting the sphere's center at 300 x 300 should afaik put the sphere in the center of the window as well.
my specific solution
(Thanks to Thomas for pushing me to the right direction!)
As Thomas rightly said, my questions where two distinct problems. Considering projecting the sphere in the center, I did as he suggested and changed the origin and projections of the rays.
To get the perspective right, I did not realize I already had to calculate the focal length from the dimensions.
focal_length = sqrt(width^2 + height^2) / ( 2*tan( 45/2 ) )
The result:
This is normal for linear perspective projections, and exacerbated by wide camera angles; see http://en.wikipedia.org/wiki/Perspective_projection_distortion. Most games use something like 90 degrees in the horizontal direction, 45 on either side. But by casting rays up across 600 pixels in the x direction but 300 in the z direction, yours is significantly wider, 126 degrees to be precise.
The reason why your sphere doesn't appear centered is that you're casting rays from the bottom left corner of the screen:
mu = Ray(math3d::point(0.,0.,0.),math3d::vector(float(x),float(y),-300.));
That should be something like:
mu = Ray(math3d::point(width/2,height/2,0.),math3d::vector(float(x-width/2),float(y-height/2),-300.));

Rotating around a sphere using OpenGL and gluLookAt

Alright, so I'm trying to click and drag to rotate around an object using C++ and OpenGL. The way I have it is to use gluLookAt centered at the origin and I'm getting coordinates for the eye by using parametric equations for a sphere (eyex = 2* cos(theta) * sin(phi); eyey = 2* sin(theta) * sin(phi); eyez = 2* cos(phi);). This works mostly, as I can click and rotate horizontally, but when I try to rotate vertically it makes tight circles instead of rotating vertically. I'm trying to get the up vector by using the position of the camera and a vecter at a 90 degree angle along the x-z plane and taking the cross product of that.
The code I have is as follows:
double dotProduct(double v1[], double v2[]) {
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void mouseDown(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
xpos = x;
ypos = y;
}
}
void mouseMovement(int x, int y) {
diffx = x - xpos;
diffy = y - ypos;
xpos = x;
ypos = y;
}
void camera (void) {
theta += 2*PI * (-diffy/glutGet(GLUT_SCREEN_HEIGHT));
phi += PI * (-diffx/glutGet(GLUT_WINDOW_WIDTH));
eyex = 2* cos(theta) * sin(phi);
eyey = 2* sin(theta) * sin(phi);
eyez = 2* cos(phi);
double rightv[3], rightt[3], eyes[3];
rightv[0] = 2* cos(theta + 2/PI) * sin(phi);
rightv[1] = 0;
rightv[2] = 2* cos(phi);
rightt[0] = rightv[0];
rightt[1] = rightv[1];
rightt[2] = rightv[2];
rightv[0] = rightv[0] / sqrt(dotProduct(rightt, rightt));
rightv[1] = rightv[1] / sqrt(dotProduct(rightt, rightt));
rightv[2] = rightv[2] / sqrt(dotProduct(rightt, rightt));
eyes[0] = eyex;
eyes[1] = eyey;
eyes[2] = eyez;
upx = (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[2] + (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[1];
upy = (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[0] + (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[2];
upz = (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[1] + (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[0];
diffx = 0;
diffy = 0;
}
I am somewhat basing things off of this but it doesn't work, so I tried my way instead.
This isn't exactly a solution for the way you are doing it but I did something similar the other day. I did it by using DX's D3DXMatrixRotationAxis and D3DXVec3TransformCoord The math behind the D3DXMatrixRotationAxis method can be found at the bottom of the following page: D3DXMatrixRotationAxis Math use this if you are unable to use DX. This will allow you to rotate around any axis you pass in. In my object code I keep track of a direction and up vector and I simply rotate each of these around the axis of movement(in your case the yaw and pitch).
To implement the fixed distance camera like this I would simply do the dot product of the current camera location and the origin location (if this never changes then you can simply do it once.) and then move the camera to the origin rotate it the amount you need then move it back with its new direction and up values.

Getting a Virtual Trackball to work from any viewing angle

I am currently trying to work on getting my virtual trackball to work from any angle. When I am looking at it from the z axis, it seems to work fine. I hold my mouse down, and move the mouse up... the rotation will move accordingly.
Now, if I change my viewing angle / position of my camera and try to move my mouse. The rotation will occur as if I were looking from the z axis. I cannot come up with a good way to get this to work.
Here is the code:
void Renderer::mouseMoveEvent(QMouseEvent *e)
{
// Get coordinates
int x = e->x();
int y = e->y();
if (isLeftButtonPressed)
{
// project current screen coordinates onto hemi sphere
Point sphere = projScreenCoord(x,y);
// find axis by taking cross product of current and previous hemi points
axis = Point::cross(previousPoint, sphere);
// angle can be found from magnitude of cross product
double length = sqrt( axis.x * axis.x + axis.y * axis.y + axis.z * axis.z );
// Normalize
axis = axis / length;
double lengthPrev = sqrt( previousPoint.x * previousPoint.x + previousPoint.y * previousPoint.y + previousPoint.z * previousPoint.z );
double lengthCur = sqrt( sphere.x * sphere.x + sphere.y * sphere.y + sphere.z * sphere.z );
angle = asin(length / (lengthPrev * lengthCur));
// Convert into Degrees
angle = angle * 180 / M_PI;
// 'add' this rotation matrix to our 'total' rotation matrix
glPushMatrix(); // save the old matrix so we don't mess anything up
glLoadIdentity();
glRotatef(angle, axis[0], axis[1], axis[2]); // our newly calculated rotation
glMultMatrixf(rotmatrix); // our previous rotation matrix
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*) rotmatrix); // we've let OpenGL do our matrix mult for us, now get this result & store it
glPopMatrix(); // return modelview to its old value;
}
// Project screen coordinates onto a unit hemisphere
Point Renderer::projScreenCoord(int x, int y)
{
// find projected x & y coordinates
double xSphere = ((double)x/width)*2.0 - 1.0;
double ySphere = ( 1 - ((double)y/height)) * 2.0 - 1.0;
double temp = 1.0 - xSphere*xSphere - ySphere*ySphere;
// Do a check so you dont do a sqrt of a negative number
double zSphere;
if (temp < 0){ zSphere = 0.0;}
else
{zSphere = sqrt(temp);}
Point sphere(xSphere, ySphere, zSphere);
// return the point on the sphere
return sphere;
}
I am still fairly new at this. Sorry for the trouble and thanks for all the help =)
The usual way involves quaternions. E.g., in sample code originally from SGI.

Bullet algorithm having trouble with rotation on the X

Here is what I'm trying to do. I'm trying to make a bullet out of the center of the screen. I have an x and y rotation angle. The problem is the Y (which is modified by rotation on the x) is really not working as intended. Here is what I have.
float yrotrad, xrotrad;
yrotrad = (Camera.roty / 180.0f * 3.141592654f);
xrotrad = (Camera.rotx / 180.0f * 3.141592654f);
Vertex3f Pos;
// get camera position
pls.x = Camera.x;
pls.y = Camera.y;
pls.z = Camera.z;
for(float i = 0; i < 60; i++)
{
//add the rotation vector
pls.x += float(sin(yrotrad)) ;
pls.z -= float(cos(yrotrad)) ;
pls.y += float(sin(twopi - xrotrad));
//translate camera coords to cube coords
Pos.x = ceil(pls.x / 3);
Pos.y = ceil((pls.y) / 3);
Pos.z = ceil(pls.z / 3);
if(!CubeIsEmpty(Pos.x,Pos.y,Pos.z)) //remove first cube that made contact
{
delete GetCube(Pos.x,Pos.y,Pos.z);
SetCube(0,Pos.x,Pos.y,Pos.z);
return;
}
}
This is almost identical to how I move the player, I add the directional vector to the camera then find which cube the player is on. If I remove the pls.y += float(sin(twopi - xrotrad)); then I clearly see that on the X and Z, everything is pointing as it should. When I add pls.y += float(sin(twopi - xrotrad)); then it almost works, but not quite, what I observed from rendering out spheres of the trajector is that the furthur up or down I look, the more offset it becomes rather than stay alligned to the camera's center. What am I doing wrong?
Thanks
What basically happens is very difficult to explain, I'd expect the bullet at time 0 to always be at the center of the screen, but it behaves oddly. If i'm looking straight at the horizon to +- 20 degrees upward its fine but then it starts not following any more.
I set up my matrix like this:
void CCubeGame::SetCameraMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(Camera.rotx,1,0,0);
glRotatef(Camera.roty,0,1,0);
glRotatef(Camera.rotz,0,0,1);
glTranslatef(-Camera.x , -Camera.y,-Camera.z );
}
and change the angle like this:
void CCubeGame::MouseMove(int x, int y)
{
if(!isTrapped)
return;
int diffx = x-lastMouse.x;
int diffy = y-lastMouse.y;
lastMouse.x = x;
lastMouse.y = y;
Camera.rotx += (float) diffy * 0.2;
Camera.roty += (float) diffx * 0.2;
if(Camera.rotx > 90)
{
Camera.rotx = 90;
}
if(Camera.rotx < -90)
{
Camera.rotx = -90;
}
if(isTrapped)
if (fabs(ScreenDimensions.x/2 - x) > 1 || fabs(ScreenDimensions.y/2 - y) > 1) {
resetPointer();
}
}
You need to scale X and Z by cos(xradrot). (In other words, multiply by cos(xradrot)).
Imagine you're pointing straight down the Z axis but looking straight up. You don't want the bullet to shoot down the Z axis at all, this is why you need to scale it. (It's basically the same thing that you're doing between X and Z, but now doing it on the XZ vector and Y.)
pls.x += float(sin(yrotrad)*cos(xrotrad)) ;
pls.z -= float(cos(yrotrad)*cos(xrotrad)) ;
pls.y += float(sin(twopi - xrotrad));

Rotating coordinates around an axis

I'm representing a shape as a set of coordinates in 3D, I'm trying to rotate the whole object around an axis (In this case the Z axis, but I'd like to rotate around all three once I get it working).
I've written some code to do this using a rotation matrix:
//Coord is a 3D vector of floats
//pos is a coordinate
//angles is a 3d vector, each component is the angle of rotation around the component axis
//in radians
Coord<float> Polymers::rotateByMatrix(Coord<float> pos, const Coord<float> &angles)
{
float xrot = angles[0];
float yrot = angles[1];
float zrot = angles[2];
//z axis rotation
pos[0] = (cosf(zrot) * pos[0] - (sinf(zrot) * pos[1]));
pos[1] = (sinf(zrot) * pos[0] + cosf(zrot) * pos[1]);
return pos;
}
The image below shows the object I'm trying to rotate (looking down the Z axis) before the rotation is attempted, each small sphere indicates one of the coordinates I'm trying to rotate
alt text http://www.cs.nott.ac.uk/~jqs/notsquashed.png
The rotation is performed for the object by the following code:
//loop over each coordinate in the object
for (int k=start; k<finish; ++k)
{
Coord<float> pos = mp[k-start];
//move object away from origin to test rotation around origin
pos += Coord<float>(5.0,5.0,5.0);
pos = rotateByMatrix(pos, rots);
//wrap particle position
//these bits of code just wrap the coordinates around if the are
//outside of the volume, and write the results to the positions
//array and so shouldn't affect the rotation.
for (int l=0; l<3; ++l)
{
//wrap to ensure torroidal space
if (pos[l] < origin[l]) pos[l] += dims[l];
if (pos[l] >= (origin[l] + dims[l])) pos[l] -= dims[l];
parts->m_hPos[k * 4 + l] = pos[l];
}
}
The problem is that when I perform the rotation in this way, with the angles parameter set to (0.0,0.0,1.0) it works (sort of), but the object gets deformed, like so:
alt text http://www.cs.nott.ac.uk/~jqs/squashed.png
which is not what I want. Can anyone tell me what I'm doing wrong and how I can rotate the entire object around the axis without deforming it?
Thanks
nodlams
Where you do your rotation in rotateByMatrix, you compute the new pos[0], but then feed that into the next line for computing the new pos[1]. So the pos[0] you're using to compute the new pos[1] is not the input, but the output. Store the result in a temp var and return that.
Coord<float> tmp;
tmp[0] = (cosf(zrot) * pos[0] - (sinf(zrot) * pos[1]));
tmp[1] = (sinf(zrot) * pos[0] + cosf(zrot) * pos[1]);
return tmp;
Also, pass the pos into the function as a const reference.
const Coord<float> &pos
Plus you should compute the sin and cos values once, store them in temporaries and reuse them.