I have function moveCamera() that rotate camera around center sphere.
void moveCamera()
{
glLoadIdentity();
int vec = ceil(theta / 3.1415);
int y;
if (vec%2)
y = 1;
else
y = -1;
gluLookAt(e_x, e_y, e_z, 0, 0, 0, 0, y, 0);
}
This function is called inside display()
void display()
{
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
moveCamera();
glCallList(idList);
GLfloat pos[] = {0, 0, 0, 1};
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glFinish();
}
In this situation all works fine. But I noticed some things, that I cannot explain.
For example, if I modify display() function for drawing red line in the direction X-axis like this
void display()
{
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glColor3ub(255, 0, 0);
glLineWidth(5);
glBegin(GL_LINES);
glVertex3i(0, 0, 0);
glVertex3i(1000, 0, 0);
glEnd();
moveCamera();
glCallList(idList);
GLfloat pos[] = {0, 0, 0, 1};
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glFinish();
}
... nothing happened. Why???
Another, if I remove glLoadIdentity() after glClear() the red line will draw, but when I move the camera by keyboard buttons, I see some bug in rendering this line (the line change their coordinates for drawing). For see it, run my code.
The full code:
#include <iostream>
#include <glut.h>
#include <math.h>
#include <QDebug>
using namespace std;
#define WIDTH 1024
#define HEIGHT 600
void display();
void reshape(int width, int height);
void keyboard(unsigned char key, int x, int y);
void moveCamera();
void init();
void mkList();
void enableLight();
//double z(const double &x, const double &y);
void printMatrix(double *m)
{
for (int i = 0; i < 4; i++)
qDebug() << QString("%1 %2 %3 %4").arg(m[i*4]).arg(m[i*4+1]).arg(m[i*4+2]).arg(m[i*4+3]);
qDebug() << "\n";
}
GLuint idList = 0;
double e_x = 0;
double e_y = 0;
double e_z = 0;
double r = 300;
double phi = 0;
double theta = 1.5;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WIDTH, HEIGHT);
glutInitWindowPosition(30, 100);
glutCreateWindow("Lab#2");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glEnable(GL_DEPTH_TEST);
init();
mkList();
enableLight();
glutMainLoop();
return 0;
}
void display()
{
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glColor3ub(255, 0, 0);
glLineWidth(5);
glBegin(GL_LINES);
glVertex3i(0, 0, 0);
glVertex3i(1000, 0, 0);
glEnd();
moveCamera();
glCallList(idList);
GLfloat pos[] = {0, 0, 0, 1};
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glFinish();
}
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 2, 100, 2000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
#define ESCAPE '\033'
switch (key)
{
case ESCAPE:
exit(0);
break;
case 's':
theta += 0.1;
break;
case 'w':
theta -= 0.1;
break;
case 'a':
phi += 0.1;
break;
case 'd':
phi -= 0.1;
break;
case 'q':
r-=5;
break;
case 'e':
r+=5;
break;
default:
break;
}
e_x = r * sin(theta) * cos(phi);
e_z = r * sin(theta) * sin(phi);
e_y = r * cos(theta);
glutPostRedisplay();
}
void moveCamera()
{
glLoadIdentity();
int vec = ceil(theta / 3.1415);
int y;
if (vec%2)
y = 1;
else
y = -1;
gluLookAt(e_x, e_y, e_z, 0, 0, 0, 0, y, 0);
}
void init()
{
e_x = r * sin(theta) * cos(phi);
e_z = r * sin(theta) * sin(phi);
e_y = r * cos(theta);
}
void mkList()
{
int idInnerList = glGenLists(1);
glNewList(idInnerList, GL_COMPILE);
glColor3ub(255, 0, 0);
glPushMatrix();
glTranslatef(-200, 0, 0);
glutWireSphere(50, 10, 10);
glPopMatrix();
glColor3ub(0, 255, 0);
glPushMatrix();
glTranslatef(200, 0, 0);
glutSolidCube(100);
glPopMatrix();
glEndList();
idList = glGenLists(1);
glNewList(idList, GL_COMPILE);
glCallList(idInnerList);
glPushMatrix();
glTranslatef(0, 0, 200);
glCallList(idInnerList);
glPopMatrix();
glPushMatrix();
glTranslatef(0, 0, -200);
glCallList(idInnerList);
glPopMatrix();
glEndList();
}
void enableLight()
{
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
GLfloat diffuse[] = {0.7, 0.7, 0.7, 1};
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glEnable(GL_LIGHT0);
}
For a start, I want to say this: it's 2016 - don't use legacy OpenGL. Read up on modern OpenGL with the help of your favorite search engine.
If by "nothing happened" you mean "i couldn't see the red line" and if I understood your code correctly, that's just because the line will be entirely clipped. Let me explain.
The first thing you do that affects vertex transformation inside display()
is call glLoadIdentity()
. This will set the top of the current matrix stack to the identity matrix, I
. Let's assume the current stack is MODELVIEW
and the current projection matrix, P
, is the one set in reshape()
, then your line will undergo the following transformation from local-space into clip-space:
Vx_clip = P * I * Vx_local
Vy_clip = P * I * Vy_local
Given that the model-view matrix is the identity, both local coordinates will remain the same in world-space before being transformed into clip-space. Since your near plane is at z=-100
, the line will be completely out of the frustum, i.e. not in the space between the near- and the far-plane, and thus be clipped entirely. Mathematically this is a little more involved, but it's conceptually accurate.
You can convince yourself by defining the red line like this
glVertex3i(-500, 0, -100);
glVertex3i(500, 0, -100);
Now, part of the line will be inside inside your frustum, even with an identity model-view matrix, because it partially intersects the near plane and thus must not be entirely clipped.
If you apply a non-identity model-view matrix first by calling moveCamera()
before rendering the red-line, you'll also be able to partially see the red line. Why? Well, let's assume your polar coordinates are chosen so that the camera will still look in the direction (0, 0, -z)
, then with the given radius, you define the camera to be at (0, 0, 300) in world-space, which gluLookAt()
will map to a transformation matrix which will simply add a translation of (0, 0, -300) to both vertices.
Given the initial definition of your line and the new model-view matrix the vertices of the line will be at (0, 0, -300)
and (1000, 0, -300)
after left-multiplying the model-view matrix. After transformation to clip-space by left-multiplying the projection matrix, the line will be only partially clipped and thus be visible.
As I said, this is much more involved and in fact, this is only part of the complete vertex transformation pipeline. Read this and this for a mathematical treatise of the subject of vertex transformation. It's computer-graphics 101. And please: focus on the math, not on the use of the legacy API that you'll unfortunately see there.