[英]Use Qt3D offscreen-rendered texture in OpenGL
我想为 Qt3D 实现一个实际的小部件,因为QWidget::createWindowContainer
不适合我。
我让新的 class 子类QWidget
和QSurface
的第一种方法没有成功,因为 Qt3D 代码在多个地方需要QWindow
或QOffscreenSurface
,而且我不想重新编译整个 Qt3D 基础。
我的第二个想法是将 Qt3D 内容渲染到屏幕外表面,然后在QOpenGLWidget
中的四边形上绘制纹理。 当我使用QRenderCapture
framegraph 节点将渲染的图像保存到屏幕外纹理,然后将图像加载到QOpenGLTexture
并在QOpenGLWidget
的paintGL
function 中绘制时,我可以看到渲染图像 -即在 Qt3D 和 OpenGL 中渲染小部件工作正常。 与直接从 Qt3D 渲染内容相比,这非常慢。
现在,当我在QOpenGLWidget
渲染期间使用QTexutre2D
返回的GLuint
绑定纹理时,一切都保持黑色。
当然,如果QOpenGLWidget
和 QT3D 的上下文是完全独立的,那么这是有道理的。 但是通过从QRenderAspectPrivate
中检索AbstractRenderer
,我能够获得 Qt3D 使用的上下文。 在我的main.cpp
中,我设置了
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QOpenGLWidget
和 Qt3D 的上下文都引用相同的共享上下文 - 我通过使用qDebug
打印两者来验证这一点,它们是相同的 object。
这不应该允许我使用 Qt3D 的纹理吗?
或者关于如何实现这样一个小部件的任何其他建议? 我只是认为这是最简单的方法。
这就是我的paintGL
中的QOpenGLWidget
的样子:
glClearColor(1.0, 1.0, 1.0, 1.0);
glDisable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d->m_shaderProgram->bind();
{
QMatrix4x4 m;
m.ortho(0, 1, 1, 0, 1.0f, 3.0f);
m.translate(0.0f, 0.0f, -2.0f);
QOpenGLVertexArrayObject::Binder vaoBinder(&d->m_vao);
d->m_shaderProgram->setUniformValue("matrix", m);
glBindTexture(GL_TEXTURE_2D, d->m_colorTexture->handle().toUInt());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
d->m_shaderProgram->release();
m_colorTexture
是附加到QTexture2D
在屏幕外渲染场景的QRenderTargetOutput
/ QRenderTarget
的 QTexture2D。
我有一个QFrameAction
来触发QOpenGLWidget
上的绘图更新:
connect(d->m_frameAction, &Qt3DLogic::QFrameAction::triggered, this, &Qt3DWidget::paintGL);
我已经验证这确实调用了paintGL
function。所以每次我绘制QOpenGLWidget
时,框架应该准备好并出现在纹理中。
我还尝试用m_colorTexture
替换QSharedGLTexture
。 然后我像这样用QOpenGLWidget
的上下文创建了这个纹理
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
// w and h are width and height of the widget
m_texture->setSize(w, h);
// m_colorTexture is the QSharedGLTexture
m_colorTexture->setTextureId(m_texture->textureId());
在resizeEvent
的QOpenGLWdiget
function 中,我在此纹理上以及 Qt3D 的所有屏幕外资源上设置了适当的大小。 这也只显示黑屏。 放置qDebug() << glGetError();
绑定纹理后直接每次都显示0
,所以我假设没有任何错误。
代码可以在我的 GitHub 项目中找到。
更新(2021 年 5 月 10 日,因为我再次偶然发现了我的答案):
我的Qt3DWidget 实现现在可以完美运行,问题是当框架动作被触发时我不得不调用update()
而不是paintGL
(呃,我真傻,我真的知道)。
虽然我没有找到我的问题的确切解决方案,但我会在这里发布一个答案,因为我成功创建了一个 Qt3D 小部件。
可以在此处找到代码。 这不是最干净的解决方案,因为我认为应该可以以某种方式使用共享纹理。 相反,现在我在 Qt3D 上设置QOpenGLWidget
的上下文,为此我必须使用 Qt3D 的私有类。 这意味着 Qt3D 直接绘制到由 OpenGL 小部件绑定的帧缓冲区上。 不幸的是,现在小部件必须是渲染驱动程序并通过调用processFrame
在QAspectEngine
上执行手动更新。 理想情况下,我希望将所有处理循环留给 Qt3D,但至少小部件现在可以正常工作。
编辑:
我在 此处的手动测试中找到了QSharedGLTexture
的示例。 它以相反的方式工作,即 OpenGL 渲染到纹理并且 Qt3D 使用它所以我认为应该可以反转方向。 不幸的是, QSharedGLTexture
似乎有点不稳定,因为调整 OpenGL window 有时会使应用程序崩溃。 这就是为什么我现在会坚持我的解决方案。 但是,如果有人有关于此问题的消息,请随时发布答案!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.