OpenGL and gluLookAt function



我有一个函数moveCamera(),围绕中心球体旋转相机。

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

这个函数在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();
}

在这种情况下一切都很好。但我注意到一些事情,我无法解释。

例如,如果我修改display()函数,以便在x轴方向上绘制红线,如下所示

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

…什么也没有发生。为什么? ?

另外,如果我在glClear()之后删除glloadiidentity(),红线将绘制,但是当我通过键盘按钮移动相机时,我看到渲染这条线的一些错误(线改变了它们的坐标来绘制)。要查看它,请运行我的代码。

完整代码:

#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 '33'
    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);
}

首先,我想说的是:这是2016年-不要使用传统的OpenGL。在你最喜欢的搜索引擎的帮助下,阅读现代OpenGL。

如果你说的"什么都没发生"的意思是"我看不到红线",如果我正确理解了你的代码,那只是因为这条线将被完全剪切。让我解释一下。

影响display()内部顶点变换的第一件事是调用glLoadIdentity()。这将把当前矩阵堆栈的顶部设置为单位矩阵I。假设当前堆栈是MODELVIEW,当前投影矩阵Preshape()中的一个集合,那么您的行将经历以下从本地空间到剪辑空间的转换:

Vx_clip = P * I * Vx_local
Vy_clip = P * I * Vy_local

假设模型-视图矩阵是单位矩阵,在转换到剪辑空间之前,两个局部坐标将在世界空间中保持不变。因为你的近平面是在z=-100,这条线将完全脱离截锥体,即不在近平面和远平面之间的空间,因此被完全剪切。这在数学上有点复杂,但在概念上是准确的。

你可以这样定义红线来说服自己

glVertex3i(-500, 0, -100);
glVertex3i(500, 0, -100);

现在,线的一部分将在你的截锥体内部,即使是恒等模型-视图矩阵,因为它部分与近平面相交,因此不能完全剪切。

如果在呈现红线之前先调用moveCamera() 来应用非同一性模型视图矩阵,您还可以部分地看到红线。为什么?好吧,让我们假设你选择了极坐标,这样相机仍然会朝(0, 0, -z)的方向看,然后在给定的半径下,你将相机定义为世界空间中的(0,0,300),gluLookAt()将映射到一个变换矩阵,该变换矩阵将简单地向两个顶点添加(0,0,-300)的平移。

给定线的初始定义和新的模型视图矩阵,在左乘模型视图矩阵后,线的顶点将位于(0, 0, -300)(1000, 0, -300)。通过左乘投影矩阵变换到剪辑空间后,该线将只被部分剪辑,因此是可见的。

正如我所说,这是更复杂的,事实上,这只是完整的顶点变换管道的一部分。阅读这篇和这篇关于顶点变换主题的数学论文。这是计算机图形学101。请把注意力集中在数学上,而不是使用遗留的API,你将不幸地在那里看到。

最新更新