OpenGL - FPS style Camera move with object fixed on camera - opengl

I am trying to move a camera in a 3d space. So far I have had success in moving and rotating the camera using this code:
void specialKeyHandler(int key, int x, int y) {
float fraction = 0.05f;
switch (key) {
case GLUT_KEY_LEFT :
camAngle -= 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_RIGHT :
camAngle += 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_UP :
iX += lX * fraction;
iZ += lZ * fraction;
break;
case GLUT_KEY_DOWN :
iX -= lX * fraction;
iZ -= lZ * fraction;
break;
default:
break;
}
}
Of course I have these variables defined. lX, lY, lZ are for LookAt variables and iX, iY and iZ are for camera's eye.
The camera moves as required, but now I want to attach an object on the "camera's eye" which shall move with the camera. Just like a Weapon in a FPS game.
This is what I have for that:
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEarth();
drawWalls();
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX+0.05,iY, iZ-0.05);
glRotatef(camAngle, 0,1,0);
glutWireCone(0.005,0.1,20,20); // object to go with camera
glPopMatrix();
glutSwapBuffers();
}
This code currently does bind the object with the camera while moving up and down. But when I rotate the camera by pressing left and right keys, object stays there and camera moves on its own..
Any solution?
Here's the full opengl code, if anyone wants to run:
#include <GL/glut.h>
#include<iostream>
#include<math.h>
using namespace std;
void display(void);
void reshape(int, int);
void mouseHandler(int button, int state, int x, int y);
void keyBoardHandler(unsigned char c, int x, int y);
void specialKeyHandler(int key, int x, int y);
float angle = 0;
bool camDefault = true, perspectiveOrtho = true;
float iX =0 , iY = -0.8, iZ = 0, lX = 0, lY = -0.8, lZ = -1, uX = 0, uY = 1, uZ = 0;
float camAngle = 0;
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitWindowSize(512, 512);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("FPS Camera");
glutDisplayFunc(display);
glutIdleFunc(display);
//look from negative x axis towards origin. with y on top
glutReshapeFunc(reshape);
glEnable(GL_DEPTH_TEST);
glClearColor(0,0,0,1);
glutMouseFunc(mouseHandler);
glutKeyboardFunc(keyBoardHandler);
glutSpecialFunc(specialKeyHandler);
glutMainLoop();
return 0;
}
void drawEarth() {
glColor3f(0,255,0);
glBegin(GL_QUADS);
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(1,-1,1);
glVertex3f(1,-1,-1);
glEnd();
}
void drawWalls() {
glColor3f(0,0,255);
glBegin(GL_QUADS);
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(-1,1,1);
glVertex3f(-1,1,-1);
glEnd();
glColor3f(0,234,255);
glBegin(GL_QUADS);
glVertex3f(-1,-1,1);
glVertex3f(-1,1,1);
glVertex3f(1,1,1);
glVertex3f(1,-1,1);
glEnd();
}
float unitVector(float dir, float x, float y, float z) {
float sumSqr = pow(x,2) + pow(y,2) + pow(z,2);
return dir / (sqrt(sumSqr));
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEarth();
drawWalls();
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX+0.05,iY, iZ-0.05);
glRotatef(camAngle, 0,1,0);
glutWireCone(0.005,0.1,20,20);
glPopMatrix();
glutSwapBuffers();
}
void reshape(int width, int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90,1, 0.001, 1000);
gluLookAt(iX,iY,iZ,iX+lX,lY,iZ+lZ,uX,uY,uZ);
glMatrixMode(GL_MODELVIEW);
}
void updateLookAt() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (90, 1 ,0.001, 1000);
gluLookAt(iX,iY,iZ,iX+lX,lY,iZ+lZ,uX,uY,uZ);
glMatrixMode(GL_MODELVIEW);
}
void keyBoardHandler(unsigned char c, int x, int y) {
switch(c) {
case 'f': // go left
iX-=0.01;
lX -= 0.01;
cout<<endl<<"S pressed";
break;
case 's': // go right
iX += 0.01;
lX += 0.01;
break;
case 'e': // go up
iZ += 0.01;
lZ += 0.01;
break;
case 'd': // go down
iZ -= 0.01;
lZ -= 0.01;
break;
default:
break;
}
updateLookAt();
}
void mouseHandler(int button, int state, int x, int y) {
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
if(camDefault) {
glLoadIdentity();
gluLookAt(-1,0,0,0.0,0.0,0.0,0.0,1,0);
camDefault = false;
}
else {
glLoadIdentity();
gluLookAt(0,0,0,0.0,0.0,0.0,0.0,1,0);
camDefault = true;
}
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(perspectiveOrtho) {
gluPerspective (90, 1 ,0.00001, 1000);
perspectiveOrtho = false;
}
else {
glOrtho(-1,1,-1,1, -1,100);
perspectiveOrtho = true;
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(camDefault)
gluLookAt(0,0,1,0.0,0.0,0.0,0.0,1,0);
else
gluLookAt(-1,0,0,0.0,0.0,0.0,0.0,1,0);
}
}
void specialKeyHandler(int key, int x, int y) {
float fraction = 0.05f;
switch (key) {
case GLUT_KEY_LEFT :
camAngle -= 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_RIGHT :
camAngle += 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_UP :
iX += lX * fraction;
iZ += lZ * fraction;
break;
case GLUT_KEY_DOWN :
iX -= lX * fraction;
iZ -= lZ * fraction;
break;
default:
break;
}
updateLookAt();
}

You have two problems.
The first problem is on your coordinates system.
When you apply :
glTranslatef(iX+0.05,iY, iZ-0.05);
You place the object at the camera position, and add an offset to see him. But this is in the world coordinates system. So when you rotate the camera, the object doesn't move cause it doesn't follow the camera's coordinates system.
You need to translate to the camera center, rotate the camera, then add the offset.
The second problem is on the rotation. Your "camAngle" variable is in radian, cause you use it with cos() and sin(). But in OpenGL, glRotate take the angle as a degree value. You need to convert this angle in angle : angle *= 180/PI. (180/PI ~= 57.2957795)
Here the corrected display function :
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX,iY,iZ); // Translation to the camera center
glRotatef(-camAngle * 57.2957795, 0,1,0); // Rotate to correspond to the camera
glTranslatef(0.05,0,-0.05); // Offset to draw the object
glutWireCone(0.005,0.1,20,20);
glPopMatrix();
drawEarth();
drawWalls();
glutSwapBuffers();
}

Related

How to fix zoom in & out with mouse scroll wheel?

I'm trying to make a program where I'm able to zoom in & out on the figures I've drawn, but is not doing it; it's switching the orientation of the figures and if I keep scrolling, it just disappears. The function that are suppose to be executed for this to work are the MouseFunc() along with the renderScene(). Any explanation for the problem or help is welcomed.
#include"glut.h"
#include<cmath>
#include<iostream>
using namespace std;
float xr = 0, yr = 0; //to control the object's movement from left to right
// XZ position of the camera
float x = 0.0f, z = 5.0f; //Module 4
float angleX = 0.0f; //Module 4
//Shift + ArrowKey rotation
float transX = 0.0f;
float transY = 0.0f;
float rotY = 0.0f;
//end
//Mouse Commands
//float ZoomFactor = 0.5;
GLfloat theta3 = 0;
GLfloat phi = 0;
GLfloat rho = 5;
GLfloat camX = 0;
GLfloat camY = 0;
GLfloat camZ = 0;
GLfloat upX = 0;
GLfloat upY = 0;
GLfloat upZ = 0;
//end
GLfloat angle = 0.0f;
int refreshmill = 1;
void timer(int value) { //to control the rotation of the object
glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
//Circle One
float theta;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
glPushMatrix();
glBegin(GL_POLYGON);
for (int x = 0; x < 360; x++) {
theta = x * 3.142 / 180;
glVertex2f(150 * cos(theta) + xr, 150 * sin(theta) + yr);
}
glEnd();
glPopMatrix();
//Circle Two
float theta2;
glPushMatrix();
glTranslatef(0.5f, 0.0f, 0.0f); // rotation
glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
glBegin(GL_POLYGON);
glColor3f(0, 0, 1);
for (int x = 0; x < 360; x++) {
theta2 = x * 3.142 / 180;
glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
}
angle += 0.2; // rotation
glEnd();
glPopMatrix();
//Draw Star
glColor3ub(119, 193, 15);
glPushMatrix();
glBegin(GL_POLYGON);
glVertex2d(15 + xr, 60 + yr);
glVertex2d(75 + xr, 75 + yr); //right peak
glVertex2d(15 + xr, 90 + yr);
glVertex2d(0 + xr, 150 + yr); //Up-peak Changed
glVertex2d(-15 + xr, 90 + yr);
glVertex2d(-75 + xr, 75 + yr);
glVertex2d(-15 + xr, 60 + yr);
glVertex2d(0 + xr, 0 + yr);
glEnd();
glPopMatrix();
}
//Close code
void handleKeypress(unsigned char key, int x, int y){
switch (key){
case 27: //when the escape key is pressed the program will exit.
exit(0);
}
}
//Movement of drawing
void keyboard(int key, int x, int y) {
float fraction = 0.1f;
bool shift = false;
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_SHIFT) {
shift = true;
}
if (!shift) {
switch (key) {
case GLUT_KEY_RIGHT: xr++; break;
case GLUT_KEY_LEFT: xr--; break;
case GLUT_KEY_UP: angleX -= 1.0f; break; //Module 4
case GLUT_KEY_DOWN: angleX += 1.0f; break; //Module 4
}
}
else {
switch (key) {
case GLUT_KEY_LEFT:// Rotación del dibujo hacia la izquierda en el eje de Y
rotY -= 1.0f;
break;
case GLUT_KEY_RIGHT:// Rotación del dibujo hacia la derecha en el eje de Y
rotY += 1.0f;
break;
}
}
}
//Mouse Function
void MouseFunc(int button, int state, int x, int y){
if (button > 4){
rho = rho + 3.0;
}
else (button < 3);{
rho = rho - 3.0;
}
}
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
glRotatef(rotY, 0.0, 1.0, 0.0); //Rotation with Shift + ArrowKey
GLfloat camX = rho * cos(theta3*3.1415926f / 180)*sin(phi*3.1415926f / 180);
GLfloat camY = rho * sin(theta3*3.1415926f / 180);
GLfloat camZ = rho * cos(theta3*3.1415926f / 180)*cos(phi*3.1415926f / 180);
// Reduce theta slightly to obtain another point on the same longitude line on the sphere.
GLfloat dt = 1;
GLfloat eyeXtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*sin(phi*3.1415926f / 180);
GLfloat eyeYtemp = -rho * sin((theta3 - dt)*3.1415926f / 180);
GLfloat eyeZtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*cos(phi*3.1415926f / 180);
// Connect these two points to obtain the camera's up vector.
GLfloat upX = eyeXtemp - camX;
GLfloat upY = eyeYtemp - camY;
GLfloat upZ = eyeZtemp - camZ;
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set the camera
gluLookAt(camX, camY, camZ, 0, 0, 0, upX, upY, upZ);
gluLookAt(x, 0.0f, z, x, 0.0f, z - 1.0f, 0.0f, 1.0f, 0.0f); //Module 4
glRotatef(angleX, 1, 0, 0); //Module 4
myDisplay();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(0.0f, 0.1f, 0.1f, 0.0f);
glOrtho(-250, 250, -250, 250, -250, 250); //IMPORTANT- Define from negative to positive
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Homework: Circle");
// register callbacks
glutDisplayFunc(renderScene);
glutTimerFunc(0,timer,0);
glutKeyboardFunc(handleKeypress);
glutSpecialFunc(keyboard);
glutMouseFunc(MouseFunc);
// OpenGL init
init();
// enter GLUT event processing cycle
glutMainLoop();
}
Is wired to set a perspective and an orthographic projection. Delete the perspective projection gluPerspective:
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(0.0f, 0.1f, 0.1f, 0.0f); <---- delete
glOrtho(-250, 250, -250, 250, -250, 250);
glMatrixMode(GL_MODELVIEW);
}
If you want to zoom, the the orthographic projection has to be changed (glOrtho). The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport.
Implement a mouse wheel event, which changes the zoom, in a restricted range:
e.g.
GLdouble zoom = 0.0f;
void MouseFunc(int button, int state, int x, int y){
GLdouble min_z = -100.0;
GLdouble max_z = 100.0;
if (button == 4 && zoom < max_z) {
zoom += 3.0;
}
else if (button == 3 && zoom > min_z) {
zoom -= 3.0;
}
}
Modify the orthographic projection, dependent on the zoom in the display loop renderScene:
void renderScene(void) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLdouble ortho = 250 + zoom;
glOrtho(-ortho, ortho, -ortho, ortho, -250, 250);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// [...]
}

Draw trajectory of an object in OpenGL

I want to make the codes that draw trajectory as the object's moving when I clicked any position on the screen.
I set the initial center point as a starting point. And I want to set the other point with mouse button clicked (destination point) as variables but I can't figure out how to do this.
float v1[3] = { -35.0f, 22.5f, 0.0f };
float v2[3] = { -35.0f, -22.5f, 0.0f };
float v3[3] = { 0.0f, 42.5f, 0.0f };
float v4[3] = { 0.0f, -42.5f, 0.0f };
float v5[3] = { 35.0f, 22.5f, 0.0f };
float v6[3] = { 35.0f, -22.5f, 0.0f };
This is the initial position of the object. (6-point star with 2 triangles)
float px, py;
float center_s[3] = { 0.0f, 0.0f, 0.0f };
float center_d[3] = { px, py, 0.0f };
center_s is the starting point and center_d is the destination point with variable px, py.
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
}
This function draws trajectory with red lines from center_s to center_d. Also it draws a center point.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
}
glutPostRedisplay();
break;
Here is the problem. When the left mouse button is pressed, the star has to move to the clicked position and calculates the center point of the position and draw the line. But if I run these codes, the movement trajectory is not drawn.
Please let me know what the problem is. Plus, the star must move at a constant speed to the clicked location. (Not teleportation)
Following is the full codes:
#include <stdlib.h>
#include <GL/glut.h>
float v1[3] = { -35.0f, 22.5f, 0.0f };
float v2[3] = { -35.0f, -22.5f, 0.0f };
float v3[3] = { 0.0f, 42.5f, 0.0f };
float v4[3] = { 0.0f, -42.5f, 0.0f };
float v5[3] = { 35.0f, 22.5f, 0.0f };
float v6[3] = { 35.0f, -22.5f, 0.0f };
float px, py;
float center_s[3] = { 0.0f, 0.0f, 0.0f };
float center_d[3] = { px, py, 0.0f };
static GLfloat spin = 0.0;
float x = 400.0f, y = 442.5f;
float color1[3] = { 1.0f, 1.0f, 1.0f };
float color2[3] = { 1.0f, 1.0f, 1.0f };
int mode = 1;
int rotate = 1;
void init(void);
void triangle_1(void);
void triangle_2(void);
void lines(void);
void display(void);
void spinDisplay_1(void);
void spinDisplay_2(void);
void reshape(int, int);
void changeColor(int);
void mouse(int, int, int, int);
////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(300, 300);
glutCreateWindow("6-Point Star");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
////////////////////////////////////////////////////////////////////
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
}
void triangle_1(void) {
glColor3fv(color1);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v1);
glVertex3fv(v4);
glVertex3fv(v5);
glEnd();
}
void triangle_2(void) {
glColor3fv(color2);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v2);
glVertex3fv(v3);
glVertex3fv(v6);
glEnd();
}
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
glutSwapBuffers();
}
void spinDisplay_1(void) {
spin = spin + 2.0;
if (spin > 360.0) {
spin = spin - 360.0;
}
glutPostRedisplay();
}
void spinDisplay_2(void) {
spin = spin - 2.0;
if (spin < 360.0) {
spin = spin + 360.0;
}
glutPostRedisplay();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void changeColor(int n) {
if (n == 1) {
color1[0] = 0.0f, color1[1] = 0.0f, color1[2] = 1.0f;
color2[0] = 0.0f, color2[1] = 1.0f, color2[2] = 0.0f;
}
else if (n == 2) {
color1[0] = 1.0f, color1[1] = 1.0f, color1[2] = 1.0f;
color2[0] = 1.0f, color2[1] = 1.0f, color2[2] = 1.0f;
}
}
void mouse(int button, int state, int mx, int my) {
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
}
glutPostRedisplay();
break;
case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN) {
if (mode == 1) {
changeColor(mode);
mode = 2;
}
else if (mode == 2) {
changeColor(mode);
mode = 1;
}
}
glutPostRedisplay();
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
if (rotate == 1) {
glutIdleFunc(spinDisplay_1);
rotate = 2;
}
else if (rotate == 2) {
glutIdleFunc(spinDisplay_2);
rotate = 1;
}
break;
default:
break;
}
}
You're missing a few glEnd() and unless you have other plans for center_s and center_d then you don't need them. As x and y is center_s, while px and py is center_d.
So first of all in mouse() just assign the mouse position to px and py instead of x and y.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
px = mx;
py = glutGet(GLUT_WINDOW_HEIGHT) - my;
}
Now next you need a way to obtain the delta time. Delta time is the time passed since the last frame. For ease I added the following code to the top of display().
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
Remember to declare int timeLastFrame = 0; among your global variables.
Now (still in display()) we can calculate the direction of the travel path. We do this by calculating the difference between the two points. Then calculate the length and normalize the difference.
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
Now you just put it all together.
if (length > 1.0f) {
x += dx * speed * delta;
y += dy * speed * delta;
}
So while length > 1.0 then we move towards px and py at the speed of float speed = 100.0f; (declare this among your global variables as well).
Just to reemphasize. Yes, do delete glutIdleFunc(lines) from mouse(). Then we add it in display() instead. The full extend of display() should look like this now:
void display(void) {
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
if (length > 1.0f) {
x += dx * speed * delta;
y += dy * speed * delta;
}
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
lines();
glutSwapBuffers();
glutPostRedisplay();
}
Remember glutPostRedisplay(). If not then it won't redraw and thus not animate. Also remember to #include <math.h> for sqrt().
Everything before glClear() could be moved to your glutIdleFunc() callback.
Since there was no need for center_s and center_d then lines() can be boiled down to:
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex2f(px, py);
glEnd();
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f(x, y);
glVertex2f(px, py);
glEnd();
}
The result should look something like this:
For future reference. If you don't want to do the linear algebra by hand. Then you can use something like GLM.

OpenGL Keyboard Events not working

I have the following snippet:
float z, yrot = 0, xrot = 0;
float x = 0.0;
float y = 0.0;
void display() /* 2. */
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 3. */
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
glMatrixMode (GL_MODELVIEW);
glTranslatef(x, y, -0.5);
glRotatef(rotation, 0, 0, -1);
glColor3f(1.0,1.0,1.0);
glutWireTeapot(0.2);
glutSwapBuffers(); /* 4. */
}
void keyPressed(unsigned char key, int x, int y)
{
float yrotrad = (yrot / (180 * 3.141592654f));
float xrotrad = (xrot / (180 * 3.141592654f));
switch (key)
{
case 'w':
x += (float)(sin(yrotrad));
z -= (float)(cos(yrotrad)) ;
y -= (float)(sin(xrotrad));
glutPostRedisplay();
break;
}
}
int main(int argc, char **argv) /* 5. */
{
glutDisplayFunc(display);
glutKeyboardFunc(keyPressed);
glutMainLoop();
}
What is supposed to happen when I press the w key is that it's supposed to tilt the camera. But when I press w, nothing happens. What am I doing wrong?
Your x and y parameters are shadowing the globals:
void keyPressed(unsigned char key, int x, int y)
So the increment of those is not doing what you think it does. Turn up your compiler warnings -- you'll probably see some about losing precision.
Ironically, it works correctly for z but you don't seem to be using it anywhere in your rendering code.
(Aside: You may also want to look into GLFW. It's quite similar to GLUT and as easy to get started with, but better in every respect.)

Want to move one 2d object and not the other

I have to make a bowling game in openGL. This is the code I have so far. What it does that it draws a ball and is moved accordingly when an arrow key is pressed.
So far, I have that ball moving, that is fine. What I want to do that other point I have created, that should not be moved. Because, when that ball reaches to that point, it should be drop or something I will make that obstacle is dropped.
The code is written in Eclipse IDE.
#include <stdio.h>
#include <GL/glut.h>
#include <math.h>
#include <stdio.h> /* printf, scanf, puts, NULL */
float posX = 0, posY = -0.1, posZ = 0;
GLfloat rotation = 90.0;
double x, y, angle;
#define PI 3.1415926535898
GLint circle_points = 50;
void reshape(int width, int heigth) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//clip the windows so its shortest side is 2.0
if (width < heigth) {
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) heigth / (GLfloat) width,
2.0 * (GLfloat) heigth / (GLfloat) width, 2.0, 2.0);
} else {
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) width / (GLfloat) heigth,
2.0 * (GLfloat) width / (GLfloat) heigth, 2.0, 2.0);
}
// set viewport to use the entire new window
glViewport(0, 0, width, heigth);
}
void circ() {
glColor3f(0.0, 0.0, 1.0);
glPointSize(11.0);
glBegin(GL_POINTS);
glVertex3f(0.1, 0.1, 0.0);
glEnd();
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i <= 300; i++) {
angle = 2 * PI * i / 300;
x = cos(angle) / 20;
y = sin(angle) / 20;
glVertex2d(x, y);
}
glEnd();
}
void display() {
//Clear Window
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(posX, posY, posZ);
circ();
glPopMatrix();
glFlush();
}
void init() {
// set clear color to black
glClearColor(1.0, 1.0, 1.0, 0.0);
// set fill color to white
glColor3f(1.0, 1.0, 1.0);
//This is the default view and these statements could be removed
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
}
float move_unit = 0.02f;
void keyboardown(int key, int x, int y) {
switch (key) {
case GLUT_KEY_RIGHT:
posX += move_unit;
break;
case GLUT_KEY_LEFT:
posX -= move_unit;
break;
case GLUT_KEY_UP:
posY += move_unit;
break;
case GLUT_KEY_DOWN:
posY -= move_unit;
break;
default:
break;
}
glutPostRedisplay();
}
int main(int argc, char** argv) {
//initialize mode and open a windows in upper left corner of screen
//Windows tittle is name of program
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(600, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Practice 1");
glutDisplayFunc(display);
init();
glutSpecialFunc(keyboardown);
glutMainLoop();
}
Modern graphics APIs simulating finite state machine. That means that before Draw calls you must fully configure (or leave default) graphics pipeline "machine":
SetStates(); // Configure pipeline state: set geometry, textures, matrices, etc.
Begin();
Draw(); // Render frame according to current pipeline configuration (state)
End(); // Swap screen buffers
In case of many objects, you can just wrap all stuff with for loop:
for( each_object )
{
SetStates(); // current object's vertex/index buffer, texture, matrices, etc.
Begin();
Draw();
End();
}
Not very efficient. Next step of improvement might include: frustum culling, instancing, vertex buffers merging, texture atlases, draw calls sorting, etc.
BTW, consider using Vertex Buffer Objects (VBOs), instead of Begin/glVertex2d/End which is deprecated
Try this:
#include <GL/glut.h>
#include <cmath>
float posX = 0, posY = -0.1, posZ = 0;
GLfloat rotation = 90.0;
double x, y, angle;
#define PI 3.1415926535898
GLint circle_points = 50;
void point()
{
glColor3f(0.0, 0.0, 1.0);
glPointSize(11.0);
glBegin(GL_POINTS);
glVertex3f(0.1, 0.1, 0.0);
glEnd();
}
void circ()
{
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i <= 300; i++)
{
angle = 2 * PI * i / 300;
x = cos(angle) / 20;
y = sin(angle) / 20;
glVertex2d(x, y);
}
glEnd();
}
void display()
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
point();
glPopMatrix();
glPushMatrix();
glTranslatef(posX, posY, posZ);
circ();
glPopMatrix();
glutSwapBuffers();
}
float move_unit = 0.02f;
void keyboardown(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_RIGHT:
posX += move_unit;
break;
case GLUT_KEY_LEFT:
posX -= move_unit;
break;
case GLUT_KEY_UP:
posY += move_unit;
break;
case GLUT_KEY_DOWN:
posY -= move_unit;
break;
default:
break;
}
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(600, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Practice 1");
glutDisplayFunc(display);
glutSpecialFunc(keyboardown);
glutMainLoop();
}

OpenGL 3rd person camera

I've put together a 3rd person camera system using OpenGL and C++ from tutorials and such online, but I can't seem to figure out a specific problem. When I turn using mouse movement, my character is rotated around the camera rather than the camera around the character and the character turning on the spot. What should I do to have the character turn on the spot?
// variables ..
void checkMouse(){
if (mouseXPos > SCREEN_WIDTH/2){
// turn right
yrot += abs(mouseXPos - SCREEN_WIDTH/2) * .005;
} else if (mouseXPos < SCREEN_WIDTH/2){
// turn left
yrot -= abs(mouseXPos - SCREEN_WIDTH/2) * .005;
}
if (mouseYPos > SCREEN_HEIGHT/2){
// look up
xrot += abs(mouseYPos - SCREEN_HEIGHT/2) * .005;
} else if (mouseYPos < SCREEN_HEIGHT/2){
// look down
xrot -= abs(mouseYPos - SCREEN_HEIGHT/2) * .005;
}
}
void checkKeys(){
if(keys['t'] == true){
wireframe=!wireframe;
if(wireframe){
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if (keys['w'] == true){
float xrotrad, yrotrad;
yrotrad = (yrot / 180 * 3.141592654f);
xrotrad = (xrot / 180 * 3.141592654f);
xpos += float(sin(yrotrad)) * 10 ;
zpos -= float(cos(yrotrad)) * 10 ;
}
if (keys['s'] == true){
float xrotrad, yrotrad;
yrotrad = (yrot / 180 * 3.141592654f);
xrotrad = (xrot / 180 * 3.141592654f);
xpos -= float(sin(yrotrad)) * 10;
zpos += float(cos(yrotrad)) * 10;
}
if (keys['a'] == true){
float yrotrad;
yrotrad = (yrot / 180 * 3.141592654f);
xpos -= float(cos(yrotrad)) * 10;
zpos -= float(sin(yrotrad)) * 10;
}
if (keys['d'] == true){
float yrotrad;
yrotrad = (yrot / 180 * 3.141592654f);
xpos += float(cos(yrotrad)) * 10;
zpos += float(sin(yrotrad)) * 10;
}
}
void renderScene(){
// Clear framebuffer & depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset Modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set view position & direction
gluLookAt(0,0,5, 0,0,-1, 0,1,0);
checkKeys();
checkMouse();
// 3rd person object
// draw body
glPushMatrix();
glRotatef(xrot,1.0,0.0,0.0); // keeps object on ground level rather than always in front of camera
glTranslatef(0,-90,-400.0); // keep object 400 away from camera
glRotatef(-90,0.0,1.0,0.0);
glutSolidCube(20);
glPopMatrix();
// CAMERA
glRotatef(xrot,1.0,0.0,0.0); //rotate our camera on the x-axis (left and right)
glRotatef(yrot,0.0,1.0,0.0); //rotate our camera on the y-axis (up and down)
glTranslated(-xpos,-ypos-200,-zpos);
// rest of world
glPushMatrix();
glutSolidCube(30);
glPopMatrix();
// ..
glDisable(GL_TEXTURE_2D);
// Swap double buffer for flicker-free animation
glutSwapBuffers();
}
void updateScene(){
// Wait until at least 16ms passed since start of last frame
// Effectively caps framerate at ~60fps
while(timeGetTime()-lastTickCount<16);
lastTickCount=timeGetTime();
// Draw the next frame
glutPostRedisplay();
}
void keypress (unsigned char key, int x, int y) {
keys[key] = true;
// Test if user pressed ESCAPE (ascii 27)
// If so, exit the program
if(key==27){
exitScene();
}
}
void keypressup (unsigned char key, int x, int y) {
keys[key] = false;
wheel_turn = 0;
}
void mouseMovement(int x, int y) {
mouseXPos = x;
mouseYPos = y;
}
void mouseClick(int button, int state, int x, int y){
if (button == GLUT_LEFT_BUTTON){
if (state == GLUT_DOWN)
lButton = true;
else
lButton = false;
}
}
void setupScene(){
forwards = 0;
strafe = 0;
turn = 0;
std::cout<<"Initializing scene..."<<std::endl;
//Set up Lighting Stuff
glLightfv(GL_LIGHT0, GL_POSITION, left_light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, white_light);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
}
void exitScene(){
std::cout<<"Exiting scene..."<<std::endl;
// Close window
glutDestroyWindow(windowId);
// Free any allocated memory
// Exit program
exit(0);
}
void setViewport(int width, int height) {
// Work out window ratio, avoid divide-by-zero
if(height==0)height=1;
float ratio = float(width)/float(height);
// Reset projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Fill screen with viewport
glViewport(0, 0, width, height);
// Set a 45 degree perspective
gluPerspective(45, ratio, .1, 200000);
}
int main(int argc, char *argv[]){
// Initialise OpenGL
glutInit(&argc, argv);
// Set window position, size & create window
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(50,50);
glutInitWindowSize(SCREEN_WIDTH,SCREEN_HEIGHT);
windowId = glutCreateWindow("3rd person cam");
// Set GLUT callback functions
glutReshapeFunc(setViewport);
glutDisplayFunc(renderScene);
glutIdleFunc(updateScene);
glutKeyboardFunc(keypress);
glutKeyboardUpFunc(keypressup);
glutPassiveMotionFunc(mouseMovement); //check for mouse movement
glutMotionFunc(mouseMovement);
glutMouseFunc(mouseClick);
// Setup OpenGL state & scene resources (models, textures etc)
setupScene();
// Show window & start update loop
glutMainLoop();
return 0;
}
You're rotating the camera around itself — it's akin to you turning your head. You want to change the camera position, revolving around your object of interest.
1. Find your camera position
Look up 'spherical coordinates' for this
Your horizontal angle should vary between (0 and 2*PI) based on mouse x move
Your vertical angle should vary between (0 and PI) based on mouse y move
You can scale the found (x,y,z) position with a value to vary the distance between camera and object
Add the object position to this found position
You now have a valid camera position around your object
2. Find View matrix
There's a handy glut method called gluLookAt, just use that to find your final camera matrix. It needs (camera positoin, object position, and world up(0,1,0))