场景图 - QML 下的 Vulkan

展示了如何在 Qt Quick 场景下直接使用 Vulkan 进行渲染。

注意:编译此示例需要 SDK。有关要安装内容的详细信息,请参阅Vulkan 集成

概述

此示例使用QQuickWindow::beforeRendering() 和QQuickWindow::beforeRenderPassRecording() 信号,在 Qt Quick 场景下绘制自定义 Vulkan 内容。QML 用于渲染顶部的文本标签。

在大多数方式上,此示例与OpenGL Under QMLDirect3D 11 Under QMLMetal Under QML 示例等价,它们都渲染相同自定义内容,只是通过不同的本地 API。

此文档将涵盖 QML 的具体使用,而不会深入到自定义 Vulkan 渲染的细节。

从 QML 影响Vulkan渲染

此示例展示了如何使用暴露给 QML 的值来控制 Vulkan 渲染。

要将在 VulkanSquircle 的定义中暴露给 QML 的阈值值 t,我们使用 Q_OBJECTQ_PROPERTYQML_ELEMENT

class VulkanSquircle : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
    QML_ELEMENT

然后我们声明公共和私有项

public:
    VulkanSquircle();

    qreal t() const { return m_t; }
    void setT(qreal t);

signals:
    void tChanged();

public slots:
    void sync();
    void cleanup();

private slots:
    void handleWindowChanged(QQuickWindow *win);

private:
    void releaseResources() override;

    qreal m_t = 0;
    SquircleRenderer *m_renderer = nullptr;

然后,在 main.qml 中,我们使用NumberAnimation 动画阈值值。

    VulkanSquircle {
        SequentialAnimation on t {
            NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
            NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
            loops: Animation.Infinite

t 变量最终用于绘制 squircles 的 SPIR-V 着色器程序。

使用信号渲染自定义Vulkan内容

使用QQuickWindow::beforeRendering() 和QQuickWindow::beforeRenderPassRecording() 信号。

QQuickWindow::beforeRendering() 信号在每个帧的开始时发射,在场景图开始渲染之前。这意味着对响应此信号所发出的任何 Vulkan 绘制调用,将堆叠在 Qt Quick 项之下。有两个信号,因为自定义 Vulkan 命令被记录在场景图使用的相同命令缓冲区上。

仅仅使用 beforeRendering() 函数是不够的,因为它在帧的开始时发射,在记录 renderpass 实例的开始之前使用vkCmdBeginRenderPass

解决方案:通过连接到 beforeRenderPassRecording(),应用程序的自身命令和场景图的框架将最终以正确的顺序结束。

通过 sync() 函数连接信号

void VulkanSquircle::sync()
{
    if (!m_renderer) {
        m_renderer = new SquircleRenderer;
        // Initializing resources is done before starting to record the
        // renderpass, regardless of wanting an underlay or overlay.
        connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection);
        // Here we want an underlay and therefore connect to
        // beforeRenderPassRecording. Changing to afterRenderPassRecording
        // would render the squircle on top (overlay).
        connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection);
    }
    m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
    m_renderer->setT(m_t);

您还可以通过连接到QQuickWindow::afterRendering() 和 QQuickWindow::afterRenderPassRecording() 信号来在 Qt Quick 场景上渲染 Vulkan 内容。

示例项目 @ code.qt.io

© 2024 Qt 公司。本文件中的文档贡献归其各自的版权所有者所有。本提供的文档是根据自由软件基金会发布的GNU 自由文档许可协议版本 1.3许可的。Qt 和相应的商标是芬兰 Qt 公司的商标,也是全球其他国家的商标。所有其他商标均为其各自所有者的财产。