简体   繁体   中英

Understanding GL coordinates - setting perspective and using gluLookAt

I'm using QGlWidget to draw a couple of points. 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. 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.

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.

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:

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

在此输入图像描述

I think what you've got there looks mostly correct, though your glViewport parameters look wrong. glViewport is supposed to be (left, bottom, width, height), but you're using something else.

Set glViewport to 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). NDC ranges from -1 to 1 on each axis, which puts (0,0,0) right in the center of the viewing region.

When your point lies directly in front of the camera, this gets transformed to xy (0,0) in normalized device coordinates.

If you look at the formulas on glViewport, these map NDC to the actual pixels on the screen.

So if you supply (0,0,1024,768) as the parameters, it gets mapped as the following:

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

Substituting our glViewport values:

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. I would say a 0.1(0.5) for the near value of the perspective should go nicely.

Note: If you set the near value to be a big number your geometry will be clipped by the camera (perspective frustum).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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