using gluLookAt and mouse to channge viewing angle in opengl/glut - c++

Hello so i am attempting to use a mouse function to move the perspective of gluLookAt to no luck so far i have attempted to adjust upX and upY based off of the mouse position however I want the program to be able to do an entire 360 rotation around the object based on the mouse movement and would like it to stop when the mouse movement in the window stops. Any help would be appreciated I am still learning
#include <iostream>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
float posX=4, posY=6, posZ=5, targetX=0, targetY=0, targetZ=0, upX=0, upY=1, upZ=0;
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0/3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(posX, posY, posZ, targetX, targetY, targetZ, upX, upY, upZ);
glColor3f(1.0, 1.0, 1.0);
glutWireTeapot(1.5);
glBegin(GL_LINES);
glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(10, 0, 0);
glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, 10, 0);
glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, 10);
glEnd();
glFlush();
}
void usage(){
std::cout<< "\n\n\
q,Q: Quit\n\n" ;
std::cout.flush();
}
void onMouseMove(int x, int y)
{
posX = x*cos(posY) + PosY*sin(PosX)*sin(yRot) - dz*cos(xRot)*sin(yRot)
glutPostRedisplay();
}
void KeyboardFunc (unsigned char key, int eyeX, int eyeY)
{
switch (key)
{
case 'q':
case 'Q':
exit(0);
break;
}
glutPostRedisplay();
}
void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
usage();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(300,250);
glutInitWindowSize(800, 600);
glutCreateWindow("Final");
init();
glutDisplayFunc(display);
glutPassiveMotionFunc(&onMouseMove);
glutKeyboardFunc(&KeyboardFunc);
glutMainLoop();
}

If you want to implement an arcball camera, and you want to do it with the fixed-function pipeline matrix stack, it'd actually be simpler to not use gluLookAt() but glRotate/glTranslate, like so:
glTranslatef(0f, 0f, -radius);
glRotatef(angX, 1f, 0f, 0f);
glRotatef(angY, 0f, 1f, 0f);
glTranslatef(-targetX, -targetY, -targetZ);
where radius is the distance of the "camera" to the viewed point, angX is the angle around the X axis, angY the angle around the Y axis and (targetX, targetY, targetZ) is the position of the viewed point (your targetX/Y/Z).
You don't have to compute sin/cos yourself (it is computed by glRotatef) and all you have to do is set/increase angX and angY in your motion function.

Related

OpenGL Project - objects not keeping filling color on movement

When I execute the code I get a hot air balloon formed of three elements. My issue is that when I move the objects from the keyboard, the objects loose color, and become more like wire than solid.
From what I discovered until now, my trouble comes from this function call:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
But I need it to make the ropes...
/*
This program shows a hot air balloon rotating around its own axe to the left and to the right
*/
#include "glos.h"
#include<math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK rotateRight(void);
void CALLBACK rotateLeft(void);
static GLfloat x = 0;
static GLfloat y = 0;
static GLfloat z = 0;
static GLfloat alfa = 0;
double PI = 3.14159265;
void myinit (void) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
}
void CALLBACK rotateLeft(void) { y -= 5; }
void CALLBACK rotateRight(void) { y += 5; }
void CALLBACK display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(x, 1, 0, 0);
glRotatef(y, 0, 1, 0);
glTranslatef(0, -80, 0);
//cube = basket
glColor3f(1, 1, 0);
auxSolidCube(50);
//full sphere = baloon
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glTranslatef(0,200,0);
glRotatef(-90, 1, 0, 0);
auxSolidSphere(130.0);
glPopMatrix();
//polygon cylinder = ropes
glPushMatrix();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUAD_STRIP);
glColor3f(0.0, 1.0, 1.0);
for (alfa = 0; alfa <= 360; alfa+=30) {
glVertex3f(65 * sin((PI * alfa) / 180), 100, 65 * cos((PI * alfa) / 180));//top of the cylinder
glVertex3f(15 * sin((PI * alfa) / 180),0, 15 * cos((PI * alfa) / 180));//base of the cylinder
}
glEnd();
glPopMatrix();
glPopMatrix();
glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
if (!h) return;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-400,400, -400 *(GLfloat)h / (GLfloat)w, +400.0*(GLfloat)h/(GLfloat)w, -1000.0, 1000.0);
else
glOrtho (-400*(GLfloat)w / (GLfloat)h, 400.0*(GLfloat)w/(GLfloat)h, -400, 400.0, -1000.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH);
auxInitPosition (100, 0, 600, 400);
auxInitWindow ("Hot air balloon");
myinit ();
auxKeyFunc(AUX_RIGHT, rotateRight);
auxKeyFunc(AUX_LEFT, rotateLeft);
auxReshapeFunc (myReshape);
auxMainLoop(display);
return(0);
}
OpenGL is a state engine. Once a state has been set, it is retained until it is changed again, even beyond frames. Therefore, you need to set the polygon mode GL_FILL before rendering the solid geometry:
void CALLBACK display (void)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// render solid geometry
// [...]
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// render wireframe geometry
// [...]
}

Why in OpenGL my camera rotates 180 degrees every other time?

I want to do something like a 3d-shooter.
The calculations seems to be correct, but it is works every other time with a spread with 180 degree rotation on every call glutPostRedisplay(). I understood that thanks to that red line.
I do this with such IDE: Code Blocks / Qt Creator under Linux(Ubuntu x64).
main.cpp
#include "Functions.h"
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(wnd_width, wnd_height);
glutInitWindowPosition(300, 100);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glutCreateWindow("OpenGL my");
glutDisplayFunc(display);
glutIdleFunc(Idle);
glutSpecialFunc(KeyPressed);
GLdouble aspect = wnd_width/wnd_height;
gluPerspective(90, aspect, 0.1, 10);
glTranslatef(0, -0.3, 0);
glutMainLoop();
return 0;
}
Functions.h
#include <GL/glut.h>
#include <math.h>
#include <iostream>
int wnd_width=1300;
int wnd_height=900;
float pos_x=0, pos_z=0.1;
float angle = 0;
float speed = 0.1;
void DrawFloor(){
glVertex3d(1, 0, 2.5);
glVertex3d(1, 0, 0);
glVertex3d(-1, 0, 0);
glVertex3d(-1, 0, 2.5);
}
void DrawWall(float x, float width, float height){
glVertex3f(x, height, 0);
glVertex3f(x, height, width);
glVertex3f(x, 0, width);
glVertex3f(x, 0, 0);
}
void DrawLine(){
glVertex3f(0, 0.1, -1);
glVertex3f(0, 0.1, 1);
}
void KeyPressed(int key, int x, int y){
switch (key) {
case GLUT_KEY_UP: {
//pos_x = speed * cos(3.14*angle/180);
//pos_z = speed * sin(3.14*angle/180);
pos_z+=0.1;
break;
}
case GLUT_KEY_DOWN: {
pos_x = speed*cos(angle);
pos_z = speed*sin(angle);
break;
}
case GLUT_KEY_LEFT: {
angle += 1;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
case GLUT_KEY_RIGHT: {
angle -= 3;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
}
std::cout<<"x: "<<pos_x<<'\t';
std::cout<<"z: "<<pos_z<<'\n';
glutPostRedisplay();
}
void display(){
glClearColor(0.6, 0.8, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z+0.2, 0, 1, 0);
glBegin(GL_QUADS);
glColor3f(0, 0, 0.7);
DrawFloor();
glColor3f(0, 0.8, 0.1);
DrawWall(-0.5, 2, 0.7);
DrawWall(0.5, 2, 0.7);
glEnd();
glLineWidth(2);
glColor3f(0.7, 0.2, 0.2);
glBegin(GL_LINES);
DrawLine();
glEnd();
glutSwapBuffers();
}
void Idle(){
//pos_z+=0.01;
//glutPostRedisplay();
}
You're using the fixed function stack, so you'll have to learn what glMatrixMode does and how transformation matrices are managed in those old ways.
Anyway, consider this a possible implementation of glMatrixMode
void glMatrixMode(GLenum m)
{
switch(m){
case GL_MODELVIEW: ctx->M = &ctx->matrix_modelview; break;
case GL_PROJECTION: ctx->M = &ctx->matrix_projection; break;
case GL_TEXTURE: ctx->M = &ctx->matrix_texture; break;
case GL_COLOR: ctx->M = &ctx->matrix_color; break;
}
}
On other words, there's a (context) global matrix selected with glMatrixMode, that's subsequently used for all folloing matrix manipulations.
Hence, glMatrixMode is not some form of initialization, but something you use to switch (often several times) during rendering a frame! Your use of it in the main function is kind of pointless. You must use it in your drawing function.
Furthermore, every matrix manipulation multiplies on top, of what's currently in ctx->M. gluLookAt is normally used with a identity matrix. If you don't reset you identity, that gluLookAt will work relative to the look-at done previously. So what you want is this:
void display(){
glClearColor(0.6, 0.8, 1., 1.); /* <<<----* */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTIOM);
glLoadIdentity();
setup_projection_here();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z+0.2, 0, 1, 0);
glBegin(GL_QUADS);
/* ... */
glutSwapBuffers();
}
(*) Also you normally want to clear to alpha = 1 on the main framebuffer, unless you're planning on drawing window-translucent imagery. With alpha = 0 things might look correct in the window, but if a screenshot is taken, or some screen recording or sharing is used, it may cause undesired transparence.

gluLookAt() has no effect in OpenGL

I'm trying to look at the square from the other side using the gluLookAt() function.
After using the function, nothing changes, although I expected that the corners of the square will change.
I set the camera point to the rightmost part of the world and look at its center, where the square is located.
He had to stretch out to the sides. Why hasn't anything changed?
Code:
#include "includes.h"
using namespace std;
constexpr auto FPS_RATE = 60;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;
void init();
void idleFunction();
void displayFunction();
double getTime();
double getTime()
{
using Duration = std::chrono::duration<double>;
return std::chrono::duration_cast<Duration>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
}
const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;
void init()
{
glutDisplayFunc(displayFunction);
glutIdleFunc(idleFunction);
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -windowDepth / 2, windowDepth / 2);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
void idleFunction()
{
const double current_time = getTime();
if ((current_time - last_render) > frame_delay)
{
last_render = current_time;
glutPostRedisplay();
}
}
void displayFunction()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
gluLookAt(-300, 0, 0,
0, 0, 0,
0, 1, 0);
glColor3f(1, 1, 1);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
glutCreateWindow("Window");
init();
glutMainLoop();
return 0;
}
The issue is caused because gluLookAt() is call with in a glBegin/glEnd sequence. This is not allowed. You've to call gluLookAt before glBegin.
Once drawing of primitives was started by glBegin it is only allowed to specify vertex coordinates (glVertex) and change attributes (e.g. glColor, glTexCoord ...), till the drawn is ended (glEnd).
All other instruction will be ignored and cause a GL_INVALID_OPERATION error (error code 1282).
Further note, that glLookAt doesn't set a the current matrix. It defines a matrix and multiplies the current matrix by the new matrix. Set the matrix mode (glMatrixMode) and set Identity matrix by glLoadIdentity before gluLookAt.
With the view matrix
gluLookAt(-300, 0, 0, 0, 0, 0, 0, 1, 0);
you want "see" anything, because with that matrix the line of sight is set along the x-axis and you look at the 2 dimensional polygon from the side.
Note, the polygon is a 2D object. The size of the object appears different if you look at it from the front, from the side (then it is a line and not visible) or from an direction in between. The first 3 parameters of gluLookAt define the point of view the next 3 parameters define the point you look at. The vector from the point of view to the point you look at is the line of sight.
Probably yo want look along the z-axis:
void displayFunction()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, -300, 0, 0, 0, 0, 1, 0);
glBegin(GL_POLYGON);
glColor3f(1, 1, 1);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glutSwapBuffers();
}
You use Orthographic (parallel) projection. If you would use Perspective projection, then the projected size of the object would decrease, when the distance to the point of view increases. Perspective projection can be set by gluPerspective. e.g.:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0, (double)windowWidth / windowHeight, 0.1, 600.0);

make GLUT application to rotate on keyboard press

guys i try to make an GLUT application that could rotate object on key pressed, but it seems not worked.
#include <stdio.h>
#include <gl/glut.h>
GLfloat rotation = 90.0;
float posX = 0, posY = 0, posZ = 0;
void reshape(int width, int heigth){
/* window ro reshape when made it bigger or smaller*/
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 rect(){
glBegin(GL_POLYGON);
glVertex2f(-0.2, -0.2);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(-0.2, 0.2);
glColor3f(1.0, 0.0, 1.0);
glVertex2f(0.2, 0.2);
glColor3f(0.0, 1.0, 1.0);
glVertex2f(1.2, -0.2);
glColor3f(1.0, 1.0, 1.0);
glEnd();
}
void display(){
//Clear Window
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(posX,posY,posZ);
rect();
glPopMatrix();
glFlush();
}
void init(){
// set clear color to black
glClearColor(0.0, 0.0, 0.0, 0.0);
// set fill color to white
glColor3f(1.0, 1.0, 1.0);
//set up standard orthogonal view with clipping
//box as cube of side 2 centered at origin
//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 = 10;
int deg = 0;
void keyboardown(int key, int x, int y)
{
switch (key){
case GLUT_KEY_RIGHT:
glRotatef((deg+=move_unit), posX, posY, posZ);;
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
glRotatef(deg-=move_unit, posX, posY, posZ);;
break;
case GLUT_KEY_UP:
glRotatef(deg-=move_unit, posX, posY, posZ);;
break;
case GLUT_KEY_DOWN:
glRotatef(deg+=move_unit, posX, posY, posZ);;
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(500,500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Move Test");
glutDisplayFunc(display);
init();
glutSpecialFunc(keyboardown);
glutMainLoop();
}
is there is something i did it wrong?
before, i tried to use the GLUT_KEY_ for moving 2d object and it worked, but when i change the command to glrotatef, it doesn't work.
have any suggestion?
The problem here is, that you override the matrix before it is used. In keyboardown the matrix is set, but at the begin of display the glLoadIdentity(); function is called, which resets the matrix and removes the rotation.
To solve this, you can, e.g., store the rotation angle in a variable. In keyboardown you increase/decrease the angle. When rendering in the display function, you reset the matrix as already done and then add the rotation by calling glRotatef with the previously stored angle.

Depth Test in opengl

My program refuses to do depth testing. The two sphere objects are always drawn in the order they are created, not according to their position. Sphere alpha is positioned at (0, 0, 1) and Sphere beta is positioned (0, 0, -10), yet OpenGL still draws beta on top of alpha. I set depth test to enabled in my program.
Nothing appears to work. I want OpenGL to do depth test automatically on any objects drawn in the window. Any help or advise would be greatly appreciated. Here is the full code.
#include "GL/freeglut.h"
#include "GL/gl.h"
#include "GL/glu.h"
const int SPHERE_RES = 200;
double Z_INIT = -28.0;
double RADIUS = 2;
double Red[3] = {1, 0, 0};
double Blue[3] = {0, 0, 1};
using namespace std;
/*
* Method handles resize of the window
*/
void handleResize (int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double ratio = (float)w/ (float)h;
gluPerspective(45.0, ratio, 1.0, 100.0);
}
/*
* Color and depth is enabled and in this method
*/
void configureColor(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 0.0f); //Set background to white
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear window.
glDepthFunc(GL_ALWAYS);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
void display (void) {
configureColor();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat sun_direction[] = { 0.0, 0.0, -1.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, sun_direction);
GLUquadric* quad = gluNewQuadric();
//first sphere is drawn
glColor3f(Red[0], Red[1], Red[2]);
glPushMatrix();
glLoadIdentity();
glTranslatef(0, 0, Z_INIT);
glTranslatef(0, 0, 1.0);
gluSphere(quad, RADIUS, SPHERE_RES, SPHERE_RES);
glPopMatrix();
//second sphere is supposed to be drawn behind it,
//but it is drawn on top.
glColor3f(Blue[0], Blue[1], Blue[2]);
glPushMatrix();
glLoadIdentity();
glTranslatef(0, 0, Z_INIT);
glTranslatef(0, 0, -10.0);
gluSphere(quad, RADIUS, SPHERE_RES, SPHERE_RES);
glPopMatrix();
free(quad);
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); //initializes the GLUT
glutInitDisplayMode(GLUT_SINGLE);
glutInitWindowSize(600,600);
glutInitWindowPosition(100,100);
glutCreateWindow("OpenGL - First window demo");
glutReshapeFunc(handleResize);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
I am using Ubuntu 14.04 operating system.
glDepthFunc(GL_ALWAYS);
This is the reason you see the spheres in the order they are drawn. Setting the depth function to GL_ALWAYS simply means all depth tests always pass, for any fragment, be it closer or farther.
You need GL_LESS for the result you want. A fragment having depth lesser than the one in the frame buffer wins; the closer (lesser z) one wins over the farther (greater z) one.
You can either call glDepthFunc(GL_LESS) or comment out glDepthFunc(GL_ALWAYS) since GL_LESS is the default.