简体   繁体   English

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

[英]Understanding GL coordinates - setting perspective and using gluLookAt

I'm using QGlWidget to draw a couple of points. 我正在使用QGlWidget绘制几个点。 The problems I'm having is that I seem to fail to set up the perspective properly and establish correct view on the points. 我遇到的问题是我似乎无法正确设置视角并在点上建立正确的视图。 I must be misunderstanding the coordinates somewhere or doing something else stupid, but after reading a bunch of guides and tutotrials I'm still stuck. 我一定是误解了某个地方的坐标或做了别的蠢事,但在看了一堆导游和tutotrials之后我仍然被卡住了。 The screen is black, no points. 屏幕是黑色的,没有分数。 Here's the code: 这是代码:

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

I've tried manipulating z coordinate of the "eye" in gluLookAt to no avail, so I must be getting something else wrong. 我试过在gluLookAt中操纵“眼睛”的z坐标无济于事,所以我必须得到别的错误。

To develop a more clear understanding of how gluPerspective() and gluLookAt() works, I recommend playing with the tutorials from Nate Robins , more specifically the projection demo. 为了更清楚地了解gluPerspective()gluLookAt()工作,我建议使用Nate Robins的教程,更具体地说是投影演示。

Trust me, this is the droid you are looking for ! 相信我, 这是你正在寻找的机器人

在此输入图像描述

Anyway, a few days ago I wrote a spiced up version of Nehe lesson 5 (3D Shapes) in Qt: 无论如何,几天前我在Qt写了一篇加剧版的Nehe第5课(3D Shapes)

GLWidget.cpp : 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 : 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 : 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();
}

在此输入图像描述

I think what you've got there looks mostly correct, though your glViewport parameters look wrong. 虽然你的glViewport参数看起来不对,但我认为你所拥有的内容看起来大致正确。 glViewport is supposed to be (left, bottom, width, height), but you're using something else. glViewport应该是(左,底,宽,高),但你正在使用别的东西。

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

For more explanation: 有关更多说明:

After transformation by modelViewProjection matrix (and perspective divide), all coordinates lie in what's known as Normalized Device Coordinates (abbreviated as NDC). 在通过modelViewProjection矩阵(和透视分割)进行变换之后,所有坐标都位于所谓的标准化设备坐标(缩写为NDC)中。 NDC ranges from -1 to 1 on each axis, which puts (0,0,0) right in the center of the viewing region. NDC在每个轴上的范围从-1到1,它将(0,0,0)放在查看区域的中心。

When your point lies directly in front of the camera, this gets transformed to xy (0,0) in normalized device coordinates. 当您的点直接位于摄像机前方时,会在标准化设备坐标中转换为xy(0,0)。

If you look at the formulas on glViewport, these map NDC to the actual pixels on the screen. 如果你看一下glViewport上的公式,这些将NDC映射到屏幕上的实际像素。

So if you supply (0,0,1024,768) as the parameters, it gets mapped as the following: 因此,如果您提供(0,0,1024,768)作为参数,它将被映射为以下内容:

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

Substituting our glViewport values: 替换我们的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

Your near value is quite large to be honest, usually this has to be a low value so that if you have a 2D environment as your example you can still render objects. 实际上,您的近似值非常大,通常这必须是一个较低的值,因此如果您以2D环境为例,您仍然可以渲染对象。 I would say a 0.1(0.5) for the near value of the perspective should go nicely. 我会说透视的近似值0.1(0.5)应该很好。

Note: If you set the near value to be a big number your geometry will be clipped by the camera (perspective frustum). 注意:如果将近值设置为大数字,则几何体将被相机剪切(透视平截头体)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM