简体   繁体   中英

Cannot read GL_DEPTH_COMPONENT using QOpenGLWidget

I am implementing a simple click selection for 3D objects inside a QOpenGLWidget. To do this I need to transform 2D mouse coordinates into 3D worldspace. I had previously implemented the whole thing using QGLWidget. Using QOpenGLWidget, I am not able to read the GL_DEPTH_COMPONENT of a pixel:

float z;
glReadPixels(pixel.x, height - pixel.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);

'z' is always 0. To make sure my pixel coordinates were correct I tried receiving GL_RGBA values:

float rgba[4];
glReadPixels((int)p_temp.x(), (int) (viewport[3] - p_temp.y()), 1, 1, GL_RGBA, GL_FLOAT, rgba);

, which returns the correct pixel Colors. In order for this to work I had to change the domain of the pixel coordinates from local to parent coordinates. This probably results from the fact that the GL_VIEWPORT is set corresponding to the parent widgets size:

int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

for QGLWidget this returns: {0, 0, this->width(), this->height()}

for QOpenGLWidget this returns: {0, 0, this->parent()->width(), this->parent()->height()}

BTW, my OpenGL version is 4.5 and I do not get any OpenGL error using glReadPixels with GL_DEPTH_COMPONENT

Now, I am kind of clueless as to what I might be missing. Any ideas?

QOpenGLWidget works into an underlying Framebuffer Object (FBO) and you can't simply read the depth component from that FBO if multi sampling is enabled. The easiest solution is to set the samples to zero, so your code will look like this:

QSurfaceFormat format;
format.setVersion(2, 1);
format.setProfile(QSurfaceFormat::CoreProfile);

format.setSamples(0);

QSurfaceFormat::setDefaultFormat(format);

Or you can use multisampling like format.setSamples(4), but an additional FBO will be required without multisampling where the depth buffer can be copied.

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
//
// OTHER WIDGET RELATED STUFF
//
QOpenGLFramebufferObject *mFBO=nullptr;

MyGLWidget::paintGL()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  //
  // DRAW YOUR SCENE HERE!
  //

  QOpenGLContext *ctx = QOpenGLContext::currentContext();

  // FBO must be re-created! is there a way to reset it?
  if(mFBO) delete mFBO;

  QOpenGLFramebufferObjectFormat format;
  format.setSamples(0);
  format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
  mFBO = new QOpenGLFramebufferObject(size(), format);

  glBindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebufferObject());
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO->handle());
  ctx->extraFunctions()->glBlitFramebuffer(0, 0, width(), height(), 0, 0, mFBO->width(), mFBO->height(), GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT, GL_NEAREST);

  mFBO->bind(); // must rebind, otherwise it won't work!

  float mouseDepth = 1.f;
  glReadPixels(mouseX, mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseDepth);

  mFBO->release();
}
};

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