我正在为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);
Run Code Online (Sandbox Code Playgroud)
“ 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);
Run Code Online (Sandbox Code Playgroud)
,它返回正确的像素颜色。为了使它起作用,我不得不将像素坐标的域从局部坐标更改为父坐标。这可能是由于GL_VIEWPORT设置为与父窗口小部件尺寸相对应的事实造成的:
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
Run Code Online (Sandbox Code Playgroud)
对于QGLWidget,它返回: {0, 0, this->width(), this->height()}
对于QOpenGLWidget,它返回: {0, 0, this->parent()->width(), this->parent()->height()}
顺便说一句,我的OpenGL版本是4.5,使用带有GL_DEPTH_COMPONENT的glReadPixels我没有任何OpenGL错误
现在,我对可能会丢失的东西一无所知。有任何想法吗?
小智 5
QOpenGLWidget可以在基础帧缓冲区对象(FBO)中使用,如果启用了多重采样,则不能简单地从该FBO中读取深度分量。最简单的解决方案是将样本设置为零,因此您的代码将如下所示:
QSurfaceFormat format;
format.setVersion(2, 1);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(0);
QSurfaceFormat::setDefaultFormat(format);
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用诸如format.setSamples(4)之类的多重采样,但是需要额外的FBO,而无需多重采样即可复制深度缓冲区。
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();
}
};
Run Code Online (Sandbox Code Playgroud)