OpenGL/Glut: Making the camera rotate around X axis with arrow keys? - c++

I'm trying to make the gluLookAt() function so that when I press the up & down key the camera moves around the X axis
I'm trying a method I saw at: http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard-example-moving-around-the-world/
but it's not working for me. Anyone knows an easier way? and where should I put the gluLookAt() so on myDisplay() func?
#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
// actual vector representing the camera's direction
float lx = 0.0f, lz = -1.0f;
// XZ position of the camera
float x = 0.0f, z = 5.0f;
GLfloat angle = 0.0f;
int refreshmill = 1;
void timer(int value) { //to control the rotation of the object
glutPostRedisplay();
glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
//Circle One
float theta;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
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;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
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);
}
glutSwapBuffers();
angle += 0.2; // rotation
glEnd();
glPopMatrix();
//Draw Star
glColor3ub(119, 193, 15);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
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();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt(x, 1.0f, z,
x + lx, 1.0f, z + lz,
0.0f, 1.0f, 0.0f);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
myDisplay();
glutSwapBuffers();
}
//Move to left or right
void keyboard(int key, int x, int y) {
float fraction = 0.1f;
switch (key) {
case GLUT_KEY_RIGHT:
xr++;
cout << x << endl;
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
xr--;
cout << x << endl;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
angle -= 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_DOWN:
angle += 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
}
}
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-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(myDisplay);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutTimerFunc(0,timer,0);
glutSpecialFunc(keyboard);
// OpenGL init
init();
// enter GLUT event processing cycle
glutMainLoop();
}

First of all there should be only 1 display call back function:
int main(int argc, char** argv) {
// [...]
// glutDisplayFunc(myDisplay); <----- DELETE!!!
glutDisplayFunc(renderScene);
// glutIdleFunc(renderScene); <----- DELETE!!!
// [...]
}
Setup an an orthographic projection with an extended near and far plane. If the object is rotated around the X axis, it takes space in the 3 dimensions:
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-250, 250, -250, 250, -250, 250); // <----
glMatrixMode(GL_MODELVIEW);
}
Add a variable anglaX which is changed in the keyboard event:
float angleX = 0.0f;
void keyboard(int key, int x, int y) {
switch (key) {
case GLUT_KEY_RIGHT: xr++; break;
case GLUT_KEY_LEFT: xr--; break;
case GLUT_KEY_UP: angleX -= 1.0f; break;
case GLUT_KEY_DOWN: angleX += 1.0f; break;
}
}
Rotate the model, after the view was set:
gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1, 0, 0);
Don't do any calls to glutSwapBuffers(), glFlush() and glutPostRedisplay(), except at the end of renderScene:
void timer(int value) { //to control the rotation of the object
// glutPostRedisplay(); <--- DELETE
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();
}
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set the camera
gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1, 0, 0);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
myDisplay();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
Further I recommend to use double buffering:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

You can init your camera with gluLookAt at init(), then rotate it when arrow keys pressed. If you want to rotate camera around it's local x axis, assume your initial modelview matrix is V, newly happened rotation around x axis is R, you need to set modelview matrix to R*V, not V*R.
case GLUT_KEY_UP:
GLfloat temp[16];
glGetFloatv(GL_MODELVIEW_MATRIX, temp);
glLoadIdentity();
glRotate(stepAngle, 1, 0, 0); // calculate stepAngle by your self
glMultMatrixf(temp);
break;
You don need to reset modelview matrix during rendering, view part is already done, make sure you restore it after rendering the whole scene:
glPushMatrix(GL_MODELVIEW_MATRIX)
// don't call glLoadIdentity() here, you don't need to reset view part.
...
...
glPopMatrix()

Related

Distorted output when I apply projection OpenGL

I'm trying to implement camera functionality on a simple scene but the output is distored. I think it has something to do with perspective projection or maybe I'm using the gluLookAt() function wrong but I can't seem to pinpoint the problem. Whenever I press the arrow keys to more the camera the view keeps getting distorted. The camera code works fine in another example. I've used the exact same code with the display replaced for my scene. I have tried different arguments for gluLookAt() and even tried ortho projection but nothing seems to work.
Before camera implementation:
After camera implementation:
Code:
#include <Windows.h>
#include <math.h>
#include "glut.h"
float angle = 0.0f;
float lx = 0.0f, lz = -0.1f;
float x = 0.0f, z = 0.5f;
float deltaAngle = 0.0f;
float deltaMove = 0;
double rot = 0;
double doorAngle = 0;
double carMove = -0.75; //Initially car positioned at the start of road
void myInit(void)
{
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1000, 480);
glutInitWindowPosition(100, 150);
glutCreateWindow(" project part1 ");
glClearColor(0.333, 0.725, 0.905, 0);
glColor3f(0.0f, 0.0f, 0.0f);
}
void reshape(int w, int h) {
if (h == 0)
h = 1;
float ratio = w* 1.0 / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45.0f, ratio, 0.1f, 20.0f);
glMatrixMode(GL_MODELVIEW);
}
void computePos(float deltaMove) //compute camera position
{
x += deltaMove * lx * 0.1f;
z += deltaMove * lz * 0.1f;
}
void computeDir(float deltaAngle)//compute camra direction
{
angle += deltaAngle;
lx = sin(angle);
lz = -cos(angle);
}
void display(void)
{
if (deltaMove)
computePos(deltaMove);
if (deltaAngle)
computeDir(deltaAngle);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(x, 0.0f, z, x + lx, 0.0f, z + lz, 0.0f, 1.0f, 0.0f);
//display quads road
glPushMatrix();
glLineWidth(3.0);
glColor3f(0.474, 0.552, 0.603);
glBegin(GL_QUADS);//grey road
glTexCoord2f(0.0, 0.0);
glVertex3f(-1, 0, 0);
glTexCoord2f(0.0, 1.0);
glVertex3f(1, 0, 0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1, -1, 0);
glTexCoord2f(1.0, 0.0);
glVertex3f(-1, -1, 0);
glEnd();
//green grass above
glColor3f(0.305, 0.513, 0.341);
glBegin(GL_QUADS);
glVertex3f(-1, 0, 0);
glVertex3f(1, 0, 0);
glVertex3f(1, -0.1, 0);
glVertex3f(-1, -0.1, 0);
glEnd();
//green grass below
glColor3f(0.372, 0.407, 0.070);
glBegin(GL_QUADS);
glVertex3f(-1, -1, 0);
glVertex3f(1, -1, 0);
glVertex3f(1, -0.8, 0);
glVertex3f(-1, -0.8, 0);
glEnd();
//white lines on road
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
int factor = 10; GLushort pattern = 0x3333;
glEnable(GL_LINE_STIPPLE);
glLineStipple(factor, pattern);
glBegin(GL_LINES);
glVertex3f(1, -0.45, 0);
glVertex3f(-1, -0.45, 0);
glEnd();
glDisable(GL_LINE_STIPPLE);
glColor3f(0.929, 0.850, 0.850);
glPointSize(5.0);
glBegin(GL_LINES);
glVertex3f(1, -0.75, 0);
glVertex3f(-1, -0.75, 0);
glVertex3f(1, -0.15, 0);
glVertex3f(-1, -0.15, 0);
glEnd();
glPushMatrix();
glTranslatef(-0.8, 0.4, 0);
glScalef(0.5, 0.45, 0);
building(0, 0.17, 0.394);
glPopMatrix();
glPushMatrix();
glTranslatef(-0.35, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.552, 0.266, 0.505);
glPopMatrix();
glPushMatrix();
//glLoadIdentity();
glTranslatef(0.2, 0.45, 0);
glScalef(1.2, 0.5, 0);
building(0.294, 0.337, 0.584);
glPopMatrix();
glPushMatrix();
glTranslatef(0.75, 0.27, 0);
glScalef(0.55, 0.3, 0);
building(0.309, 0.396, 0.427);
glPopMatrix();
//building bases
//car1
glPushMatrix();
glTranslatef(carMove, -0.2, 0);
glScalef(0.5, 0.5, 0.5);
car(0.65, 0, 0);
glPopMatrix();
glutSwapBuffers();
}
void pressKey(int key, int xx, int yy) {
switch (key) {
case GLUT_KEY_LEFT:
if (deltaAngle > 30)
break;
deltaAngle = -0.01f;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT: deltaAngle = 0.01f; break;
case GLUT_KEY_UP: deltaMove = 0.05f; break;
case GLUT_KEY_DOWN: deltaMove = -0.05f; break;
}
}
void releaseKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT:
case GLUT_KEY_RIGHT: deltaAngle = 0.0f; break;
case GLUT_KEY_UP:
case GLUT_KEY_DOWN: deltaMove = 0; break;
}
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
myInit();
glutDisplayFunc(display);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(display);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(releaseKey);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
Note:
The texture mapping car and building code have been excluded for being too large but they work fine and I don't think that they're the problem. If you require the full working code then kindly let me know and I'll upload it. I've been stuck at this problem a while. Any help is appreciated
The issue is a Z-fighting issue.
To solve you issue you have to disable the Depth Test and draw the objects form the back to the front:
glEnable(GL_DEPTH_TEST)
Or you have to draw the object with a different z coordinates, which define the z order of the object.
Note, in view space the z axis points out of the viewport. So if the z coordinate of an object is greater than that of an other object, then the object is in front of the other object.
A perspective effect can only be achieved if the depth of the objects is different, so that object in the behind appear smaller, than that object which are closer to the point of view (eye position).
But you have to ensure that the objects are not clipped.
This mean the (view space) z distance of the object to the eye position (first 3 parameters of gluLookAt) has to be in between the near and far plane (last 2 parameters of gluPerspective).

Why Rotation along from center origin

I'm facing a rotation problem a triangle that draw with opengl drawing primitive. I am using glut key function to rotate the triangle anticlockwise and clockwise by pressing E and R keys. And then also using glut special key function to translate the triangle x axis and y axis by pressing up down left right keys like this
But after translate this triangle to another position than press rotation key it's not rotate form it's last position where it stay. It's rotate from center origin how to fix this.
I don't know what i'm doing wrong.
Code:
#include<iostream>
#include <cstdlib>
#include<GL\freeglut.h>
using namespace std;
float posX = 0.0f;
float posY = 0.0f;
float movethis = 0.1f;
float angle = 0.0f;
void init(void) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, -1.0);
}
void drawFigure() {
glPointSize(4);
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_LINES);
//Total 4 liens 9 vertex
glVertex2f(0.1f, 0.0f);
glVertex2f(-0.1f, 0.0f);
glVertex2f(0.0f, 0.1f);
glVertex2f(-0.1f, 0.0f);
glVertex2f(0.0f, 0.1f);
glVertex2f(0.1f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.0f, 0.1f);
glVertex2f(0.0f, 0.0f);
glEnd();
glBegin(GL_POINTS);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.1f);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glEnd();
}
void SpecialKeys(int key, int xpos, int ypos) {
if (key == GLUT_KEY_UP) {
posY = posY + movethis;
}
else if (key == GLUT_KEY_DOWN) {
posY = posY - movethis;
}
else if (key == GLUT_KEY_RIGHT) {
posX = posX + movethis;
}
else if (key == GLUT_KEY_LEFT) {
posX = posX - movethis;
}
glutPostRedisplay();
}
void KeysFun(unsigned char key, int xpos, int ypos) {
if (key == 'e' || key == 'E') {
angle=angle+10;
}
else if (key == 'r' || key == 'R') {
angle=angle-10;
}
glutPostRedisplay();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(angle, 0.0f, 0.0f, 1.0f);
glTranslatef(posX, posY, 0.0f);
drawFigure();
glFlush();
}
int main(int argc, char**argv) {
glutInit(&argc, argv);
glutInitWindowSize(600, 600);
glutInitWindowPosition(450, 50);
glutCreateWindow("Frame");
init();
glutDisplayFunc(display);
glutSpecialFunc(&SpecialKeys);
glutKeyboardFunc(&KeysFun);
glutMainLoop();
return EXIT_SUCCESS;
}
You have to read the order of operations in the matrix multiplication chain "backwards". You first have to rotate, then translate, but if you write it as
rotate
translate
vertices
data is traveling "upwards", so the vertices "see" first the translation, then the rotation. Solution: Flip the order of rotation and translation.

How do I get color to change using glut and openGL?

I am trying to teach myself to animate an object without user input, so far I have figured out how to make a scene rotate. How do I get an object to change color though? I thought the code I have would do it, but it remains a white triangle (not even a different color).
How do I get it to change color at the same time that the triangle or perspective rotates?
Here is my current code:
#include <GL/glut.h>
float color1;
float color2;
float color3;
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if (h == 0)
h = 1;
float ratio = w * 1.0 / h;
// Use the Projection Matrix
glMatrixMode(GL_PROJECTION);
// Reset Matrix
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45.0f, ratio, 0.1f, 100.0f);
//changeColor?
color1 += 0.1f;
color2 += 0.3;
color3 += color2;
if (color1 > 1.0)
color1 = 0;
if (color2 > 1.0)
color2 = 0;
if (color3 > 1.0)
color3 = 0;
// Get Back to the Modelview
glMatrixMode(GL_MODELVIEW);
}
float angle = 0.0f;
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt(0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
glColor3f(color1, color2, color3);
glVertex3f(2.0f, -2.0f, 0.0f);
glVertex3f(2.0f, 0.0f, 0.0);
glVertex3f(0.0f, 2.0f, 0.0);
glEnd();
angle += 0.1f;
color1 += 0.1f;
color2 += 0.3;
color3 += color2;
glutSwapBuffers();
}
int main(int argc, char **argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(320, 320);
glutCreateWindow("tutorial example");
// register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
// enter GLUT event processing cycle
glutMainLoop();
return 1;
}
Float colors have to be in range of [0,1] and you only add something to your values and never reset it to zero, so it becomes greater than 1 in first 10 frames (=very fast), OpenGL clamps it to 1, so you see it white.
I.e. that bunch of ifs in changeSize should actually be in renderScene.
For something simple like this use a glutTimerFunc() callback with a reasonable timeout
Update the angle/color in the timer callback & kick off a repaint
Re-set the projection/modelview matrices each time through the glutDisplayFunc() callback, helps prevent weird matrix problems
All together:
#include <GL/glut.h>
float angle = 0.0f;
float color1 = 0.0f;
float color2 = 0.0f;
float color3 = 0.0f;
void timer( int value )
{
angle += 3.0f;
//changeColor?
color1 += 0.001f;
color2 += 0.003f;
color3 += color2;
if (color1 > 1.0)
color1 = 0;
if (color2 > 1.0)
color2 = 0;
if (color3 > 1.0)
color3 = 0;
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
void renderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective(45.0f, w / h, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt
(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
glColor3f(color1, color2, color3);
glVertex3f(2.0f, -2.0f, 0.0f);
glVertex3f(2.0f, 0.0f, 0.0);
glVertex3f(0.0f, 2.0f, 0.0);
glEnd();
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(320, 320);
glutCreateWindow("tutorial example");
glutDisplayFunc(renderScene);
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 1;
}

C++ and GLUT smooth movement

I am new at using graphics with C++ and I have the following code from this
tutorial
here is the code
#include <windows.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h>
#include <math.h>
float angle = 0.0f;
float lx = 0.0f, lz = -1.0f;
float x = 0.0f, z = 5.0f;
float deltaAngle = 0.0f;
float deltaMove = 0;
void drawSnowMan(){
glColor3f(1.0f, 1.0f, 1.0f);
glTranslatef(0.0f, 0.75f, 0.0f);
glutSolidSphere(0.75f, 20, 20);
glTranslatef(0.0f, 1.0f, 0.0f);
glutSolidSphere(0.25f, 20, 20);
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(0.5f, 0.10f, 0.18f);
glutSolidSphere(0.05f, 10, 10);
glTranslatef(-0.1f, 0.0f, 0.0f);
glutSolidSphere(0.05f, 10, 10);
glPopMatrix();
glColor3f(1.0f, 0.5f, 0.5f);
glutSolidCone(0.8f, 0.5f, 10, 2);
}
void changeSize(int w, int h){
if(h == 0)
h = 1;
float ratio = 1.0*w/h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0,0,w,h);
gluPerspective(45.0f, ratio, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}
void computePos(float deltaMove){
x += deltaMove * lx * 0.1f;
z += deltaMove * lz * 0.1f;
}
void computeDir(float deltaAngle){
angle += deltaAngle;
lx = sin(angle/75.0);
lz = -cos(angle/75.0);
}
void pressKey(int key, int xx, int yy){
switch(key){
case GLUT_KEY_LEFT: deltaAngle = -0.5f; break;
case GLUT_KEY_RIGHT: deltaAngle = 0.5; break;
case GLUT_KEY_UP: deltaMove = 0.5f; break;
case GLUT_KEY_DOWN: deltaMove = -0.5f; break;
}
}
void relaseKey(int key, int x, int y){
switch(key){
case GLUT_KEY_LEFT:
case GLUT_KEY_RIGHT: deltaAngle = 0.0f; break;
case GLUT_KEY_UP:
case GLUT_KEY_DOWN: deltaMove = 0; break;
}
}
void renderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
if(deltaMove)
computePos(deltaMove);
if(deltaAngle)
computeDir(deltaAngle);
gluLookAt( x, 1.0f, z,
x+lx, 1.0f, z+lz,
0.0f, 1.0f, 0.0f
);
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
angle += 0.1f;
for(int i = -3; i < 3; i++){
for(int j = -3; j < 3; j++){
glPushMatrix();
glTranslatef(i*10.0,0, j*10.0);
drawSnowMan();
glPopMatrix();
}
}
glutSwapBuffers();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(320,320);
glutInitWindowPosition(100,100);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Lighthouse 3D");
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glutSpecialFunc(pressKey);
glutIgnoreKeyRepeat(1);
glutSpecialUpFunc(relaseKey);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return 1;
}
My problem is the following, when i try to turn to the left and i keep the left key pressed everything works perfectly fine. When i try to hit the left once the action is not smooth at all. In some cases if the button stroke is too fast it even turns to the opposite direction!
I assume you mean keyboard instead of mouse, in which case to have a "smoother" and "slower" feel you need to adjust your deltaAngle values, which might be too high.
This is only a temporary fix, since those values may affect other machines in different ways - some may be faster, some may be slower. You need to calculate the host machine's FPS in your render loop and multiply your delta values with it, to have the same performance on every computer. This is called time-based movement and is an essential feature of every modern graphics application.
This is exactly what is happening in the following tutorial, when a dot is moving too fast on the screen.
http://lazyfoo.net/SDL_tutorials/lesson32/index.php
A glutIdleFunc() will eat all your battery/CPU/GPU, use a glutTimerFunc() instead to redraw on a predictable, sane schedule.
Accumulate your input state between frames and apply it in your glutTimerFunc() instead of trying to do it right in your keyup/keydown callbacks.
No need for a glutResizeFunc(), do all that just before your draw.
You're using C++ so you should use the C++ versions of C headers, like <cmath> instead of <math.h>.
All together:
#include <GL/glut.h>
#include <cmath>
#include <map>
std::map< int, bool > keys;
void pressKey(int key, int xx, int yy)
{
keys[ key ] = true;
}
void relaseKey(int key, int x, int y)
{
keys[ key ] = false;
}
float angle = 0.0f;
float lx = 0.0f, lz = -1.0f;
float x = 0.0f, z = 5.0f;
void update()
{
const float angleStep = 0.5f;
if( keys[ GLUT_KEY_LEFT ] ) angle -= angleStep;
if( keys[ GLUT_KEY_RIGHT ] ) angle += angleStep;
const float moveStep = 0.5f;
float move = 0.0f;
if( keys[ GLUT_KEY_DOWN ] ) move -= moveStep;
if( keys[ GLUT_KEY_UP ] ) move += moveStep;
x += move * lx * 0.1f;
z += move * lz * 0.1f;
lx = sin(angle/75.0);
lz = -cos(angle/75.0);
}
void drawSnowMan()
{
glColor3f(1.0f, 1.0f, 1.0f);
glTranslatef(0.0f, 0.75f, 0.0f);
glutSolidSphere(0.75f, 20, 20);
glTranslatef(0.0f, 1.0f, 0.0f);
glutSolidSphere(0.25f, 20, 20);
glPushMatrix();
glColor3f(0.0f, 0.0f, 0.0f);
glTranslatef(0.5f, 0.10f, 0.18f);
glutSolidSphere(0.05f, 10, 10);
glTranslatef(-0.1f, 0.0f, 0.0f);
glutSolidSphere(0.05f, 10, 10);
glPopMatrix();
glColor3f(1.0f, 0.5f, 0.5f);
glutSolidCone(0.8f, 0.5f, 10, 2);
}
void renderScene(void)
{
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective(45.0f, w / h, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt
(
x, 1.0f, z,
x+lx, 1.0f, z+lz,
0.0f, 1.0f, 0.0f
);
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
for(int i = -3; i < 3; i++)
{
for(int j = -3; j < 3; j++)
{
glPushMatrix();
glTranslatef(i*10.0,0, j*10.0);
drawSnowMan();
glPopMatrix();
}
}
glutSwapBuffers();
}
void timer( int value )
{
update();
glutTimerFunc( 16, timer, 0 );
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(320,320);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Lighthouse 3D");
glutDisplayFunc(renderScene);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(relaseKey);
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 1;
}

gluLookAt() doesn't work as expected

I have created a bowling game in OpenGL using Eclipse.
Now I want to change the view of camera upon key-pressed.
But When I press x button, everything disappears.
Here us the code: -
#include <GL/glut.h>
#include <stdlib.h>
int refreshMillis = 30; // Refresh period in milliseconds
int windowWidth = 640; // Windowed mode's width
int windowHeight = 480; // Windowed mode's height
int windowPosX = 50; // Windowed mode's top-left corner x
int windowPosY = 50; // Windowed mode's top-left corner y
bool fullScreenMode = false; // Full-screen or windowed mode?
GLfloat ballTSpeed = 0.15f; // Ball's speed in y directions
GLfloat x = 1.0f, y = 10.0f, z = 10.0f, i = 0.0f, j = 0.0f, k = 0.0f, a = 0.0f,
b = 0.0f, c = -1.0f;
bool moveBallUp = false, moveBallDown = false, isCollision = false, resetCall =
false;
//
GLfloat cone1[] = { 0.0f, 2.5f, -11.0f, /*rotated*/30.0f, -1.5, 0.0, 0.0 };
GLfloat cone2[] = { 2.0f, 2.5f, -11.0f, /*rotated*/30.0f, -1.5, 0.0, 0.0 };
GLfloat cone3[] = { -2.0f, 2.5f, -11.0f, /*rotated*/30.0f, -1.5, 0.0, 0.0 };
GLfloat ball[] = {/* X */0.0f, /* Y */-2.0f, /* Z */-6.0f, /*sphere*/1.0f, 50.0,
50.0 };
//
void resetGame() {
resetCall = true;
cone1[0] = 0.0f;
cone1[1] = 2.5f;
cone1[2] = -11.0f;
/*rotated*/
cone1[3] = 30.0f;
cone1[4] = -1.5;
cone1[5] = 0.0;
cone1[6] = 0.0;
cone2[0] = 2.0f;
cone2[1] = 2.5f;
cone2[2] = -11.0f;
/*rotated*/
cone2[3] = 30.0f;
cone2[4] = -1.5;
cone2[5] = 0.0;
cone2[6] = 0.0;
cone3[0] = -2.0f;
cone3[1] = 2.5f;
cone3[2] = -11.0f;
/*rotated*/
cone3[3] = 30.0f;
cone3[4] = -1.5;
cone3[5] = 0.0;
cone3[6] = 0.0;
}
const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f };
static void resize(int width, int height) {
const float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(x, y, z, i, j, k, a, b, c);
// eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz
}
/* Called back when the timer expired */
void Timer(int value) {
glutPostRedisplay(); // Post a paint request to activate display()
glutTimerFunc(refreshMillis, Timer, 0); // subsequent timer call at milliseconds
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case 27: // ESC key
exit(0);
break;
case 'r':
resetGame();
break;
case 'i':
x += 0.5;
gluLookAt(x, y, z, i, j, k, a, b, c);
// eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz
}
}
void specialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_F1: // F1: Toggle between full-screen and windowed mode
fullScreenMode = !fullScreenMode; // Toggle state
if (fullScreenMode) { // Full-screen mode
windowPosX = glutGet(GLUT_WINDOW_X ); // Save parameters for restoring later
windowPosY = glutGet(GLUT_WINDOW_Y );
windowWidth = glutGet(GLUT_WINDOW_WIDTH );
windowHeight = glutGet(GLUT_WINDOW_HEIGHT );
glutFullScreen(); // Switch into full screen
} else { // Windowed mode
glutReshapeWindow(windowWidth, windowHeight); // Switch into windowed mode
glutPositionWindow(windowPosX, windowPosX); // Position top-left corner
}
break;
case GLUT_KEY_UP:
if (!isCollision)
moveBallUp = true;
break;
case GLUT_KEY_PAGE_UP:
ballTSpeed *= 1.2f;
break;
}
}
static void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (moveBallUp) {
ball[1] += ballTSpeed;
ball[2] -= 0.02 + ballTSpeed;
}
if (ball[1] >= (cone1[1] - 0.4) && ball[1] <= cone1[1]) {
if (!isCollision)
{
cone1[0] -= 0.5;
cone1[4] -= 10.0;
cone1[5] += 10.0;
cone1[2] += -0.3;
cone2[0] += 0.5;
cone2[4] -= 10.0;
cone2[5] -= 10.0;
cone2[2] += -0.4;
cone3[0] += 0.5;
cone3[4] -= 10.0;
cone3[5] -= 10.0;
cone3[2] += -0.4;
}
isCollision = true;
moveBallUp = false; // stop moving the ball
}
if (resetCall) {
if ((ball[1] >= -2.0f && ball[1] <= -1.6f)
&& (ball[2] >= -6.0f && ball[2] <= -5.6f)) {
resetCall = false;
isCollision = false;
}
else {
ball[1] -= ballTSpeed;
ball[2] += 0.02 + ballTSpeed;
}
}
glColor3d(1, 1, 0);
glPushMatrix();
glTranslated(cone1[0], cone1[1], cone1[2]);
glRotated(cone1[3], cone1[4], cone1[5], cone1[6]);
glutSolidCone(1, 2, 50, 50);
glPopMatrix();
glColor3d(1, 0, 1);
glPushMatrix();
glTranslated(cone2[0], cone2[1], cone2[2]);
glRotated(cone2[3], cone2[4], cone2[5], cone2[6]);
glutSolidCone(1, 2, 50, 50);
glPopMatrix();
glColor3d(0, 0, 1);
glPushMatrix();
glTranslated(cone3[0], cone3[1], cone3[2]);
glRotated(cone3[3], cone3[4], cone3[5], cone3[6]);
glutSolidCone(1, 2, 50, 50);
glPopMatrix();
glColor3d(1, 0, 0);
glPushMatrix();
glTranslated(ball[0], ball[1], ball[2]);
glutSolidSphere(ball[3], ball[4], ball[5]);
glPopMatrix();
glPushMatrix();
glColor3d(0.6, 1, 0.20);
glBegin(GL_QUADS);
glVertex3f(16.0, 5.0, -25.0);
glVertex3f(-16.0, 5.0, -25.0);
glVertex3f(-6.0, -4.0, -5.0);
glVertex3f(6.0, -4.0, -5.0);
glEnd();
glColor3d(1, 1, 0);
glBegin(GL_QUADS);
glVertex3f(16.0, 15.0, -25.0);
glVertex3f(-16.0, 15.0, -25.0);
glVertex3f(-16.0, -4.0, -25.0);
glVertex3f(16.0, -4.0, -25.0);
glEnd();
glutSwapBuffers();
}
/* Program entry point */
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(windowWidth, windowHeight); // Initial window width and height
glutInitWindowPosition(windowPosX, windowPosY); // Initial window top-left corner (x, y)
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Balling Game 3d");
glutReshapeFunc(resize);
glutDisplayFunc(display);
glClearColor(1, 1, 1, 1);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glutTimerFunc(0, Timer, 0); // First timer call immediately
glutSpecialFunc(specialKeys); // Register callback handler for special-key event
glutKeyboardFunc(keyboard); // Register callback handler for special-key event
glutMainLoop();
return EXIT_SUCCESS;
}
In the code case 'i':
x += 0.5;
gluLookAt(x, y, z, i, j, k, a, b, c);
// eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz
Camera view should be changed as I guess but I know that I am doing wrong. Please tell me how to do this?
Never call OpenGL functions from input event handlers. Only misery and dispair comes out of this.
In your input event handlers set variables from the user input data and trigger a redraw. In the drawing function parameterize the rendering process from those variables.
You can remove the resize handler entirely. Setup viewport and projection in the display function
static void display(void) {
int const width = glutGet(GLUT_WINDOW_WIDTH);
int const height = glutGet(GLUT_WINDOW_HEIGHT);
float const ar = (float) width / (float) height;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-ar, ar, -1.0, 1.0, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(view_x, view_y, view_z, target_x, target_y, target_z, up_x, up_y, up_z);
// eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz
/* ... */
In the keyboard handler just set variables and trigger a redisplay
void keyboard(unsigned char key, int mouse_x, int mouse_y) {
switch (key) {
case 27: // ESC key
exit(0);
break;
case 'r':
resetGame();
break;
case 'i':
view_x += 0.5;
/* don't call gluLookAt here! */
}
glutPostRedisplay();
}