OpenGL - Why doesn't my ball move? - c++

In OpenGL, I'm building a football game that allows you to shoot a ball by first moving height indicators left and right, before shooting based on the indicators when a button is pressed. Here's what it looks like:
Football Game Visual
When these indicators are moved, my ball needs to travel at the height of the vertical indicator (y), and left or right direction if the vertical one (x).
Firstly, here's the code that moves my indicators (which are just textures being drawn in my RenderScene() function)
void SpecialKeys(int key, int x, int y){
if (key == GLUT_KEY_RIGHT) { // moves the bottom indicator RIGHT
horizontalBarX += 5.0f;
}
if (key == GLUT_KEY_LEFT) {
horizontalBarX -= 5.0f; // moves the bottom indicator LEFT
}
if (key == GLUT_KEY_UP) { // moves the top indicator UP
verticalBarY += 5.0f;
verticalBarX += 1.0f;
}
if (key == GLUT_KEY_DOWN) { // moves the top indicator DOWN
verticalBarY -= 5.0f;
verticalBarX -= 1.0f;
}
}
Calculations for my football to move
Now to get my football to move after the indicators have be moved, I need to apply the following calculations to the x, y and z axis of the ball:
x = sin(theta) * cos (phi) y = cos(theta) * sin(phi) z = cos(theta)
where theta = angle in z-x, and phi = angle in z-y
So with this, I have attempted to get the values of both theta and phi angles first, by simply incrementing them depending on what height indicators you have pressed in the SpecialKeys() function:
void SpecialKeys(int key, int x, int y){
if (key == GLUT_KEY_RIGHT) { // moves the bottom indicator RIGHT
horizontalBarX += 5.0f;
theta += 5; // Increase theta angle by 5
}
if (key == GLUT_KEY_LEFT) {
horizontalBarX -= 5.0f; // moves the bottom indicator LEFT
theta -= 5; // Decrease theta angle by 5
}
if (key == GLUT_KEY_UP) { // moves the top indicator UP
verticalBarY += 5.0f;
verticalBarX += 1.0f;
phi += 5; // Increase theta angle by 5
}
if (key == GLUT_KEY_DOWN) { // moves the top indicator DOWN
verticalBarY -= 5.0f;
verticalBarX -= 1.0f;
phi -= 5; // Decrease phi angle by 5
}
}
Now that I have the angles, I want to plug in the calculated values into the drawFootball() parameters, which by the way is initially called in my RenderScene function as...
drawFootBall(0, 40, 500, 50); // x,.y, z, r
...and here's how I'm attempting to launch the ball with the calculations above:
void SpecialKeys(int key, int x, int y){
// indicator if statements just above this line
if (key == GLUT_KEY_F1) {
drawFootBall(sin(theta)*cos(phi), cos(theta)*sin(phi), cos(theta), 50);
}
}
But when I go to click the launch button F1, nothing happens at all. Where have I messed up?
EDIT:
If it helps, here's my drawFootball() function:
void drawFootBall(GLfloat x, GLfloat y, GLfloat z, GLfloat r)
{
glPushMatrix();
glFrontFace(GL_CCW);
glTranslatef(x,y,z);
//create ball texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BALL]);
//glDisable(GL_LIGHTING);
glColor3f(0.5,0.5,0.5);
quadricFootball = gluNewQuadric();
gluQuadricDrawStyle(quadricFootball, GLU_FILL);
gluQuadricNormals(quadricFootball, GLU_SMOOTH);
gluQuadricOrientation(quadricFootball, GLU_OUTSIDE);
gluQuadricTexture(quadricFootball, GL_TRUE);
gluSphere(quadricFootball, r, 85, 50);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}

Firstly make sure your theta and phi are in the right units i.e. Radians. If in degrees convert them to radians by using sin(theta * PI/180.0f) and so on, assuming PI is defined.
I believe what you are computing there is a direction vector for the Ball. The d(x,y,z) is the direction in which the ball should travel, (assuming there is no gravity or other forces). Its probably the direction in which the ball is kicked.
I think if you simply wanted to move your ball, you need to multiply this direction with a length. Since your ball has a radius of 50 units, try translating to 2 times this radius.
glTranslatef(2.0f*r*x,2.0f*r*y,2.0f*r*z);
This will move the ball to 2 times its radius in your desired direction.
However you probably want to have some physics to have a more realistic movement.

Related

Rotation of a boat animation in C++

I'm creating an attack boat game in c++ and I have an issue with my boat following the mouse around the screen. My plan is to have the boat follow the mouse more like a boat (slow rotations, instead of instantaneous whilst taking about 4 seconds to do a 360 turn) and for the most part it does what it should.
The bug happens when the mouse is on the left side of the screen (as soon as my mouse crosses the -x axis), as the boat follows the mouse, the boat turns in the wrong direction and does a 360, instead of following the mouse.
This is the code i'm using to do my boat turning.
angle = atan2(delta_y, delta_x) * 180.0 / PI;
//Rotate the boat towards the mouse and
//make the boat turn more realistically
if (angle - rotate > 0) {
rotate += 1.0f; // turns left
} else if (angle - rotate < 0) {
rotate -= 1.0f; // turns right
}
if (angle - rotate >= 360.0f) {
rotate = 0.0f;
}`
you forget to clamp the angle difference. It should be on interval <-pi,+pi> [rad] so any angle difference outside this interval will lead to such problems. Try this instead:
angle = atan2(delta_y, delta_x) * 180.0 / PI; // target [deg]
da = angle-rotate; // unclamped delta [deg]
while (da<-180.0f) da+=360.0f;
while (da>+180.0f) da-=360.0f;
if (da >= +1.0f) rotate += 1.0f;
else if (da <= -1.0f) rotate -= 1.0f;
else rotate = 0.0f;

Moving a drawing around in openGL with mouse

I am trying to move an image around in openGL while holding left mouse button.
i am NOT trying to drag an object around, just move the whole picture. Its a 2d drawing of a fractal and i was told that i can use gluortho2d but i can't find any info or similar tries on how to do it.
I am assuming something like
void mouse_callback_func(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
gluOrtho2D(x-250.0, x+250.0, y-250.0,y+250.);
glutPostRedisplay();
}
for a 500x500 window,but it's not working. The moment i left click the window goes blank.
Any ideas?
gluOrtho2D modifies the current matrix. It's designed to be used with glMatrixMode(GL_PROJECTION), for example:
glMatrixMode(GL_PROJECTION); //start editing the projection matrix
glLoadIdentity(); //remove current projection
gluOrtho2D(...); //create new one
glMatrixMode(GL_MODELVIEW); //back to editing the modelview matrix
It might be more simple to set up a camera concept...
float cameraX, cameraY;
int lastMouseX, lastMouseY;
void mouse_callback_func(int button, int state, int x, int y)
{
int dx = x - lastMouseX;
int dy = y - lastMouseY;
const float speed = 0.1f;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
cameraX += dx * speed; //or -=, depending on which direction feels more natural to you
cameraY -= dy * speed; //-= as mouse origin is top left, so +y is moving down
glutPostRedisplay();
}
lastMouseX = x;
lastMouseX = y;
}
void display()
{
glLoadIdentity(); //remove transforms from previous display() call
glTranslatef(-cameraX, -cameraY, 0.0f); //move objects negative = move camera positive
...

OpenGl - Object inverts after 180 degrees of rotation

I have an object rendered and I'm trying to rotate the object with the mouse. The object will rotate fine for 180 degrees but after that, the object inverts (if facing toward camera, switches to face away from camera) as does the expected movement of the mouse i.e. if dragging the mouse to the right rotates the object clockwise, then it will now rotate anti-clockwise. Once it reaches the next 180 degrees, it inverts again and normality is restored. I'm sure there must be something simple that I'm just not seeing?
Here is my code:
// Detect mouse state
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
moving = 1;
beginX = x;
beginY = y;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
{
moving = 0;
}
}
// Detect mouse movement
void motion(int x, int y)
{
if (moving)
{
angleX = (angleX + (x - beginX));
angleY = (angleY + (y - beginY));
beginX = x;
beginY = y;
newModel = 1;
glutPostRedisplay();
}
}
// Rotate object
void recalcModelView(void)
{
// Get object's centre
int hh = head->GetHeight() / 2;
int hw = head->GetWidth() / 2;
int hd = head->GetDepth() / 2;
glPopMatrix();
glPushMatrix();
// Rotate object based on mouse movement
glTranslatef(hw, hd, hh);
float temp1 = angleX / 5;
float temp2 = angleY / 5;
printf("TEMP1: %g\n", temp1);
printf("TEMP2: %g\n", temp2);
glRotatef(temp1, 0.0, 1.0, 0.0);
glRotatef(-temp2, 1.0, 0.0, 0.0);
glTranslatef(-hw, -hd, -hh);
newModel = 0;
}
Use something like Arcball to fix this.

OpenGL Matrix Camera controls, local rotation not functioning properly

So I'm trying to figure out how to mannually create a camera class that creates a local frame for camera transformations. I've created a player object based on OpenGL SuperBible's GLFrame class.
I got keyboard keys mapped to the MoveUp, MoveRight and MoveForward functions and the horizontal and vertical mouse movements are mapped to the xRot variable and rotateLocalY function. This is done to create a FPS style camera.
The problem however is in the RotateLocalY. Translation works fine and so does the vertical mouse movement but the horizontal movement scales all my objects down or up in a weird way. Besides the scaling, the rotation also seems to restrict itself to 180 degrees and rotates around the world origin (0.0) instead of my player's local position.
I figured that the scaling had something to do with normalizing vectors but the GLframe class (which I used for reference) never normalized any vectors and that class works just fine. Normalizing most of my vectors only solved the scaling and all the other problems were still there so I'm figuring one piece of code is causing all these problems?
I can't seem to figure out where the problem lies, I'll post all the appropriate code here and a screenshot to show the scaling.
Player object
Player::Player()
{
location[0] = 0.0f; location[1] = 0.0f; location[2] = 0.0f;
up[0] = 0.0f; up[1] = 1.0f; up[2] = 0.0f;
forward[0] = 0.0f; forward[1] = 0.0f; forward[2] = -1.0f;
}
// Does all the camera transformation. Should be called before scene rendering!
void Player::ApplyTransform()
{
M3DMatrix44f cameraMatrix;
this->getTransformationMatrix(cameraMatrix);
glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
glMultMatrixf(cameraMatrix);
}
void Player::MoveForward(GLfloat delta)
{
location[0] += forward[0] * delta;
location[1] += forward[1] * delta;
location[2] += forward[2] * delta;
}
void Player::MoveUp(GLfloat delta)
{
location[0] += up[0] * delta;
location[1] += up[1] * delta;
location[2] += up[2] * delta;
}
void Player::MoveRight(GLfloat delta)
{
// Get X axis vector first via cross product
M3DVector3f xAxis;
m3dCrossProduct(xAxis, up, forward);
location[0] += xAxis[0] * delta;
location[1] += xAxis[1] * delta;
location[2] += xAxis[2] * delta;
}
void Player::RotateLocalY(GLfloat angle)
{
// Calculate a rotation matrix first
M3DMatrix44f rotationMatrix;
// Rotate around the up vector
m3dRotationMatrix44(rotationMatrix, angle, up[0], up[1], up[2]); // Use up vector to get correct rotations even with multiple rotations used.
// Get new forward vector out of the rotation matrix
M3DVector3f newForward;
newForward[0] = rotationMatrix[0] * forward[0] + rotationMatrix[4] * forward[1] + rotationMatrix[8] * forward[2];
newForward[1] = rotationMatrix[1] * forward[1] + rotationMatrix[5] * forward[1] + rotationMatrix[9] * forward[2];
newForward[2] = rotationMatrix[2] * forward[2] + rotationMatrix[6] * forward[1] + rotationMatrix[10] * forward[2];
m3dCopyVector3(forward, newForward);
}
void Player::getTransformationMatrix(M3DMatrix44f matrix)
{
// Get Z axis (Z axis is reversed with camera transformations)
M3DVector3f zAxis;
zAxis[0] = -forward[0];
zAxis[1] = -forward[1];
zAxis[2] = -forward[2];
// Get X axis
M3DVector3f xAxis;
m3dCrossProduct(xAxis, up, zAxis);
// Fill in X column in transformation matrix
m3dSetMatrixColumn44(matrix, xAxis, 0); // first column
matrix[3] = 0.0f; // Set 4th value to 0
// Fill in the Y column
m3dSetMatrixColumn44(matrix, up, 1); // 2nd column
matrix[7] = 0.0f;
// Fill in the Z column
m3dSetMatrixColumn44(matrix, zAxis, 2); // 3rd column
matrix[11] = 0.0f;
// Do the translation
M3DVector3f negativeLocation; // Required for camera transform (right handed OpenGL system. Looking down negative Z axis)
negativeLocation[0] = -location[0];
negativeLocation[1] = -location[1];
negativeLocation[2] = -location[2];
m3dSetMatrixColumn44(matrix, negativeLocation, 3); // 4th column
matrix[15] = 1.0f;
}
Player object header
class Player
{
public:
//////////////////////////////////////
// Variables
M3DVector3f location;
M3DVector3f up;
M3DVector3f forward;
GLfloat xAngle; // Used for FPS divided X angle rotation (can't combine yaw and pitch since we'll also get a Roll which we don't want for FPS)
/////////////////////////////////////
// Functions
Player();
void ApplyTransform();
void MoveForward(GLfloat delta);
void MoveUp(GLfloat delta);
void MoveRight(GLfloat delta);
void RotateLocalY(GLfloat angle); // Only need rotation on local axis for FPS camera style. Then a translation on world X axis. (done in apply transform)
private:
void getTransformationMatrix(M3DMatrix44f matrix);
};
Applying transformations
// Clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Apply camera transforms
player.ApplyTransform();
// Set up lights
...
// Use shaders
...
// Render the scene
RenderScene();
// Do post rendering operations
glutSwapBuffers();
and mouse
float mouseSensitivity = 500.0f;
float horizontal = (width / 2) - mouseX;
float vertical = (height / 2) - mouseY;
horizontal /= mouseSensitivity;
vertical /= (mouseSensitivity / 25);
player.xAngle += -vertical;
player.RotateLocalY(horizontal);
glutWarpPointer((width / 2), (height / 2));
Honestly I think you are taking a way to complicated approach to your problem. There are many ways to create a camera. My favorite is using a R3-Vector and a Quaternion, but you could also work with a R3-Vector and two floats (pitch and yaw).
The setup with two angles is simple:
glLoadIdentity();
glTranslatef(-pos[0], -pos[1], -pos[2]);
glRotatef(-yaw, 0.0f, 0.0f, 1.0f);
glRotatef(-pitch, 0.0f, 1.0f, 0.0f);
The tricky part now is moving the camera. You must do something along the lines of:
flaot ds = speed * dt;
position += tranform_y(pich, tranform_z(yaw, Vector3(ds, 0, 0)));
How to do the transforms, I would have to look that up, but you could to it by using a rotation matrix
Rotation is trivial, just add or subtract from the pitch and yaw values.
I like using a quaternion for the orientation because it is general and thus you have a camera (any entity that is) that independent of any movement scheme. In this case you have a camera that looks like so:
class Camera
{
public:
// lots of stuff omitted
void setup();
void move_local(Vector3f value);
void rotate(float dy, float dz);
private:
mx::Vector3f position;
mx::Quaternionf orientation;
};
Then the setup code uses shamelessly gluLookAt; you could make a transformation matrix out of it, but I never got it to work right.
void Camera::setup()
{
// projection related stuff
mx::Vector3f eye = position;
mx::Vector3f forward = mx::transform(orientation, mx::Vector3f(1, 0, 0));
mx::Vector3f center = eye + forward;
mx::Vector3f up = mx::transform(orientation, mx::Vector3f(0, 0, 1));
gluLookAt(eye(0), eye(1), eye(2), center(0), center(1), center(2), up(0), up(1), up(2));
}
Moving the camera in local frame is also simple:
void Camera::move_local(Vector3f value)
{
position += mx::transform(orientation, value);
}
The rotation is also straight forward.
void Camera::rotate(float dy, float dz)
{
mx::Quaternionf o = orientation;
o = mx::axis_angle_to_quaternion(horizontal, mx::Vector3f(0, 0, 1)) * o;
o = o * mx::axis_angle_to_quaternion(vertical, mx::Vector3f(0, 1, 0));
orientation = o;
}
(Shameless plug):
If you are asking what math library I use, it is mathex. I wrote it...

How to move an object around a 3D environment in the direction it is facing in C++

I am trying to move a pyramid around in opengl in C++ and I am trying to get it to move forward in the direction it is facing. However, I cannot seem to figure out how to do this. This is my code for drawing my pyramid:
void drawTriangle()
{
//back
glBegin(GL_POLYGON);
glColor3f(1,0,0);
glVertex3f(-1,-1,-1);
glVertex3f(1,-1,-1);
glVertex3f(0,1,0);
glEnd();
//front
glBegin(GL_POLYGON);
glColor3f(0,1,0);
glVertex3f(-1,-1,1);
glVertex3f(1,-1,1);
glVertex3f(0,1,0);
glEnd();
//right
glBegin(GL_POLYGON);
glColor3f(0,0,1);
glVertex3f(1,-1,-1);
glVertex3f(1,-1,1);
glVertex3f(0,1,0);
glEnd();
//left
glBegin(GL_POLYGON);
glColor3f(1,1,0);
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(0,1,0);
glEnd();
//bottom
glBegin(GL_POLYGON);
glColor3f(1,0,1);
glVertex3f(-1,-1,-1);
glVertex3f(1,-1,-1);
glVertex3f(1,-1,1);
glVertex3f(-1,-1,1);
glEnd();
}
This is how the pyramid is drawn to the screen:
glPushMatrix();
glTranslatef(Xtri,0,Ztri);
glRotatef(heading,0,1,0);
drawTriangle();
glPopMatrix();
glFlush();
And here is how the variables are updated so that the pyramid could move around :
void processKeys()
{
if(keys[VK_LEFT])
{
heading-=1.0f;
}
if(keys[VK_RIGHT])
{
heading+=1.0f;
}
if(keys[VK_UP])
{
Vtri-=0.001f;
}
if(keys[VK_DOWN])
{
Vtri+=0.001f;
}
}
void update()
{
Xtri += Vtri*cos((90+heading)*(PI/180.0f));
Ztri += Vtri*sin((90+heading)*(PI/180.0f));
}
I am trying to get the pyramid to move forward so that the red or back face is the face that I want to be the direction that the pyramid moves in but when I use this code it doesn't work that way at all and it moves in a very funny way.
Here's one way you can do it. It's based on Direct3D, but I assume it should be very similar for OpenGL.
Have two vectors for your pyramid: one containing its position and another one containing its rotation. Initially both initialized to 0,0,0. Also have a direction vector initially facing in the direction your object does (e.g. 1,0,0) and speed, again set to 0.
Upon pressing a or d adjust the y element of the rotation vector to a desired angle. Similarly upon pressing w or s adjust the speed of your object. You probably want to take frame rendering time into account to make the movement fps independent.
Then create a rotation matrix around Y axis, like you do. Use that matrix to create new normalized vector by multiplying it with the initial position vector. Then add this vector multiplied by speed to your position coordinates and use these coordinates for translation matrix.
Hope it makes sense. Here's some pseudo-code:
// in constructor:
x = y = z = 0.0f; // position
ry = 0.0f; // rotation
speed = 0.0f;
initVec(1,0,0); // initial direction vector
// in event handler:
// upon key press adjust speed and/or ry
// in move():
// create rotation matrix around Y axis by ry = rotationMatrix
// use it to find new direction vector
newDirectionVector = initVec * rotationMatrix;
// adjust your position
x += newDirectionVector * speed;
y += newDirectionVector * speed;
z += newDirectionVector * speed;
glTranslatef(x, y, z);
// render
I came across this when searching for ideas for a similar problem, and decided to share my solution:
For a triangle with 1 unit base, and 2 units height, on y = 0.3 = pos[2]
void triangle::draw() {
glPushMatrix();
//pos[0] is the x value initialized to 0
//pos[2] is the z value initialized to 0
glTranslatef(pos[0], 0, pos[2]);
glRotatef(direction, 0, 1, 0);
glBegin(GL_TRIANGLES);
glVertex3f(.5, pos[1], 0);
glVertex3f(-.5, pos[1], 0);
glVertex3f(0, pos[1], 2);
glEnd();
glPopMatrix();
}
//called when key w is pressed
void triangle::forward() {
// convert degrees to rads and multiply (I used 0.5)
pos[0] += sin(M_PI * direction / 180) * .5;
pos[2] += cos(M_PI * direction / 180) * .5;
std::cout << pos[0] << "," << pos[2] << std::endl;
}
//called when key s is pressed
void triangle::back() {
pos[0] -= sin(M_PI * direction / 180) * .5;
pos[2] -= cos(M_PI * direction / 180) * .5;
std::cout << pos[0] << "," << pos[2] << std::endl;
}
//called when key d is pressed
void triangle::right() {
direction -= 5;
//direction is the angle (int)
//this is probably not needed but, if you keep turning in the same direction
//an overflow is not going to happen
if (direction <= 360)direction %= 360;
std::cout << direction << std::endl;
}
//called when key a is pressed
void triangle::left() {
direction += 5;
if (direction >= -360)direction %= 360;
std::cout << direction << std::endl;
}
Hope I was of help, for someone facing similar problems bumping into this.
You need to do rotations before translations, assuming your object is at the origin to begin with (if I recall my math correctly). I believe the rotation matrix applied rotates around the axis (0, 1, 0), if you've already translated to a new location, that rotation will affect your position as well as direction you are facing.