实例化渲染
简介
Qt Quick 3D 支持Model 对象的实例化。实例化是指通过单次绘制调用将一个对象渲染多次的技术。(例如OpenGL函数glDrawElementsInstanced 。)
实例化允许以不同变体形式复制模型。与使用Repeater3D 不同,模型及其图形资源仅需分配一次。复制的实例由GPU在底层进行渲染。根据模型的复杂程度,这可带来几个数量级的性能提升。
实际上,实例化是通过定义一个表格来实现的,该表格指定了每个实例相对于基础模型的修改方式。
实例化 API
实例化 API 的主要原则在于其显式性:它不会尝试在现有 API 中自动检测实例化的机会。相反,每个模型都会通过将它的 `instancing ` 属性设置为引用一个 `Instancing ` 对象来单独标记。同一个 `Instancing` 对象可以同时用于多个模型。
Instancing对象指定了一张表,用于定义每个副本的渲染方式。可用的修改包括:
- 变换:位置、旋转和缩放
- 颜色:与模型材质混合的颜色
- 自定义数据:可由自定义材质使用的数据
Qt 提供了三个继承自 Instancing 的 Qml 类型:
- InstanceList 可枚举所有实例,并允许绑定到每个实例的属性。
- RandomInstancing 提供了一种在定义的范围内生成随机实例的方法,以便快速测试和原型设计。
- FileInstancing 从外部文件读取实例表。
实例化示例演示了如何使用 QML API 创建场景。
其他类型的实例表可以通过在 C++ 中继承 `QQuick3DInstancing` 来定义。例如,particle system 在内部使用其专有的实例表,可通过 `ModelParticle3D.instanceTable` 访问。
通过编写自定义着色器代码,可以利用实例化来控制其他属性,例如基于物理的渲染变量、骨骼动画权重、变形,或是任何可以通过自定义材质表达的内容。实例化表中的自定义数据由四个浮点数组成。
自定义实例化示例演示了如何将自定义材质与用 C++ 实现的实例表相结合。
Alpha 混合与实例化
正确的Alpha混合要求半透明物体按从后到前的顺序进行渲染。因此,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 属性,即可启用实例化选择功能。
© 2026 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.