【发布时间】:2020-12-20 11:43:04
【问题描述】:
目标
我想为 Qt3D 实现一个实际的小部件,因为 QWidget::createWindowContainer 不适合我。
问题描述
我让新类子类 QWidget 和 QSurface 的第一种方法不成功,因为 Qt3D 代码在 multiple places 中期望 QWindow 或 QOffscreenSurface 而我不想要重新编译整个 Qt3D 基础。
我的第二个想法是将 Qt3D 内容渲染到屏幕外表面,然后在 QOpenGLWidget 中的四边形上绘制纹理。当我使用QRenderCapture framegraph 节点将渲染的图像保存到屏幕外纹理,然后将图像加载到QOpenGLTexture 并在QOpenGLWidget 的paintGL 函数中绘制它时,我可以看到渲染的图像 - 即在 Qt3D 和 OpenGL 小部件中渲染工作正常。与直接从 Qt3D 渲染内容相比,这非常慢。
现在,当我在渲染QOpenGLWidget 期间使用GLuint 返回的GLuint 绑定纹理时,一切都保持黑色。
当然,如果 QOpenGLWidget 和 QT3D 的上下文是完全分开的,这将是有意义的。但是通过从QRenderAspectPrivate 中检索AbstractRenderer,我能够获得Qt3D 使用的上下文。在我的main.cpp 我设置了
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QOpenGLWidget 和 Qt3D 的上下文都引用了相同的共享上下文 - 我通过使用 qDebug 打印来验证这一点,它们是同一个对象。
这不应该让我使用 Qt3D 中的纹理吗?
或者关于如何实现这样一个小部件的任何其他建议?我只是认为这是最简单的方法。
实现细节/到目前为止我已经尝试过什么
这就是我的QOpenGLWidget 中的paintGL 函数的样子:
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 是附加到 QRenderTargetOutput/QRenderTarget 的 QTexture2D,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());
在QOpenGLWdiget 的resizeEvent 函数中,我为此纹理以及Qt3D 的所有屏幕外资源设置了适当的大小。这也只显示黑屏。绑定纹理后直接放置qDebug() << glGetError();每次只会显示0,所以我假设没有任何错误。
代码可以在here in my GitHub project找到。
【问题讨论】:
-
我用这个开发了相当大的 QML/Qt3D 应用程序:这对你有用吗? ` #include
#include int main(int argc, char* argv[]) { QApplication app(argc, argv); QQmlApplicationEngine 引擎; engine.load(QUrl(QStringLiteral("qrc:/res/main.qml")));返回 app.exec(); } 导入 QtQuick 2.8 导入 QtQuick.Controls 2.3 导入 QtQuick.Scene3D 2.0 ApplicationWindow { Scene3D { } }` -
感谢您的评论。你是对的,实际上我已经在考虑切换到 QML,但我的应用程序的其余部分 (the one that I'm actually developing) 不在 QML 中,所以我必须适应很多 - 我认为实现 Qt3D 小部件不需要这么久。另外,我需要 3D 小部件可以通过鼠标移动(类似于在 MS Paint 中拖动一个正方形,我希望你明白我的意思)。
-
混合模式应用听起来可行。不过,我的大部分代码都是用 C++ 编写的。但是 QML 部分简化了很多事情。
-
doc.qt.io/archives/qt-5.5/qt3d-qwindow.html 怎么样,但提供的信息不多。
-
关于窗口的事情是它实现了
QSurface(因为QWindow实现了并且Qt3DWindow是一个子类)。现在,我考虑了子类化QWidget和QSurface并将表面传递给Qt3D 的QRenderSurfaceSelector,但我实际上并不知道如何实现它(例如返回QPlatformSurface *的函数)并且Qt3D 内部期望一个QWindow或QOffscreenSurface,即我将不得不修改很多 Qt3D 代码,这使得它变得不可行。
标签: c++ qt opengl qt3d openglcontext