在glOrtho和gluPerspective之间切换

时间:2013-05-15 07:51:40

标签: c++ opengl perspectivecamera orthogonal

我正在使用一个小的OpenGL - GLUT程序(我完全是noob),并且我在使用gluPerspective和glOrtho按键(例如'p')之间切换时遇到很多问题。

我用一些屏幕来说明问题...使用gluPerspectiveglOrtho

这是我的代码......

#if defined(__APPLE__)
    #include <OpenGL/OpenGL.h>
    #include <GLUT/GLUT.h>
#else
    #include <GL/gl.h>
    #include <GL/greeglut.h>
#endif

#include <iostream>
#include <math.h>
#include "model.h"

using namespace std;

// 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;
// angle for rotating triangle
float angle = 0.0f;
float fov = 45.0;

Model m;
Model m1;
Model m2;
Model m3;

double maxX, maxY, maxZ;
double minX, minY, minZ;
double centX, centY, centZ;
double maxTam;

bool persp = true;

double min(double x, double y) {
    if(x < y) return x;
    return y;
}

double max(double x, double y) {
    if(x > y) return x;
    return y;
}

void setMinMaxXYZ(void) {
    maxX = minX = m.vertices()[0];
    maxY = minY = m.vertices()[1];
    maxZ = minZ = m.vertices()[2];

    for(int i = 3; i < m.vertices().size(); i += 3) {
        maxX = max(maxX,m.vertices()[i]);
        minX = min(minX,m.vertices()[i]);

        maxY = max(maxY,m.vertices()[i+1]);
        minY = min(minY,m.vertices()[i+1]);

        maxZ = max(maxZ,m.vertices()[i+2]);
        minZ = min(minZ,m.vertices()[i+2]);
    }

    centX = ((maxX - minX)/2) + minX;
    centY = ((maxY - minY)/2) + minY;
    centZ = ((maxZ - minZ)/2) + minZ;
}

void changeView(void) {
    int w = glutGet(GLUT_WINDOW_WIDTH);
    int h = glutGet(GLUT_WINDOW_HEIGHT);
    float ratio = w * 1.0 / h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if(persp) gluPerspective(fov, ratio, 0.1f, 100.0f);
    else glOrtho(-1,1,-1,1,-0.5,100.0);

    glMatrixMode(GL_MODELVIEW);
}

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;
    if(w == 0) w = 1;

    float ratio = w * 1.0 / h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if(persp) gluPerspective(fov, ratio, 0.1f, 100.0f);
    else glOrtho(-1,1,-1,1,0.1,100.0);

    glViewport(0,0,w,h);

    glMatrixMode(GL_MODELVIEW);

    glutPostRedisplay();
}

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

    // Reset transformations
    glLoadIdentity();

    // Posicionament de la càmera
    gluLookAt(  x, 1.0f, z,
                x+lx, 1.0f, z+lz,
                0.0f, 1.0f, 0.0f);

    glClearColor(0.5,0.5,1.0,1.0);

    // dibuix terra
    glColor3f(0.0f, 255.0f, 0.0f);
    glBegin(GL_QUADS);
        glVertex3f(-5.0f, 0.0f, -5.0f);
        glVertex3f(-5.0f, 0.0f, 5.0f);
        glVertex3f( 5.0f, 0.0f, 5.0f);
        glVertex3f( 5.0f, 0.0f, -5.0f);
    glEnd();

    // Models .obj
    for (int i = 0; i < 3; ++i) {

        float transX, transY, transZ;
        if(i == 0) {
            m = m1;
            transX = -1.25; transY = 0.5; transZ = -2.0;

        } else if(i == 1) {
            m = m2;
            transX = -0.5; transY = 0.5; transZ = 2.5;

        } else {
            m = m3;
            transX = 2.5; transY = 0.25; transZ = -0.5;
        }

        setMinMaxXYZ();
        maxTam = max(max(maxX - minX, maxY - minY), maxZ - minZ);

        glPushMatrix();
            glTranslated(-(centX / maxTam), -(centY / maxTam), -(centZ / maxTam));
            glTranslated(transX,transY,transZ);
            glScaled(1.0/maxTam,1.0/maxTam,1.0/maxTam);

            glBegin(GL_TRIANGLES);
                for(int i = 0; i < m.faces().size(); i++){
                    const Face &f = m.faces()[i];
                    glColor3f(Materials[f.mat].diffuse[0],Materials[f.mat].diffuse[1],Materials[f.mat].diffuse[2]);

                    for(int j = 0; j < 3; j++)
                        glVertex3dv(&m.vertices()[f.v[j]]);
                    }
            glEnd();
        glPopMatrix();
    }

    glutSwapBuffers();
}

void processKeys(unsigned char key, int x, int y) {
    if (key == 27)
        exit(0);

    else if(key == 'p'){
        persp = not persp;
        changeView();
    }
}

void processSpecialKeys(int key, int xx, int yy) {
    float fraction = 0.1f;

    switch (key) {
        case GLUT_KEY_LEFT :
            angle -= 0.01f;
            lx = sin(angle);
            lz = -cos(angle);
        break;

        case GLUT_KEY_RIGHT :
            angle += 0.01f;
            lx = sin(angle);
            lz = -cos(angle);
        break;

        case GLUT_KEY_UP :
            x += lx * fraction;
            z += lz * fraction;
        break;

        case GLUT_KEY_DOWN :
            x -= lx * fraction;
            z -= lz * fraction;
        break;
    }
}

void idle(void) {
    glutPostRedisplay();
}

void iniView(void) {
    int w = glutGet(GLUT_WINDOW_WIDTH);
    int h = glutGet(GLUT_WINDOW_HEIGHT);
    float ratio = w * 1.0 / h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f, ratio, 0.1f, 100.0f);
    //glOrtho(-1,1,-1,1,0.01,1000);

    glMatrixMode(GL_MODELVIEW);

}

int main(int argc, char **argv) {

    // init GLUT i creació finestra
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(800,800);
    glutCreateWindow("IDI: Bloc 3 - Càmeres i perspectives");

    // Carregar models .obj
    m1.load("model/legoman-assegut.obj");
    m2.load("model/Shaun_Hastings.obj");
    m3.load("model/porsche.obj");

    // crides
    glutDisplayFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutIdleFunc(idle);
    glutKeyboardFunc(processKeys);
    glutSpecialFunc(processSpecialKeys);

    iniView();

    // OpenGL init
    glEnable(GL_DEPTH_TEST);

    // loop
    glutMainLoop();

    return 1;
}

我认为我应该在glOrtho视图中看到绿色的“地板”......我做错了什么?

PS。模型对象是教师提供的.obj文件。

编辑

最后,glOrtho正常工作。但是现在......我还有另一个问题,我怎样才能最大化窗口和(在glOrtho模式下)图像不变形?

在changeSize()函数中...当我使用gluPerspective时它工作正常,但没有glOrtho !!

1 个答案:

答案 0 :(得分:0)

根据您设置模型视图矩阵的方式,您实际上不会看到具有正交投影的地板: 它发生的原因是你的地板与XZ平面平行 - 你的视图矢量也是。

// Posicionament de la càmera
gluLookAt(  x, 1.0f, z,
            x+lx, 1.0f, z+lz,
            0.0f, 1.0f, 0.0f);

gluLookAt的前3个参数是摄像机位置的xyz分量,接下来的3个参数是“感兴趣的中心”的xyz。这两个点之间的向量是视图向量,它的y分量是0,意味着它与XZ平行,因而是你的地板。

如果你想看到地板+正投影,你必须倾斜相机以使其向下看。