我正在为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错误
现在,我对自己可能缺少的东西毫无头绪。有什么想法吗?
答案 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();
}
};