实例渲染

简介

Qt Quick 3D 支持 对象的实例化。实例化是指通过一次绘制调用多次渲染一个对象的技术。(例如 OpenGL 函数 。)Model glDrawElementsInstanced

实例化允许以不同的方式复制一个模型。与使用Repeater3D 不同的是,模型及其图形资源只分配一次。复制实例的渲染由 GPU 在底层完成。根据模型的复杂程度,性能可提高几个数量级。

在实践中,实例化是通过定义一个表来完成的,该表指定了每个实例相对于基础模型的修改方式。

实例 API

实例化 API 的主要原则是显式:它不会试图在现有的 API 中自动检测实例化的机会。相反,通过设置instancing 属性以引用Instancing 对象,每个模型都会被单独标记。同一 Instancing 对象可同时用于多个模型。

实例化对象指定了一个表,该表定义了每个副本的渲染方式。可用的修改有

  • 变换:位置、旋转和缩放
  • 颜色:与模型材质混合的颜色
  • 自定义数据:可被自定义材质使用的数据

Qt Qml 提供了三种继承自 Instancing 的 QML 类型:

  • InstanceList 枚举所有实例并允许绑定每个实例的属性。
  • RandomInstancing 通过在定义的范围内生成随机实例,提供了一种快速测试和原型的方法。
  • FileInstancing 从外部文件读取实例表。

实例示例展示了如何使用 QML API 创建场景。

其他类型的实例表可通过子类化QQuick3DInstancing 在 C++ 中定义。例如,particle system 内部使用自己的实例表。它可以在ModelParticle3D.instanceTable 中找到。

通过编写自定义着色器代码,可以使用实例化来控制其他属性,如基于物理的渲染变量、骨骼动画权重、变形或其他任何可以用自定义材质表达的属性。实例化表中的自定义数据由四个浮点数组成。

自定义实例化示例展示了如何将自定义材质与用 C++ 实现的实例表结合起来。

阿尔法混合和实例化

正确的阿尔法混合需要从后向前渲染半透明对象。因此,QtQuick3D 会将不透明和半透明对象分开排序,并按照正确的顺序进行渲染。但是,如果不打开depth-sorting ,GPU 将按照实例表指定的顺序渲染实例。出于性能考虑,QtQuick3D 默认情况下不会对表格进行排序,因为如果实例数量较多,排序过程可能会耗时较长。这意味着,如果半透明实例相互重叠,或与其他半透明对象重叠,结果可能看起来不对。一般来说,不透明度较低时,错误较不明显。

完全不透明的对象与不重叠的半透明对象在一起时总是能正确渲染,因为 Qt 使用深度缓冲区测试来避免在不透明对象后面绘制。不过,缺乏排序可能会影响不透明对象的性能:它们可能不会以最佳顺序呈现,这意味着同一像素可能会被写入多次,从而增加片段着色器的工作量。

渲染器不会检查实例表的内容,因此当实例表包含半透明的 alpha 值时,必须明确指定:将hasTransparency 属性设置为true ,以确保渲染器启用 alpha 混合。这适用于所有实例:即使是完全不透明的实例也会在没有深度测试的情况下进行渲染,从而可能导致可见错误。

相对于场景其他部分的渲染顺序可以通过设置模型的depth bias 进行调整。

变换和实例化

每个实例在实例表中都有自己的变换。这与实例模型上的变换相结合。这有点复杂,因为有几种使用情况:

  • 对模型进行变换,并应用到每个实例。这样可以制作廉价的动画,例如一次性旋转所有实例,而无需更改实例表。
  • 一次性转换整组实例。
  • 对模型层次结构进行实例化。

为了支持所有这些情况,模型的变换分为两部分:本地实例变换全局实例变换。从概念上讲,实例化是这样进行的:

  • 首先,根据本地实例变换对模型进行变换。
  • 然后应用实例表变换计算每个实例。
  • 最后,根据全局实例变换对整个实例对象组进行变换。

默认情况下,模型的局部实例变换包括模型的缩放和旋转,其余部分进入全局实例变换。

这可以通过设置模型的instanceRoot 属性来控制。这定义了实例坐标系的原点。最常见的用法是在对模型的层次结构进行实例化时使用。例如,一个球体围绕一个立方体运行:

Model {
    id: cube
    instancing: someInstanceTable
    source: "#Cube"
    materials: DefaultMaterial { diffuseColor: "lightgray" }
    Node {
        Model {
            source: "#Sphere"
            instanceRoot: cube
            instancing: cube.instancing
            x: 150
            materials: DefaultMaterial { diffuseColor: "gray" }
        }
        NumberAnimation on eulerRotation.y {
            from: 0
            to: 360
            duration: 4000
            loops: Animation.Infinite
        }
    }
}

instanceRoot 用于指定球体实例的位置,就好像它是立方体的一个元素一样。层次结构中的每个模型仍需指定instancing 属性:在正常情况下,它们都应设置为相同的Instancing 对象。

instanceRoot 也可在实例化单个模型时使用。例如,围绕偏心点旋转的圆柱体:

 Node {
    id: parentNode
    Model {
        source: "#Cylinder"
        instanceRoot: parentNode
        instancing: anotherInstanceTable
        x: 25
        materials: DefaultMaterial { diffuseColor: "white" }
    }
    NumberAnimation on eulerRotation.y {
        from: 0
        to: 360
        duration: 1000
        loops: Animation.Infinite
    }
}

选取和实例化

Picking 是一种可以从用户界面交互中选择模型的机制。在实例化渲染中,同一模型有多个表现形式,因此选取结果将包括 。通过在基本模型上设置 属性,可启用实例化选取。instance index pickable

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.