c++ OpenGL display problem for gluLookAt - c++

I have been trying to solve this program:
Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing. Also the cube should rotate.
I have completed the coding and here it is. It seems to work fine except for 1 simple problem:
//Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing
#include <stdio.h>
#include <glut.h>
float v[][3] = {{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1},{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}};
void drawPolygon(float a[3],float b[3],float c[3],float d[3])
{
glBegin(GL_POLYGON);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glVertex3fv(d);
glEnd();
glFlush();
}
void drawCube(float v[8][3])
{
glColor3f(1,0,0);
drawPolygon(v[0],v[1],v[2],v[3]);
glColor3f(0,1,0);
drawPolygon(v[0],v[1],v[6],v[7]);
glColor3f(0,0,1);
drawPolygon(v[7],v[6],v[5],v[4]);
glColor3f(1,1,0);
drawPolygon(v[2],v[3],v[4],v[5]);
glColor3f(0,1,1);
drawPolygon(v[1],v[2],v[5],v[6]);
glColor3f(1,0,1);
drawPolygon(v[0],v[3],v[4],v[7]);
glFlush();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1,0,0);
//glRotatef(60,1,1,0);
drawCube(v);
glFlush();
}
void reshape(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2,2,-2,2,-2,2);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
void mouse(int btn,int state,int x,int y)
{
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
glRotatef(2,1,0,0);
if(btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
glRotatef(2,0,1,0);
if(btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
glRotatef(2,0,0,1);
glutPostRedisplay();
}
float ex=0,ey=0,ez=-10,cx=0,cy=0,cz=0,ux=0,uy=1,uz=0;
void keyboard(unsigned char key,int x,int y)
{
if(key == 'x')
ex += 0.1;
if(key == 'X')
ex -= 0.1;
if(key == 'y')
ey += 0.1;
if(key == 'Y')
ey -= 0.1;
if(key == 'z')
ez += 0.1;
if(key == 'Z')
ez -= 0.1;
glMatrixMode(GL_PROJECTION);
gluLookAt(ex,ey,ez,cx,cy,cz,ux,uy,uz);
glutPostRedisplay();
}
void main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("spin cube");
glClearColor(1,1,1,0);
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}
The cube rotates by mouse clicks
The camera moves by x/X y/Y z/Z
But the problem is that when i first press a key the display vanishes. Then the 2nd time it comes with properly moved camera. Why? I want the camera to just move and not vanish the display. What is wrong?

There are two mistakes in your program:
You're treating OpenGL like a scene graph with persistency – however OpenGL just draws pictures.
You apply viewpoint transformation to the projection matrix.
Both is fundamentally wrong. Here's a corrected version of your code:
//Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing
#include <stdio.h>
#include <glut.h>
float v[][3] = {{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1},{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}};
void drawPolygon(float a[3],float b[3],float c[3],float d[3])
{
glBegin(GL_POLYGON);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glVertex3fv(d);
glEnd();
}
void drawCube(float v[8][3])
{
glColor3f(1,0,0);
drawPolygon(v[0],v[1],v[2],v[3]);
glColor3f(0,1,0);
drawPolygon(v[0],v[1],v[6],v[7]);
glColor3f(0,0,1);
drawPolygon(v[7],v[6],v[5],v[4]);
glColor3f(1,1,0);
drawPolygon(v[2],v[3],v[4],v[5]);
glColor3f(0,1,1);
drawPolygon(v[1],v[2],v[5],v[6]);
glColor3f(1,0,1);
drawPolygon(v[0],v[3],v[4],v[7]);
}
float ex=0,ey=0,ez=-10,cx=0,cy=0,cz=0,ux=0,uy=1,uz=0;
void display()
{
int win_width, win_height;
win_width = glutGet(GLUT_WINDOW_WIDTH);
win_height = glutGet(GLUT_WINDOW_HEIGHT);
glViewport(0,0,width,height);
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2,2,-2,2,-2,2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(ex,ey,ez,cx,cy,cz,ux,uy,uz);
glRotatef(rot_x,1,0,0);
glRotatef(rot_y,0,1,0);
glRotatef(rot_z,0,0,1);
glColor3f(1,0,0);
//glRotatef(60,1,1,0);
drawCube(v);
glFinish();
}
void mouse(int btn,int state,int x,int y)
{
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
rot_x += 2;
if(btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
rot_y += 2;
if(btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
rot_z += 2;
glutPostRedisplay();
}
void keyboard(unsigned char key,int x,int y)
{
if(key == 'x')
ex += 0.1;
if(key == 'X')
ex -= 0.1;
if(key == 'y')
ey += 0.1;
if(key == 'Y')
ey -= 0.1;
if(key == 'z')
ez += 0.1;
if(key == 'Z')
ez -= 0.1;
glutPostRedisplay();
}
void main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("spin cube");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}

gluLookAt shouldn't go in to the projection matrix but into the modelview. I would also suggest that you keep track of your cube rotation and eye position and apply them inside the display function instead:
//Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing
#include <stdio.h>
#include <glut.h>
float ex=0,ey=0,ez=-10,cx=0,cy=0,cz=0,ux=0,uy=1,uz=0;
float cubex=0,cubey=0,cubez=0;
float v[][3] = {{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1},{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}};
void drawPolygon(float a[3],float b[3],float c[3],float d[3])
{
glBegin(GL_POLYGON);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glVertex3fv(d);
glEnd();
}
void drawCube(float v[8][3])
{
glColor3f(1,0,0);
drawPolygon(v[0],v[1],v[2],v[3]);
glColor3f(0,1,0);
drawPolygon(v[0],v[1],v[6],v[7]);
glColor3f(0,0,1);
drawPolygon(v[7],v[6],v[5],v[4]);
glColor3f(1,1,0);
drawPolygon(v[2],v[3],v[4],v[5]);
glColor3f(0,1,1);
drawPolygon(v[1],v[2],v[5],v[6]);
glColor3f(1,0,1);
drawPolygon(v[0],v[3],v[4],v[7]);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(ex,ey,ez,cx,cy,cz,ux,uy,uz);
glRotatef(cubex, 1, 0, 0);
glRotatef(cubey, 0, 1, 0);
glRotatef(cubez, 0, 0, 1);
glColor3f(1,0,0);
//glRotatef(60,1,1,0);
drawCube(v);
glFinish();
}
void reshape(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2,2,-2,2,-2,2);
glutPostRedisplay();
}
void mouse(int btn,int state,int x,int y)
{
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
cubex += 2;
if(btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
cubey += 2;
if(btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
cubez += 2;
glutPostRedisplay();
}
void keyboard(unsigned char key,int x,int y)
{
if(key == 'x')
ex += 0.1;
if(key == 'X')
ex -= 0.1;
if(key == 'y')
ey += 0.1;
if(key == 'Y')
ey -= 0.1;
if(key == 'z')
ez += 0.1;
if(key == 'Z')
ez -= 0.1;
glutPostRedisplay();
}
void main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("spin cube");
glClearColor(1,1,1,0);
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}
This isn't 100% equivalent to what you were originally trying to achieve since it applies three accumulated consecutive rotations around the x, y and z axis respectively instead of incremental ones.
Also you don't need all the glFlush calls, a single call to glFinish at the end of the rendering should be sufficient, or even better; swap to double buffered rendering and use glutSwapBuffers instead.

Related

Position the square on the left after it reaches the top

#include <stdio.h> // this library is for standard input and output
#include "glut.h"// this library is for glut the OpenGL Utility Toolkit
#include <math.h>
float squareX = 0.0f;
float squareY = -0.3f;
float squareZ = 0.0f;
static int flag = 1;
void drawShape(void) {
glTranslatef(squareX, squareY, squareZ);
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(162, 50);
glVertex2f(162, 10);
glVertex2f(220, 10);
glVertex2f(220, 50);
glVertex2f(162, 50);
glEnd();
}
void initRendering() {
glEnable(GL_DEPTH_TEST);
}
// called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, (float)w, 0.0f, (float)h, -1.0f, 1.0f);
}
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawShape();
glutSwapBuffers();
}
// make the square go up
void update(int value) {
if (flag) {
squareY += 1.0f;
if (squareY > 400.0) {
flag = 0;
}
}
glutPostRedisplay();
glutTimerFunc(25, update, 0);
}
// make the square go right
/* void update(int value) {
if (flag) {
squareX += 1.0f;
if (squareX > 400.0) {
flag = 0;
}
}
glutPostRedisplay();
glutTimerFunc(25, update, 0);
} */
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(400, 400);
glutCreateWindow("Moving Square");
initRendering();
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutTimerFunc(25, update, 0);
glutMainLoop();
return(0);
}
I have uploaded this code before but this time I made the square go all the way up. The code just moves the square up, but I don't know how to position it on the left once it reaches the top, so then I can make it move to the right. I have uploaded a demonstration on how I want it to look below.
Preview:
What I want it to do next:
I recommend to initialize the variables squareX, squareY and squareZ with the start position of the rectangle:
float squareX = 162.0f;
float squareY = 0.0f;
float squareZ = 0.0f;
Do not draw a rectangle specific position, but draw a rectangle on the position (0,0) with a length (width, height). Let the model matrix (set by glTranslatef), do the job of the positioning:
void drawShape(void)
{
float width = 58.0f;
float height = 40.0f;
glTranslatef(squareX, squareY, squareZ);
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(0, 0);
glVertex2f(width, 0);
glVertex2f(width, height);
glVertex2f(0, height);
glVertex2f(0, 0);
glEnd();
}
Use a variable state, which has stated the direction of the current movement:
int state = 1; // 0: stop; 1: move up; 2: move right
If the rectangle a certain position has reached, then the state has to be changed and a the new start position can be set. At the final position, the rectangle can stop or the process can even be restarted:
void update(int value)
{
if (state == 1) // 1 : move up
{
squareY += 1.0f;
if (squareY > 400.0)
{
state = 2;
squareX = 0.0f;
squareY = 180.0f;
}
}
else if (state == 2) // 2 : move right
{
squareX += 1.0f;
if (squareX > 400.0)
{
state = 0;
// restart
//state = 1;
//squareX = 162.0f;
//squareY = 0.0f;
}
}
glutPostRedisplay();
glutTimerFunc(25, update, 0);
}

OpenGL - How to draw multiple different 2D shapes using pop-up menu?

I'm trying to make a simple openGL application which creates shapes using mouse clicks. The shape required is selected using a pop-up menu opened using the right mouse button. Currently I have rectangle working and also a simple paint-esque function using points. They disappear once redrawn but that's a problem I'll worry about in the future.
Currently I'm trying to also implement a Line function as a menu option. I have the below code in place but when I select the Line option from the pop-up menu and click two points it doesn't seem to draw a line as expected. Can anyone point out where I'm going wrong here?
GLfloat x1, x2, y1, y2;
GLfloat x_Src, y_Src, x_Dest, y_Dest;
//used to change colour (To be implemented)
static int colour;
void menu(int);
void display(void)
{
glClearColor(0.0, 2.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(3.0);
glColor3f(1.0, 0.0, 0.0);
//Rectangle vertices
glBegin(GL_POLYGON);
glVertex2f(x1, y1);
glVertex2f(x1, y2);
glVertex2f(x2, y2);
glVertex2f(x2, y1);
glEnd();
//Line vertices
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINE);
glVertex2f(x_Src, y_Src);
glVertex2f(x_Dest, y_Dest);
glEnd();
glFlush();
return;
}
void MyRect(GLint button, GLint state, GLint x, GLint y)
{
static int first = 1;
if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)
{
if (first)
{
//first point in terms of window size
x1 = (x - 250.0) / 250.0;
y1 = -(y - 250) / 250.0;;
}
else
{
//second point in terms of window size
x2 = (x - 250.0) / 250.0;
y2 = -(y - 250) / 250.0;
glutPostRedisplay();
}
first = !first;
}
return;
}
void MyLine(GLint button, GLint state, GLint x, GLint y)
{
static int first = 1;
if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)
{
if (first)
{
x_Src = (x - 250.0) / 250.0;
y_Src = -(y - 250) / 250.0;
}
else
{
x_Dest = (x - 250.0) / 250.0;
y_Dest = -(y - 250) / 250.0;
glutPostRedisplay();
}
first = !first;
}
return;
}
//allows drawing of un-fixed line using mouse
void MyPaint(GLint x, GLint y)
{
glColor3f(0.0, 0.0, 0.0);
glPointSize(3.0);
glBegin(GL_POINTS);
glVertex2f((x - 250.0) / 250.0, -(y - 250.0) / 250.0);
glEnd();
glFlush();
return;
}
void MainMenu(int item)
{
//Remove motion function if exists and go to rectangle function
//prevents two functions running at once
if (item == 1)
{
glutMotionFunc(NULL);
glutMouseFunc(MyRect);
}
else if (item == 2)
{
glutMotionFunc(NULL);
glutMouseFunc(MyLine);
}
else if (item == 5)
{
glutMouseFunc(NULL);
glutMotionFunc(MyPaint);
}
glutPostRedisplay();
return;
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(500, 500);
glutInitWindowPosition(500, 200);
glutCreateWindow("Draw Shapes");
glutDisplayFunc(display);
glutCreateMenu(MainMenu);
glutAddMenuEntry("Rectangle", 1);
glutAddMenuEntry("Line", 2);
glutAddMenuEntry("Circle", 3);
glutAddMenuEntry("Triangle", 4);
glutAddMenuEntry("Paintbrush", 5);
glutAddMenuEntry("Background colour", 6);
glutAddMenuEntry("Clear screen", 7);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
}
You need to use glBegin(GL_LINES) instead of glBegin(GL_LINE).
GL_LINE is an argument to the unrelated function glPolygonMode.

Attempt at Box Translation Results in Hung Output?

I have been trying to animate a simple box that moves from left to right in the viewport while changing its color at random. It is meant to restart animating on a left mouse click, and close on a right mouse click. I have been debugging my code below, and though I think my methodology is reasonable, whenever I run the code, color change does not happen, and the animation hangs immediately. Principally I am wondering if this has to do with my use of Sleep() (which documentation leads me to believe should accept milliseconds as arguments), or if my loop structure in general is the problem. When I debug, though, it seems to exit the loop without throwing an exception.
Code below - any help in resolving the hanging issue?
#define GLUT_DISABLE_ATEXIT_HACK
#include <GL/glut.h>
#include <GL/gl.h>
#include <unistd.h>
//#include <assert.h>
float boxX = 0;
float boxY = 100;
float boxWidth = 75;
float boxHeight = 75;
void display(void)
{
int const windowWidth = glutGet(GLUT_WINDOW_WIDTH);
int const windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
float const aspectRatio = (float)windowWidth / (float)windowHeight;
glClearColor (0.0, 0.0, 0.0, 0.0); /* Set background to black */
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(aspectRatio, aspectRatio, aspectRatio, aspectRatio, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
while (boxX != windowWidth)
{
glClear (GL_COLOR_BUFFER_BIT);
float leftCorner = (float)boxX / windowWidth;
float rightCorner = leftCorner + (float)boxWidth / windowWidth;
float bottomCorner = (float)boxY / windowHeight;
float topCorner = bottomCorner + (float)boxY / windowHeight;
glBegin(GL_POLYGON);
glColor3f (rand(), rand(), rand()); //Randomize the box's colour as it moves
glVertex2d(leftCorner, topCorner);
glVertex2d(rightCorner, topCorner);
glVertex2d(rightCorner, bottomCorner);
glVertex2d(leftCorner, bottomCorner);
glEnd();
boxX += 0.1; //Move the box
glutSwapBuffers();
Sleep(200000);
glutPostRedisplay();
}
}
void mouseBehav( int button, int state, int x, int y )
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
int windowID = glutCreateWindow ("Rainbow Box Animation");
glutDestroyWindow (windowID);
exit (0);
glutPostRedisplay();
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
boxX = 0;
glutPostRedisplay();
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition ((glutGet(GLUT_SCREEN_WIDTH)-250)/2, (glutGet(GLUT_SCREEN_HEIGHT)-250)/2);
glutCreateWindow ("Rainbow Box Animation");
glutMouseFunc(mouseBehav);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
using sleep() in a glutDisplayFunc() callback
No. Just...no.
Set up a timer callback for ~16-33ms and update boxX in that:
#include <GL/glut.h>
float boxX = 0;
float boxY = 0;
float boxWidth = 75;
float boxHeight = 75;
bool animate = false;
void timer( int value )
{
const int w = glutGet(GLUT_WINDOW_WIDTH);
if( boxX + boxWidth >= w / 2 )
{
animate = false;
}
if( animate )
{
boxX += 1; //Move the box
}
glutTimerFunc( 16, timer, 0 );
glutPostRedisplay();
}
void display()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
const int w = glutGet(GLUT_WINDOW_WIDTH);
const int h = glutGet(GLUT_WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( -w/2, w/2, -h/2, h/2, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
const float leftCorner = boxX;
const float rightCorner = leftCorner + boxWidth;
const float bottomCorner = boxY;
const float topCorner = bottomCorner + boxHeight;
glBegin(GL_POLYGON);
glColor3ub(rand()%255, rand()%255, rand()%255); //Randomize the box's colour as it moves
glVertex2d(leftCorner, topCorner);
glVertex2d(rightCorner, topCorner);
glVertex2d(rightCorner, bottomCorner);
glVertex2d(leftCorner, bottomCorner);
glEnd();
glutSwapBuffers();
}
void mouse( int button, int state, int x, int y )
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
exit(0);
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
boxX = 0;
animate = true;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition( (glutGet(GLUT_SCREEN_WIDTH)-250)/2, (glutGet(GLUT_SCREEN_HEIGHT)-250)/ 2);
glutCreateWindow ("Rainbow Box Animation");
glutMouseFunc(mouse);
glutDisplayFunc(display);
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 0;
}

OpenGL - FPS style Camera move with object fixed on camera

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();
}

Inaccurate Mouse Coordinates Returned

The issue is that the further the mouse click is from the top left origin (0,0) the greater the height inaccuracy when the vertex is plotted. Any ideas?
int WindowWidth = 19;
int WindowHeight = 13;
int mouseClickCount = 0;
int rectPlotted;
GLint x1;
GLint y1;
GLint x2;
GLint y2;
//Declare our functions with prototypes:
void display(void);
void init (void);
void processNormalKeys(unsigned char key, int x, int y);
void on_vertex_selected(GLint x, GLint y);
void on_mouse_event(int button, int state, int x, int y);
/////////////////////////////////// MAIN ////////////////////////////////
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
//start calculation of max window size available at 19:13 aspect ratio
int screenWidth = glutGet(GLUT_SCREEN_WIDTH);
int screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
screenWidth = screenWidth/WindowWidth;
WindowWidth = WindowWidth*screenWidth;
screenHeight = screenHeight/WindowHeight;
WindowHeight = screenHeight*WindowHeight;
//end calculation
glutInitWindowSize (WindowWidth, WindowHeight);
glutInitWindowPosition (0, 0);
glutCreateWindow ("Plot a rectangle!");
glutDisplayFunc(display);
glutKeyboardFunc(processNormalKeys);
glutMouseFunc(on_mouse_event);
init();
glutMainLoop();
return 0;
}
/////////////////////////////////////////////////////////////////////////
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT); //clear all pixels
glFlush();
}
void init (void)
{
/* select clearing (background) color */
glClearColor (1.0, 1.0, 1.0, 0.0);
/* initialize viewing values */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WindowWidth, 0, WindowHeight, -1.0, 1.0);
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27) //esc
exit(0);
//Allows color change of most recently plotted rectangle
if (key == 98){ //b
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x1, y1);
glVertex2i(x1, y2);
glVertex2i(x2, y2);
glVertex2i(x2, y1);
glEnd();
glFlush();
}
if (key == 114){ //r
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x1, y1);
glVertex2i(x1, y2);
glVertex2i(x2, y2);
glVertex2i(x2, y1);
glEnd();
glFlush();
}
if (key == 103){ //g
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x1, y1);
glVertex2i(x1, y2);
glVertex2i(x2, y2);
glVertex2i(x2, y1);
glEnd();
glFlush();
}
}
void on_vertex_selected(GLint x, GLint y){
if(mouseClickCount == 0){
x1 = x;
y1 = y;
glColor3f(0.0, 0.0, 0.0);
glEnable(GL_POINT_SMOOTH);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(x1, y1);
glEnd();
glFlush();
}
else{
x2 = x;
y2 = y;
glBegin(GL_POINTS);
glColor3f(1.0, 1.0, 1.0);
glVertex2i(x1,y1); //"clears" previous point to make way for the rectangle
glEnd();
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x1, y1);
glVertex2i(x1, y2);
glVertex2i(x2, y2);
glVertex2i(x2, y1);
glEnd();
glFlush();
}
}
void on_mouse_event(int button, int state, int x, int y){
if(button==GLUT_LEFT_BUTTON && state ==GLUT_DOWN && mouseClickCount == 0){
//y = y+20; //adjusts for VM mouse tracking error
on_vertex_selected(x, WindowHeight - y);
rectPlotted = 0;
}
if(button==GLUT_LEFT_BUTTON && state ==GLUT_UP && mouseClickCount == 0){
if(rectPlotted == 1){
return;
}
else{
mouseClickCount++;
}
}
if(button==GLUT_LEFT_BUTTON && state ==GLUT_DOWN && mouseClickCount == 1){
//y = y+20; //adjusts for VM mouse tracking error
on_vertex_selected(x, WindowHeight - y);
mouseClickCount = 0;
rectPlotted = 1;
}
}
Your glOrtho() call is almost certainly wrong. You pass the window size, not the window client area size. The difference is the size of the borders and the height of the caption.
Be aware that your actual window size will most probably be slightly different than what you asked at init time.
Simply said, implement a glutReshapeFunc()
I was compiling and running my code within Parallels VM v.6. This was the issue leading to inaccurate mouse coordinates being returned. I compiled and ran the exact same code on OS X without problem.