了解GL坐标 - 设置透视图并使用gluLookAt

时间:2012-09-17 19:14:48

标签: opengl

我正在使用QGlWidget绘制几个点。我遇到的问题是我似乎无法正确设置视角并在点上建立正确的视图。我一定是误解了某个地方的坐标或做了别的蠢事,但在看了一堆导游和tutotrials之后我仍然被卡住了。屏幕是黑色的,没有分数。这是代码:

 void CGLWidget::initializeGL()
 {
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_ALPHA_TEST);
    glDisable(GL_BLEND);
    glEnable(GL_POINT_SPRITE);
    glClearColor(0, 0, 0, 1);
    assert (glGetError() == GL_NO_ERROR);
 }

void CGLWidget::resizeGL(int w, int h)
 {
    glViewport(-w/2, -h/2, w/2, h <= 0 ? 1 : h/2);

    glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
    //Set the camera perspective
    glLoadIdentity(); //Reset the camera
    gluPerspective(80.0,   //The camera FoV
    w/(double)h, //The width-to-height ratio
    1,                   //The near z clipping coordinate
    100);                //The far z clipping coordinate
 }

 void CGLWidget::paintGL()
 {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0);
    glLoadIdentity();

    glColor3i(255, 255, 255);
    glBegin(GL_POINTS);
        glVertex3d(0,0, -2);
        glVertex3d(0,0, -3);
        glVertex3d(0,0, +3);
        glVertex3d(0,0, 0);
        glVertex3f(-0.75f, -0.25f, -5.0f);
    glEnd();

    assert (glGetError() == GL_NO_ERROR);
 }

我试过在gluLookAt中操纵“眼睛”的z坐标无济于事,所以我必须得到别的错误。

3 个答案:

答案 0 :(得分:3)

为了更清楚地了解gluPerspective()gluLookAt()的工作原理,我建议您使用Nate Robins中的教程,更具体地说是投影演示。

相信我,这是你正在寻找的机器人

enter image description here

无论如何,几天前我在Qt中写了Nehe lesson 5 (3D Shapes)的加香版:

<强> GLWidget.cpp

#include "GLWidget.h"

#include <iostream>
#include <QKeyEvent>
#include <QTimer>

GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent)
{
    angle_tri = 0.f;
    angle_quad = 0.f;
    _eye_x = 0.f;
    _eye_y = 0.f;
    _mouse_is_moving = false;
    _width = 0;
    _height = 0;
}

GLWidget::~GLWidget()
{

}

void GLWidget::_tick()
{
    update(); // triggers paintGL()
    QTimer::singleShot(33, this, SLOT(_tick()));
}

void GLWidget::initializeGL()
{
//    glShadeModel(GL_SMOOTH);                          // Enable Smooth Shading
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);               // Black Background
//    glClearDepth(1.0f);                                   // Depth Buffer Setup
//    glEnable(GL_DEPTH_TEST);                          // Enables Depth Testing
//    glDepthFunc(GL_LEQUAL);                               // The Type Of Depth Testing To Do
//    glEnable ( GL_COLOR_MATERIAL );
//    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    _tick();
}

void GLWidget::paintGL()
{    
    if (_mouse_is_moving)
    {
        glMatrixMode   ( GL_PROJECTION );  // Select The Projection Matrix
        glLoadIdentity ( );                // Reset The Projection Matrix

        gluPerspective ( 60, ( float ) _width / ( float ) _height, 1.0, 50.0 );
        gluLookAt(0.0,  0.0, 2.0,           // eye
                  _eye_x,  _eye_y, 0.0,     // center
                  0.0,  1.0, 0.0);          // up

        std::cout << "paintGL: eye " << _eye_x << "," << _eye_y << std::endl;

    }

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer

    glMatrixMode   ( GL_MODELVIEW );  // Select The Model View Matrix
    glLoadIdentity();                                   // Reset The Current Modelview Matrix

    glPushMatrix();
    glTranslatef(-1.5f,0.0f,-6.0f);                     // Move Left 1.5 Units And Into The Screen 6.0
    glRotatef(angle_tri,0.0f,1.0f,0.0f);                // Rotate The Triangle On The Y axis
    glBegin(GL_TRIANGLES);                              // Drawing Using Triangles
        glColor3f(1.0f,0.0f,0.0f);          // Red
        glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Front)
        glColor3f(0.0f,1.0f,0.0f);          // Green
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Left Of Triangle (Front)
        glColor3f(0.0f,0.0f,1.0f);          // Blue
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Right Of Triangle (Front)

        glColor3f(1.0f,0.0f,0.0f);          // Red
        glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Right)
        glColor3f(0.0f,0.0f,1.0f);          // Blue
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Left Of Triangle (Right)
        glColor3f(0.0f,1.0f,0.0f);          // Green
        glVertex3f( 1.0f,-1.0f, -1.0f);         // Right Of Triangle (Right)

        glColor3f(1.0f,0.0f,0.0f);          // Red
        glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Back)
        glColor3f(0.0f,1.0f,0.0f);          // Green
        glVertex3f( 1.0f,-1.0f, -1.0f);         // Left Of Triangle (Back)
        glColor3f(0.0f,0.0f,1.0f);          // Blue
        glVertex3f(-1.0f,-1.0f, -1.0f);         // Right Of Triangle (Back)

        glColor3f(1.0f,0.0f,0.0f);          // Red
        glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Left)
        glColor3f(0.0f,0.0f,1.0f);          // Blue
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Left Of Triangle (Left)
        glColor3f(0.0f,1.0f,0.0f);          // Green
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Right Of Triangle (Left)
    glEnd();                                            // Finished Drawing The Triangle

    glLoadIdentity();                   // Reset The Current Modelview Matrix
    glTranslatef(1.5f,0.0f,-9.0f);              // Move Right 1.5 Units And Into The Screen 6.0
    glRotatef(angle_quad,1.0f,0.0f,0.0f);           // Rotate The Quad On The X axis
    glBegin(GL_QUADS);                                  // Draw A Quad
        glColor3f(0.0f,1.0f,0.0f);          // Set The Color To Green
        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Top)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Top)
        glVertex3f(-1.0f, 1.0f, 1.0f);          // Bottom Left Of The Quad (Top)
        glVertex3f( 1.0f, 1.0f, 1.0f);          // Bottom Right Of The Quad (Top)

        glColor3f(1.0f,0.5f,0.0f);          // Set The Color To Orange
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Top Right Of The Quad (Bottom)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Top Left Of The Quad (Bottom)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Bottom)
        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Bottom)

        glColor3f(1.0f,0.0f,0.0f);          // Set The Color To Red
        glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Front)
        glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Front)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Front)
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Front)

        glColor3f(1.0f,1.0f,0.0f);          // Set The Color To Yellow
        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Back)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Back)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Back)
        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Back)

        glColor3f(0.0f,0.0f,1.0f);          // Set The Color To Blue
        glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Left)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Left)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Left)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Left)

        glColor3f(1.0f,0.0f,1.0f);          // Set The Color To Violet
        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Right)
        glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Right)
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Right)
        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Right)
    glEnd();                                            // Done Drawing The Quad
    glPopMatrix();

    angle_tri += 3.2f;                      // Increase The Rotation Variable For The Triangle ( NEW )
    angle_quad -= 3.15f;                    // Decrease The Rotation Variable For The Quad     ( NEW )

}

void GLWidget::resizeGL( int w, int h)
{
    _width = w;
    _height = h;
    glViewport     ( 0, 0, w, h );
    glMatrixMode   ( GL_PROJECTION );  // Select The Projection Matrix
    glLoadIdentity ( );                // Reset The Projection Matrix
    if ( h==0 )  // Calculate The Aspect Ratio Of The Window
       gluPerspective ( 60, ( float ) w, 1.0, 50.0 );
    else
       gluPerspective ( 60, ( float ) w / ( float ) h, 1.0, 50.0 );

    gluLookAt(0.0,  0.0, 2.0,   // eye
              0.0,  0.0, 0.0,   // center
              0.0,  1.0, 0.0);  // up

    glMatrixMode   ( GL_MODELVIEW );  // Select The Model View Matrix
    glLoadIdentity ( );    // Reset The Model View Matrix
}

void GLWidget::mousePressEvent(QMouseEvent *event)
{
    std::cout << "mousePressEvent:" << std::endl;
    _mouse_is_moving = true;
}

void GLWidget::mouseReleaseEvent(QMouseEvent *event)
{
    std::cout << "mouseReleaseEvent:" << std::endl;
    _mouse_is_moving = false;
}

void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (_mouse_x == 0)
        _mouse_x = event->pos().x();

    if (_mouse_y == 0)
        _mouse_y = event->pos().y();

    std::cout << "mouseMoveEvent: " << event->pos().x() << "," << event->pos().y() << std::endl;

    if (event->pos().x() > _mouse_x)
    {
        _eye_x += 0.10;
    }
    else if (event->pos().x() < _mouse_x)
    {
        _eye_x -= 0.10;
    }

    if (event->pos().y() > _mouse_y)
    {
        _eye_y += 0.10;
    }
    else if (event->pos().y() < _mouse_y)
    {
        _eye_y -= 0.10;
    }

    _mouse_x = event->pos().x();
    _mouse_y = event->pos().y();
}

<强> GLWidget.h

#include <QGLWidget>

class GLWidget : public QGLWidget
{
    Q_OBJECT
public:
    explicit GLWidget(QWidget* parent = 0);
    virtual ~GLWidget();

    /* OpenGL initialization, viewport resizing, and painting */

    void initializeGL();

    void paintGL();

    void resizeGL( int width, int height);

    /* enable the user to interact directly with the scene using the mouse */

    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);    
    void mouseMoveEvent(QMouseEvent *event);

private:
    float angle_tri;            // Angle For The Triangle
    float angle_quad;           // Angle For The Quad
    float _eye_x;
    float _eye_y;
    bool _mouse_is_moving;
    int _mouse_x;
    int _mouse_y;
    int _width;
    int _height;

protected slots:
    void _tick();

};

<强>的main.cpp

#include <QApplication>
#include "glwidget.h"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    GLWidget gl_widget;
    gl_widget.show();

    return app.exec();
}

enter image description here

答案 1 :(得分:2)

我认为你所拥有的内容看起来大致正确,尽管你的glViewport参数看起来不对。 glViewport应该是(左,下,宽,高),但你正在使用别的东西。

将glViewport设置为glViewport(0,0,width,height);

更多解释:

通过modelViewProjection矩阵(和透视分割)进行变换后,所有坐标都位于所谓的标准化设备坐标(简称NDC)中。 NDC在每个轴上的范围从-1到1,它将(0,0,0)放在查看区域的中心。

当你的点直接位于相机前面时,它会在标准化的设备坐标中转换为xy(0,0)。

如果你看一下glViewport上的公式,这些将NDC映射到屏幕上的实际像素。

因此,如果您提供(0,0,1024,768)作为参数,则会将其映射为以下内容:

screen X = ( Xnd + 1 ) ( width / 2) + x;
screen Y = ( Ynd + 1 ) ( height / 2) + y;

替换我们的glViewport值:

screen X = ( 0 + 1 ) ( 1024 / 2) + 0;
screen Y = ( 0 + 1 ) ( 768  / 2) + 0;

screen X = ( 1 ) ( 1024 / 2) ;
screen Y = ( 1 ) ( 768  / 2) ;

screen X = ( 1 ) ( 512 ) ;
screen Y = ( 1 ) ( 384 ) ;

screen X =  512 ; //center of screen X
screen Y =  384 ; //center of screen Y

答案 2 :(得分:-1)

说实话,你的近似值非常大,通常这必须是一个较低的值,因此如果你有一个2D环境作为你的例子,你仍然可以渲染对象。我会说透视的近似值的0.1(0.5)应该很好。

注意:如果将近似值设置为一个大数字,则相机将截断几何体(透视平截头体)。