问题描述
我想在我的OpenSceneGraph场景内的虚拟屏幕上显示Qt Quick内容。
我现在使用的方法效率很低:
- 使用FBO(FrameBufferObject)将Qt Quick渲染到屏幕外
- 使用QOpenGLFramebufferObject :: toImage()下载像素
- 将像素上传到OSG
因此是GPU-cpu-GPU传输。 Source code
适当的解决方案应该以某种方式利用现有的FBO,并能够仅在GPU内部传输数据。
存在两种选择:
- 在Qt端创建FBO,并在OSG端使用其纹理
- 在OSG端创建FBO,并将其馈送到Qt Quick渲染器
Qt部分正常。我对OSG完全迷失了。谁能为我提供一些指示?
解决方法
最后做到了。
总体思路:
-
使用FBO将QtQuick渲染为纹理-Internet上有一些examples。
-
在OpenSceneGraph中使用此纹理
整个过程包括几个技巧。
上下文共享
要执行某些图形操作,我们必须初始化OpenGL全局状态,也称为上下文。
创建纹理后,上下文将存储其ID。 id并不是全局唯一的,因此在另一个上下文中创建另一个纹理时,它可能会获得相同的id,但背后具有不同的资源。
如果仅将纹理的ID传递给另一个渲染器(在不同的上下文中操作),并期望它显示您的纹理,则最终将显示另一个纹理,黑屏或崩溃。
补救措施是上下文共享,这实际上意味着共享ID。
OpenSceneGraph和Qt抽象不兼容,因此您需要告诉OSG不要使用其自己的上下文抽象。通过调用setUpViewerAsEmbeddedInWindow
代码:
OsgWidget::OsgWidget(QWidget* parent,Qt::WindowFlags flags)
: QOpenGLWidget(parent,flags),m_osgViewer(new osgViewer::Viewer)
{
setFormat(defaultGraphicsSettings());
// ...
m_osgGraphicsContext = m_osgViewer->setUpViewerAsEmbeddedInWindow(x(),y(),width(),height());
}
// osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> m_osgGraphicsContext;
从现在开始,现有的QOpenGLContext实例将用作OSG渲染的OpenGL上下文。
您将需要为QtQuick渲染创建另一个上下文并将它们设置为共享:
void Widget::initializeGL()
{
QOpenGLContext* qmlGLContext = new QOpenGLContext(this);
// ...
qmlGLContext->setShareContext(context());
qmlGLContext->create();
}
请记住,一次只能有一个活动上下文。
您的方案是:
0. create osg::Texture out of QOpenGLFrameBufferObject::texture()
1. make QtQuick context active
2. render QtQuick to texture
3. make primary (OSG) context active
4. render OSG
5. goto 1
制作适当的osg :: Texture
由于OSG和Qt API不兼容,您几乎无法将QOpenGLFrameBufferObject
链接到osg::Texture2D
。
QOpenGLFrameBufferObject具有QOpenGLFrameBufferObject::texture()
方法,该方法返回opengl纹理ID,但是osg :: Texture自行管理所有openGL内容。
像osg::Texture2D(uint textureId);
这样的东西可以帮助我们,但根本不存在。
我们自己做一个。
osg::Texture
由osg::TextureObject
作为后盾,后者存储OpenGL纹理ID和其他一些数据。如果我们使用给定的纹理ID构造osg::TextureObject
并将其传递给osg::Texture
,后者将使用它作为自己的纹理。
代码:
void Widget::createOsgTextureFromId(osg::Texture2D* texture,int textureId)
{
osg::Texture::TextureObject* textureObject = new osg::Texture::TextureObject(texture,textureId,GL_TEXTURE_2D);
textureObject->setAllocated();
osg::State* state = m_osgGraphicsContext->getState();
texture->setTextureObject(state->getContextID(),textureObject);
}
完成演示项目here