C++ 将QGLWdiget内容绘制到FBO
我有一个QGraphicscene+QGraphicsView设置,它使用QGLWidget来绘制内容 我还制作了一些片段着色器,以向场景添加置换贴图和bloom效果。如果我使用QFramebufferObject作为设备创建QPaint对象,并在QPaint对象上调用图形场景的渲染功能,场景将渲染到FBO,然后我可以使用它进行合成。但是,它的缺点是使用软件渲染,并且会占用大量资源 不幸的是,当我尝试将一个FBO设置为当前渲染目标,并将QGLWidget留在FBO上绘制时,FBO显示为空白,我所说的空白是指glClearColor调用的颜色 所以我的问题是,有没有一种方法可以在FBO上获取QGLWidget的内容,或者有没有其他方法可以在QGLWidget中实现后期处理着色器 以下是我当前代码的相关部分C++ 将QGLWdiget内容绘制到FBO,c++,qt,opengl,fbo,C++,Qt,Opengl,Fbo,我有一个QGraphicscene+QGraphicsView设置,它使用QGLWidget来绘制内容 我还制作了一些片段着色器,以向场景添加置换贴图和bloom效果。如果我使用QFramebufferObject作为设备创建QPaint对象,并在QPaint对象上调用图形场景的渲染功能,场景将渲染到FBO,然后我可以使用它进行合成。但是,它的缺点是使用软件渲染,并且会占用大量资源 不幸的是,当我尝试将一个FBO设置为当前渲染目标,并将QGLWidget留在FBO上绘制时,FBO显示为空白,我所
void MyWindow::SwitchRenderContext(RenderType type)
{
m_renderType = type;
m_renderArea->SetRenderType(type);
switch(type)
{
case RenderType_Software:
m_view.setViewport(NULL);
layout()->removeWidget(&m_view);
layout()->addWidget(m_renderArea);
m_view.m_renderWidget = NULL;
break;
case RenderType_OpenGL:
m_view.setViewport(m_renderArea);
m_view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
layout()->addWidget(m_renderArea);
m_view.m_renderWidget = m_renderArea;
break;
}
}
void MyGlWidget::initializeGL()
{
m_initialized = true;
if(m_dispFbo == NULL)
m_dispFbo = new QGLFramebufferObject(width(), height());
if(m_bufFbo == NULL)
m_bufFbo = new QGLFramebufferObject(width(), height());
if(m_fbo == NULL)
m_fbo = new QGLFramebufferObject(width(), height());
static const float vertex[] = {
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
};
//initialize vbo
if(!m_vbo.isCreated())
{
m_vboEnabled = m_vbo.create();
if(m_vboEnabled)
{
m_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo.bind();
m_vbo.allocate(vertex, sizeof(vertex) );
m_vbo.release();
}
glEnable(GL_TEXTURE_2D);
}
glViewport(0, 0, width(), height());
m_shadersEnabled = initializeShaders();
}
void MyGlWidget::SetRenderType(RenderType type)
{
m_renderType = type;
}
void MyGlWidget::DoHardwarePaint()
{
m_fbo->release();
QPainter dispPainter(m_dispFbo);
m_dispScene->RenderScene(&dispPainter);
dispPainter.end();
DrawShaders();
m_fbo->bind();
}
void MyGlWidget::DoSoftwarePaint()
{
if(!m_shadersEnabled || !m_vboEnabled)
{
QPainter painter(this);
m_scene->render(&painter);
return;
}
QPainter dispPainter(m_dispFbo);
m_dispScene->RenderScene(&dispPainter);
dispPainter.end();
QPainter painter(m_fbo);
m_scene->render(&painter);
painter.end();
DrawShaders();
update();
}
void MyGlWidget::DrawShaders()
{
m_vbo.bind();
m_bufFbo->bind();
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_dispFbo->texture());
m_displaceShader.bind();
m_displaceShader.enableAttributeArray("in_verts");
m_displaceShader.setAttributeBuffer( "in_verts", GL_FLOAT, 0, 4);
m_displaceShader.setUniformValue("inCol", 0);
m_displaceShader.setUniformValue("inDisplace", 1);
glDrawArrays(GL_TRIANGLES, 0, m_vbo.size());
m_bufFbo->release();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_bufFbo->texture());
m_bloomShader.bind();
m_bloomShader.enableAttributeArray("in_verts");
m_bloomShader.setAttributeBuffer( "in_verts", GL_FLOAT, 0, 4);
m_bloomShader.setUniformValue("inCol", 0);
m_bloomShader.setUniformValueArray("offsets", offsets, 8, 2);
glDrawArrays(GL_TRIANGLES, 0, m_vbo.size());
m_bloomShader.disableAttributeArray("in_verts");
m_bloomShader.release();
m_vbo.release();
glEnable(GL_DEPTH_TEST);
}
void MyGlWidget::paintGL()
{
if(!m_vboEnabled && m_renderType == RenderType_OpenGL)
return;
if(m_renderType == RenderType_Software)
{
DoSoftwarePaint();
return;
}
DoHardwarePaint();
}
我不确定这是否与QGLWidget本身有关。如果它实际上与使用QGLWidget有关,那么我能想到的唯一一件事就是Qt切换绑定的方式。当绘制一个GL上下文时,渲染上下文一次只能绑定到一个线程,因此如果QGLWidget定义了自己的上下文,麻烦就会接踵而至。解决这个问题的基本方法是实现上下文共享。您能详细介绍一下QGLWidget设置吗?感谢您的评论,这确实是因为QPaint为渲染场景而创建的视图在内部重置了状态,以便在绘制之前绑定当前活动显示的默认帧缓冲区,而不是绕过此问题,我发现了为什么QPainter在绘制QGLFramebufferObject时使用软件渲染,显然,如果在创建对象时没有将CombinedDephsTencil作为附件传递,就会发生这种情况。它的工作正如预期的那样,现在不再占用CPU了,谢谢你的提示。