2

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.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335

3 Answers3

3

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!

enter image description here

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

enter image description here

karlphillip
  • 92,053
  • 36
  • 243
  • 426
2

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
Tim
  • 35,413
  • 11
  • 95
  • 121
  • Thanks! I didn't realize this, I meant to spell `glViewport(-w/2,-h/2,w,h);` so that {0,0} is in the center of the screen. However, fixing that doesn't help. – Violet Giraffe Sep 17 '12 at 19:37
  • You're misunderstanding the translation from NDC to screen space. Using (0,0,w,h) maps (0,0) in Normalized device coordinates (NDC) to the center of the screen. Using (0,0,w,h) puts objects directly in front of the camera in the center of the screen. Study the formulas on glViewport man page if you want to convince yourself of this. @VioletGiraffe – Tim Sep 17 '12 at 19:40
  • 1
    @VioletGiraffe You've put glLoadIdentity right **after** gluLookAt, probably don't want that :) – Tim Sep 17 '12 at 20:30
  • 1
    @VioletGiraffe I think you're also drawing your points as mostly black. glColor3i maps the largest possible integer value to 1.0, so 255 probably maps to something really really small. Try `glColor3f(1.0f, 1.0f, 1.0f);` – Tim Sep 17 '12 at 20:33
-1

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).

Cristina
  • 1,991
  • 3
  • 17
  • 24
  • There's nothing wrong with his near value, and the near plane value has nothing to do with a 2d or 3d scene. His nearest points are 2 units away from the camera, so that value should be fine. – Tim Sep 17 '12 at 19:29
  • 1
    No problem. You also have to be careful, because if you make your near plane value smaller than it needs to be, then you lose a lot of depth buffer precision, so it's not a good idea to just arbitrarily set it to some very small number unless you absolutely need to see objects that close to the camera. – Tim Sep 17 '12 at 19:33