Qt 3D: 线条框架 QML 示例

一个实现单遍线条框架渲染方法的 Qt 3D QML 应用程序。

Qt 3D 线条框架渲染 展示了如何使用自定义着色器集使用单遍线条框架渲染方法绘制单一实体(一个三叶结)。

运行该示例

要运行示例,请从 Qt Creator 中打开 欢迎模式 并从 示例 中选择示例。有关更多信息,请访问 构建和运行示例

创建实体

渲染器方面寻找具有某些几何形状、材质(可选)以及变换(可选)的实体。这些全部通过以下形式指定:子类化 QComponent 并作为 MeshMaterialTransform 发送到 QML 引擎。我们使用这些组件在 TrefoilKnot.qml 中创建自定义 QML 项目。

我们首先导入 Qt3D 2.0 模块,该模块提供了 Entity 类型以及如 Qt.vector3d() 的值类型助手。我们还导入了 Qt3D.Renderer 模块,该模块提供了渲染器方面选择的所有组件和其他类型

import Qt3D.Core 2.0
import Qt3D.Render 2.0

要使用其他方面的组件,我们还需要导入相应的 QML 模块。

我们然后使用 Entity 类型作为自定义 QML 类型的根元素,并暴露一些自定义属性,正如在 QML 中的任何其他类型一样

Entity {
    id: root

    property real x: 0.0
    property real y: 0.0
    property real z: 0.0
    property real scale: 1.0
    property real theta: 0.0
    property real phi: 0.0
    property Material material

除了聚合组件,Entity 类型还可以用来分组子对象,这与在 Qt Quick 2 中使用 Item 类型相似。

指定变换

我们实例化一个 Transform 组件和一个 Mesh 组件。Transform 组件指定了当使用 OpenGL 管道绘制时,渲染器应该如何转换几何形状。我们将一组有序变换组合成一个单一的 Transform 组件。此信息将通过标准命名统一变量自动对我们的着色器可用

    Transform {
        id: transform
        translation: Qt.vector3d(root.x, root.y, root.z)
        rotation: fromEulerAngles(theta, phi, 0)
        scale: root.scale
    }

加载动态按顶点数据

Mesh 组件非常简单。我们使用其源属性从 WavefrontObj 格式的文件加载静态几何形状集(如顶点位置、法向量和纹理坐标)。这些数据是从 Blender 应用程序导出的。

    Mesh {
        id: mesh
        source: "qrc:/assets/obj/trefoil.obj"
    }

除了网格元素之外,Qt 3D还通过任务引擎调用的C++钩子,实现了动态生成每个顶点的属性数据。

组件聚合

仅仅实例化组件是不够的。为了在实体上赋予特殊的操作,实体必须通过其组件属性来聚合组件

    components: [ transform, mesh, root.material ]

这使得组件能够在多个实体之间非常容易地共享。在这个例子中,我们包含了在TrefoilKnot自定义类型内部的变换和网格组件。最后一个组件,一个材质类型的组件,由TrefoilKnot自定义类型的一个属性提供。我们稍后会自定义实体的外观。

从相机渲染

我们在main.qml中使用TrefoilKnot自定义类型来在屏幕上绘制TrefoilKnot。

我们使用了与TrefoilKnot.qml中相同的导入语句,并增加了一个针对Qt Quick模块的命名空间导入,这是我们将需要用于动画的。

import QtQuick 2.1 as QQ2
import Qt3D.Core 2.0
import Qt3D.Render 2.0

我们使用实体类型作为根类型,仅仅是为了作为其子项的父项。在这个意义上,实体类型和Item类型非常相似

import Qt3D.Input 2.0
import Qt3D.Extras 2.0

Entity {
    id: root

RendererSettings组件使用ForwardRenderer类型,在完全不接触任何C++代码的情况下,完全配置渲染器

    // Render from the mainCamera
    components: [
        RenderSettings {
            activeFrameGraph: ForwardRenderer {
                id: renderer
                camera: mainCamera
            }
        },
        // Event Source will be set by the Qt3DQuickWindow
        InputSettings { }
    ]

Camera类型是一个简单的包装器,代表了虚拟相机,它包围了内置的Camera类型。它有近平面、远平面、视野、宽高比、投影类型、位置和朝向等属性

    BasicCamera {
        id: mainCamera
        position: Qt.vector3d( 0.0, 0.0, 15.0 )
    }

Configuration类型提供了在真实实现使用方面和组件的完善中,对鼠标控制相机的临时解决方案

    FirstPersonCameraController { camera: mainCamera }

通过场景渲染的所有或部分帧图,使用多个相机是极其简单的。

材质映射

Qt 3D拥有强大且非常灵活的材质系统,允许多个层面的定制。我们使用WireframeMaterial自定义类型来包裹材质类型

    WireframeMaterial {
        id: wireframeMaterial
        effect: WireframeEffect {}
        ambient: Qt.rgba( 0.2, 0.0, 0.0, 1.0 )
        diffuse: Qt.rgba( 0.8, 0.0, 0.0, 1.0 )

然后我们实例化TrefoilKnot类型,并在这上面设置材质

    TrefoilKnot {
        id: trefoilKnot
        material: wireframeMaterial
    }

Qt 3D引擎与渲染器方面一起,现在已有足够的信息,最终使用我们指定的材质渲染网格。

使用动画元素

我们使用了Qt Quick 2提供的动画元素来动画化TrefoilKnot和WireframeMaterial类型的属性。通过QML属性绑定机制更新组件类型的属性

        QQ2.SequentialAnimation {
            loops: QQ2.Animation.Infinite
            running: true

            QQ2.NumberAnimation {
                target: wireframeMaterial;
                property: "lineWidth";
                duration: 1000;
                from: 0.8
                to: 1.8
            }

            QQ2.NumberAnimation {
                target: wireframeMaterial;
                property: "lineWidth";
                duration: 1000;
                from: 1.8
                to: 0.8
            }

            QQ2.PauseAnimation { duration: 1500 }
        }

属性更新由QNode基类注意到,并自动发送至渲染器方面的相应对象。然后,渲染器负责将属性更新转换为GLSL着色器程序中的均匀变量的新值。

运行示例以查看线框线宽脉冲的TrefoilKnot。所有重负载都是由GPU完成的。CPU只需运行属性动画,并且将场景图和帧图转换为原始OpenGL调用。

还可能通过自定义着色程序和材质,在GPU上进行动画。

示例项目 @ code.qt.io

© 2024Qt公司有限公司。本文件中包含的文档贡献归各自所有者所有。本文件提供的文档依据自由软件基金会发布的、经其批准的《GNU自由文档许可证》第1.3版进行许可。