目标
我想为 Qt3D 实现一个实际的小部件,因为 QWidget::createWindowContainer
只是不适合我。
问题描述
我让新类子类的第一种方法QWidget
和 QSurface
没有成功,因为 Qt3D 代码要么期望 QWindow
或 QOffscreenSurface
在 multiple places而且我不想重新编译整个 Qt3D 基础。
我的第二个想法是将 Qt3D 内容渲染到屏幕外表面,然后在 QOpenGLWidget
中的四边形上绘制纹理。 .当我使用 QRenderCapture
framegraph 节点将渲染的图像保存到屏幕外纹理,然后将图像加载到 QOpenGLTexture
并将其绘制到 QOpenGLWidget
的paintGL
函数我可以看到渲染的图像 - 即在 Qt3D 和 OpenGL 小部件中渲染可以正常工作 .与直接从 Qt3D 渲染内容相比,这非常慢。
现在,当我使用 GLuint
由 QTexutre2D
返回在 QOpenGLWidget
的渲染期间绑定(bind)纹理,一切都保持黑色。
当然,如果 QOpenGLWidget
的上下文是有道理的和 QT3D 是完全分开的。但是通过检索 AbstractRenderer
来自 QRenderAspectPrivate
我能够获得 Qt3D 使用的上下文。在我的 main.cpp
我设置
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QOpenGLWidget
的上下文和 Qt3D 都引用了相同的共享上下文 - 我通过使用 qDebug
打印两者来验证这一点,它们是同一个对象。这不应该允许我使用 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
Qt3D 将场景渲染到屏幕外。我有一个
QFrameAction
用于触发 QOpenGLWidget
上的绘制更新:connect(d->m_frameAction, &Qt3DLogic::QFrameAction::triggered, this, &Qt3DWidget::paintGL);
我已经验证这确实调用了 paintGL
功能。所以每次我画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
的功能我在这个纹理以及 Qt3D 的所有屏幕外资源上设置了适当的大小。这也只显示黑屏。配售qDebug() << glGetError();
绑定(bind)纹理后直接显示0
每次,所以我假设没有任何错误。代码可以找到here in my GitHub project .
最佳答案
更新 (2021 年 5 月 10 日,因为我再次偶然发现了我的答案):
我的 Qt3DWidget implementation现在完美运行,问题是我不得不调用 update()
当触发框架 Action 而不是 paintGL
(呃,愚蠢的我,我实际上知道)。
虽然我没有找到问题的确切解决方案,但我会在这里发布答案,因为我成功创建了 Qt3D 小部件。
代码可以找到here .这不是最干净的解决方案,因为我认为应该可以以某种方式使用共享纹理。相反,现在我设置 QOpenGLWidget
我必须使用 Qt3D 的私有(private)类的 Qt3D 的上下文。这意味着 Qt3D 直接绘制到由 OpenGL 小部件绑定(bind)的帧缓冲区上。不幸的是,现在小部件必须是渲染驱动程序并在 QAspectEngine
上执行手动更新。调用 processFrame
.理想情况下,我希望将所有处理循环留给 Qt3D,但至少小部件现在可以正常工作。
编辑:
我找到了 QSharedGLTexture
的示例在手动测试中here .它以相反的方式工作,即OpenGL渲染到纹理并且Qt3D使用它,所以我认为应该可以反转方向。不幸的是,QSharedGLTexture
似乎有点不稳定,因为调整 OpenGL 窗口的大小有时会使应用程序崩溃。这就是为什么我现在会坚持我的解决方案。但是,如果有人有关于此问题的消息,请随时发布答案!
关于c++ - 在 OpenGL 中使用 Qt3D 离屏渲染纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63686309/