1

I'm trying to develop an application using OpenGL 4.0 and Qt 5.3 and I want to implement color picking to select different models in a QGLWidget. So basically, when I detect a mouse click, I:

  1. Get the position of the mouse
  2. Render the scene
    1. Set a white background (glClearColor then glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    2. I bind my shader program
    3. I draw my models (each one with a different color and its own transformation matrix)
    4. Release my shader program
  3. Call glFlush and glFinish to make sure I have finished rendering before calling glReadPixels
  4. Call glReadPixels(mouse.x, window_height - mouse.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data) data being a GLubyte array of length 4

My program runs "well" but when I want to select an object, I have to click a little more up and right than where the model really is. I tried to swap buffers to check if the models are rendered at the right position and yes, they are... I also tried to call glPixelStorei(GL_PACK_ALIGNMENT, x) with x = 1, 2, 4, 8 before glReadPixels but it doesn't seem to affect it.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Gpack
  • 1,878
  • 3
  • 18
  • 45
  • 1
    Don't do "glFlush and glFinish" as the OpenGL will finish all the commands before you download the data . – Michael IV Nov 05 '14 at 10:37
  • 1
    off by one error? `window_height - mouse.y - 1` because `window_height` is outside the window. Could also be an issue with QTs mouse origin (e.g. you're getting it in relation to a parent element). Try printing the coordinates and try to click at `0, 0`. – jozxyqk Nov 05 '14 at 11:06

2 Answers2

0

Thanks for your comments Michael IV and jozxyqk. In the end I just ended up drawing in a QOpenGLFramebufferObject and I read the pixels color using a QImage. Like this:

QImage image = fbo->toImage(); //fbo is the QOpenGLFramebufferObject
QRgb rgb = image.pixel(mouse.x(), mouse.y());

For more information, see: http://dangelog.wordpress.com/2013/02/10/using-fbos-instead-of-pbuffers-in-qt-5-2/

Happy coding!

Gpack
  • 1,878
  • 3
  • 18
  • 45
0

It's a bit late... 6 years late, but I had the same problem using a QOpenGLWidget. I found that glReadPixels is covering the entire window (or maybe just the "central widget"), not the OpenGL widget. If creating a new FBO is not an option you can use the window offsets to get the correct results:

void MyOpenGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (!parentWidget()) //This widget needs to belong to a window or another widget
        return;

    QPointF wpos = event->windowPos();

    GLfloat color[4];
    //Note: If a menu or status bar is present the height of the bar(s) needs
    //      to be included in the y calc because the parentWidget is the "centralwidget",
    //      not the window.
    glReadPixels(wpos.x(), parentWidget()->height() - wpos.y(), 1, 1, GL_RGBA, GL_FLOAT, color); 

    QString msg = QString("%1 %2 %3 %4").arg(color[0]).arg(color[1]).arg(color[2]).arg(color[3]);
    qDebug() << "Clicked on pixel " << event->x() << ", " << event->y() << ", color " << msg;
}

Unfortunately, I cannot find documentation that supports this fact, but the returned colors now align with what is expected (no more offset).

atomSmasher
  • 1,465
  • 2
  • 15
  • 37