使用QOpenGLWidget

时间:2016-02-09 23:03:37

标签: c++ qt opengl

我正在为QOpenGLWidget内的3D对象实现一个简单的点击选择。为此,我需要将2D鼠标坐标转换为3D世界空间。我之前使用QGLWidget实现了整个过程。使用QOpenGLWidget,我无法读取像素的GL_DEPTH_COMPONENT:

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

' Z'总是0。 为了确保我的像素坐标正确,我尝试接收GL_RGBA值:

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

,返回正确的像素颜色。 为了使其工作,我不得不将像素坐标的域从局部坐标更改为父坐标。这可能是因为GL_VIEWPORT设置为对应于父窗口小部件的大小:

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

对于QGLWidget,它返回:{0, 0, this->width(), this->height()}

对于QOpenGLWidget,它返回:{0, 0, this->parent()->width(), this->parent()->height()}

顺便说一下,我的OpenGL版本是4.5,使用glReadPixels和GL_DEPTH_COMPONENT我没有得到任何OpenGL错误

现在,我对自己可能缺少的东西毫无头绪。有什么想法吗?

1 个答案:

答案 0 :(得分:4)

QOpenGLWidget可用于底层FBO,如果启用了多次采样,则无法从该FBO中读取深度分量。最简单的解决方案是将样本设置为零,因此您的代码将如下所示:

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

format.setSamples(0);

QSurfaceFormat::setDefaultFormat(format);

或者您可以使用format.setSamples(4)之类的多重采样,但是如果没有可以复制深度缓冲区的多重采样,则需要额外的FBO。

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

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