c++ - 在 OpenGL 中使用 Qt3D 离屏渲染纹理

标签 c++ qt opengl qt3d openglcontext

目标
我想为 Qt3D 实现一个实际的小部件,因为 QWidget::createWindowContainer只是不适合我。

问题描述
我让新类子类的第一种方法QWidgetQSurface没有成功,因为 Qt3D 代码要么期望 QWindowQOffscreenSurfacemultiple places而且我不想重新编译整个 Qt3D 基础。
我的第二个想法是将 Qt3D 内容渲染到屏幕外表面,然后在 QOpenGLWidget 中的四边形上绘制纹理。 .当我使用 QRenderCapture framegraph 节点将渲染的图像保存到屏幕外纹理,然后将图像加载到 QOpenGLTexture并将其绘制到 QOpenGLWidgetpaintGL函数我可以看到渲染的图像 - 即在 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_colorTextureQTexture2D附加到 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/

相关文章:

c++ - C++ ABI如何处理RVO和NRVO?

c++ - 堆栈/堆中的 vector 元素?长输入,C++

c++ - 在 Qt 饼图中显示百分比?

c++ - openGL - 调用 glMatrixMode(...) 时出现访问冲突

c++ - 析构函数可以在 const 对象上调用非常量函数吗?

c++ - 没有对 std::index_sequence 中的包扩展进行诊断

c++ - 在增量凸包 3D 期间获取点的地平线

c++ - 如何从 QT C++ 中的对话框将 key 发送到父 mainWindow

c - 在 C 中进行简单绘图和事件捕获的最简单方法是什么?

c++ - 删除 OpenGL 中的嵌套显示列表