关于使用OpenGL模型视图矩阵和矩阵变换的澄清

4
我已经能够使用modelview矩阵和函数,如glTranslatef()gluLookAt()来转换对象或整个场景的透视图,但当我尝试同时进行两者时遇到了问题。
似乎无论我使用gluLookAt()的参数是什么,我绘制的对象都从同一个角度显示。我尝试根据其他线程中的内容调用不同的函数,并使用glPushMatrix()glPopMatrix()的不同用法,但没有成功。这是我现在拥有的内容。对象移动得很好,但我只能从一个视点看到它们。
例如,由于它们应该在xy平面上移动,并且顺时针旋转,我认为将z_0更改为-30会使它们看起来顺时针移动,但似乎没有任何区别。它之前有一长串常量,我将其省略了。最终目标是制作一个简单的太阳系模型。
    GLfloat time = 0.0;
GLfloat inc = 0.01;

// viewing parameters
GLint winWidth = 600, winHeight = 600;
GLfloat x_0 = 0.0, y_0 = 0.0, z_0 = 30.0;
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;
GLfloat Vx = 0.0, Vy= 1.0, Vz = 0.0;
GLfloat xwMin = -50.0, ywMin = -50.0, xwMax = 50.0, ywMax = 50.0;
GLfloat dnear = .3, dfar = 10.0;

void view(void) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(x_0, y_0, z_0, xref, yref, zref, Vx, Vy, Vz);
}

void init(void) {
    view();
    glEnable(GL_DEPTH_TEST);
}

void drawPlanet(GLfloat maj, GLfloat min, GLfloat x0, GLfloat theta,
        GLfloat size) {
    GLfloat x = maj * cosf(theta) + x0;
    GLfloat y = min * sinf(theta);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(x, y, 0);
    glutSolidSphere(size, 25, 25);
    glPopMatrix();
}

void display(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3f(1.0, 1.0, 1.0);

    drawPlanet(MERCURY_MAJOR, MERCURY_MINOR, MERCURY_CENTER,
        time / MERCURY_YEAR, MERCURY_SIZE);

    drawPlanet(MARS_MAJOR, MARS_MINOR, MARS_CENTER,
        time / MARS_YEAR, MARS_SIZE);

    drawPlanet(URANUS_MAJOR, URANUS_MINOR, URANUS_CENTER,
        time / URANUS_YEAR, URANUS_SIZE);

    glFlush();
}

void idle(void) {
    time += inc;
    display();
    glutSwapBuffers();
}

int main (int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(0,0);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
    glutCreateWindow("");

    init();

    glutDisplayFunc(display);
    glutIdleFunc(idle);

    glutMainLoop();
}

如果有人看到我所缺失的内容,我真的很希望能够得到解释或指引一些额外的阅读材料,以帮助我解决这个问题。

1
当您调用 drawPlanet 时,您使用 glLoadIdentity 抹掉了由 gluLookAt 设置的矩阵。 - yiding
1个回答

4
你犯了典型的OpenGL新手错误,将矩阵操作分散在各个地方。你从未初始化OpenGL矩阵状态。每次进入显示函数时,都要重新设置它。这样可以更容易地发现问题。
此外,你可能会误认为OpenGL是场景图,使用glPush/PopMatrix来建立变换层次结构。
如你所知,glPushMatrix会复制堆栈矩阵的当前顶部,并将其推送到堆栈上。其目的是创建临时副本,可以将进一步的变换乘以其中。
现在让我们稍微改变一下你的代码:
void display(void) {
    glViewport(…);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(x_0, y_0, z_0, xref, yref, zref, Vx, Vy, Vz);

    glColor3f(1.0, 1.0, 1.0);

    {
        GLfloat x = maj * cosf(theta) + x0;
        GLfloat y = min * sinf(theta);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity(); // <<<<<<<<<

        glTranslatef(x, y, 0);
        glutSolidSphere(size, 25, 25);
        glPopMatrix();
    }

你看到这里发生了什么吗?你重置了模型视图矩阵为单位矩阵,然后进行了平移。之前创建的观察矩阵完全被丢弃,并且对球体绘制没有任何影响。

去掉我标记的glLoadIdentity()就可以正常工作。


好的,这很有道理。我重新组织了我的代码来合并矩阵变换,这也有所帮助。感谢您的回复。 - user1986358

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接