Qt 3D 概述
Qt 3D 提供了一个完全可配置的渲染器,使开发者能够快速实现所需的任何渲染管线。此外,Qt 3D 还提供了一个通用框架,用于实现渲染之外的近实时模拟。
Qt 3D 该框架清晰地分为核心部分和任意数量的“方面”(aspects),这些“方面”可实现开发者所需的任何功能。各个“方面”通过与组件和 实体交互,提供特定功能模块。例如,物理、音频、碰撞、人工智能(AI)和路径规划等均属于“方面”。
基本 3D 功能
Qt 3D 是一个 3D 框架,支持绘制 3D 形状并对其进行移动,以及移动摄像机。它支持以下基本功能:
- 适用于 C++ 和Qt Quick 应用程序的 2D 和 3Drendering
- Meshes 和几何
- Materials
- 着色器
- 阴影映射
- Ambient occlusion
- 高动态范围
- 延迟渲染
- 多纹理渲染
- 实例化渲染
- 统一缓冲区对象
- 移植到 RHI
- 专业技巧
材质
Qt 3D 拥有一个强大且非常灵活的材质系统,支持多层次的自定义。该系统可适应不同平台或不同 OpenGL 版本的渲染方式,支持使用不同状态集进行多遍渲染,提供了在不同层级覆盖参数的机制,并允许轻松切换着色器。所有这些功能均可通过 C++ 或使用 QML 属性绑定实现。
Material 类型的属性可以轻松映射到GLSL着色器程序中的uniform变量上,而该着色器程序本身是在引用的效果属性中指定的。
有关材质使用的示例,请参阅以下示例:
着色器
Qt 3D 支持所有 OpenGL 可编程渲染管线阶段:顶点着色器、细分控制着色器、细分评估着色器、几何着色器和片段着色器。计算着色器计划在未来版本中推出。
有关着色器使用的示例,请参阅Qt 3D :线框 QML 示例。
阴影映射
OpenGL 并不直接支持阴影,但有无数种技术可以用来生成阴影。阴影映射使用简单,既能生成美观的阴影,又几乎不会造成性能开销。
阴影映射通常采用两遍渲染的方式实现。第一遍渲染生成阴影信息;第二遍渲染使用特定的渲染技术生成场景,同时利用第一遍渲染中收集的信息来绘制阴影。
阴影映射的核心原理是:只有距离光源最近的片段才会被照亮。位于其他片段后方的片段会被遮挡,因此处于阴影中。
因此,在第一遍渲染中,场景是从光源的视角绘制的。所存储的信息仅仅是该光空间中最近的片段的距离。 用 OpenGL 的术语来说,这相当于有一个附带深度纹理的帧缓冲对象(FBO)。实际上,距离视点的距离就是深度的定义,而 OpenGL 执行的默认深度测试实际上只会存储最近片段的深度。
甚至无需附加颜色纹理,因为无需对片元进行着色,只需计算其深度即可。
下图展示了一个包含自投影平面和三叶结的场景:

下图展示了一个场景的夸张阴影贴图:

该图像显示了从光源视角渲染场景时存储的深度信息。 颜色越深表示深度越浅(即离摄像机越近)。在此场景中,光源位于场景中物体上方某处,相对于主摄像机而言位于右侧(可与第一张截图对比)。这与玩具平面比其他物体更靠近摄像机这一事实相吻合。
生成阴影贴图后,将进行第二次渲染。在第二次渲染中,将使用场景的常规摄像机进行渲染。 此处可使用任何效果,例如 Phong 着色法。关键在于必须在片段着色器中应用阴影贴图算法。也就是说,距离光源最近的片段会被渲染为受光状态,而其他片段则被渲染为阴影状态。
第一遍渲染生成的阴影贴图提供了关于片元到光源距离的必要信息。随后只需将片元映射到光照空间,从而计算出其相对于光源的深度,以及它在阴影贴图纹理上的坐标位置。 随后,可以在给定的坐标处采样阴影贴图纹理,并将片元的深度与采样结果进行比较。如果片元距离更远,则处于阴影中;否则处于受光区域。
实例化渲染
实例化是一种让 GPU 绘制基础对象多个副本(实例)的方法,每个副本在某些方面(通常是位置、方向、颜色、材质属性、缩放比例等)都会有所不同。Qt 3D 提供了一个与Qt Quick Repeater 元素类似的 API。 在此情况下,委托对象即为基础对象,而模型则提供每个实例的特定数据。因此,虽然附加了Mesh 组件的实体最终会被转换为对glDrawElements的调用,但附加了instanced组件的实体则会被转换为对glDrawElementsInstanced的调用。
实例化渲染计划在未来版本中实现。
统一缓冲区对象
统一缓冲区对象 (UBO) 可以绑定到 OpenGL 着色器程序中,以便随时使用大量数据。UBO 的典型用例是材质或光照参数集。
实用技巧
本页面提供了关于 3D 渲染的一些非常有用的编程技巧:Qt 3D Render Pro Tips。
可配置渲染器
为了同时支持 C++ 和 QML API,并实现完全可配置的渲染器,引入了帧图(framegraph)的概念。场景图(scenegraph)是对渲染内容的数据驱动式描述,而帧图则是对渲染方式的数据驱动式描述。
帧图使开发者能够在简单的正向渲染器(包括 z 填充阶段)与延迟渲染器等方案之间进行选择。它还允许开发者控制何时渲染透明对象等。 由于所有配置均完全基于数据,因此即使在运行时动态修改也十分便捷,且无需触碰任何 C++ 代码。开发者可以通过创建实现自定义渲染算法的帧图来扩展Qt 3D 。
3D 扩展
除了在屏幕上显示 3D 内容的基本功能外,Qt 3D 还具备足够的可扩展性和灵活性,可作为以下与 3D 对象相关的扩展类型的主机:
- 物理模拟
- 碰撞检测
- 3D 位置音频
- 刚体、骨骼及变形目标动画
- 路径规划及其他人工智能
- 拾取
- 粒子
- 对象生成
性能
Qt 3D 旨在提供良好的性能,并能随着可用 CPU 核心数量的增加而扩展,因为现代硬件是通过增加核心数量而不是提高基准时钟频率来提升性能的。使用多个核心效果很好,因为许多任务彼此独立。 例如,路径查找模块执行的操作与渲染器执行的任务之间几乎没有重叠,除非是在渲染调试信息或统计数据时。
Qt 3D 架构
Qt 3D 的主要应用场景是近实时地模拟对象,并将这些对象的状态渲染到屏幕上。《太空侵略者》示例包含以下对象:

- 玩家的地面加农炮
- 地面
- 防御方块
- 敌方太空入侵者飞船
- 敌方头目飞碟
- 敌方和玩家发射的子弹
在传统的 C++ 设计中,此类对象通常会作为类实现,并组织成某种继承树。继承树中的各个分支可能会为根类添加额外功能,例如:
- 接受用户输入
- 播放声音
- 进行动画显示
- 与其他对象发生碰撞
- 在屏幕上绘制
《太空侵略者》示例中的类型可以根据这些特征进行分类。然而,即使是对于这样一个简单的示例,设计一个优雅的继承树也并非易事。
这种方法以及继承的其他变体存在一些问题:
- 深度和广度较大的继承层次结构难以理解、维护和扩展。
- 继承分类体系在编译时便已固定不变。
- 类继承树中的每一层只能基于单一标准或维度进行分类。
- 随着时间的推移,共享功能往往会向上传播至类层次结构的更高层。
- 无法预测开发人员将来会想做什么。
扩展深而宽的继承树通常需要理解并认同原始作者使用的分类体系。因此,Qt 3D 将重点放在聚合上,而不是继承,作为将功能赋予对象实例的手段。具体来说,Qt 3D 实现了实体组件系统(ECS)。
使用 ECS
在 ECS 中,实体代表一个模拟对象,但其本身并不具备任何特定的行为或特征。可以通过让实体聚合一个或多个组件,将额外行为嫁接到实体上。每个组件都是对象类型行为的一个垂直切片。
在《太空侵略者》示例中,地面是一个实体,其附带的组件会告知系统该实体需要渲染以及需要何种渲染方式。 敌方太空入侵者飞船是另一个实体,其附加的组件不仅使飞船得以渲染,还使其能够发出声音、发生碰撞、进行动画显示,并由简单的 AI 进行控制。
玩家的地面加农炮实体与敌方太空入侵者飞船的组件大多相似,只是它没有 AI 组件。取而代之的是,加农炮有一个输入组件,使玩家能够移动它并发射子弹。
ECS 后端

Qt 3D 的后端通过“方面”的形式实现了 ECS 范式中的系统部分。一个方面实现了一组聚合组件(一个或多个)组合后为实体提供的特定功能切片。
例如,渲染器切面会查找同时具备网格、材质以及(可选)变换组件的实体。如果渲染器切面找到这样的实体,它就知道如何利用这些数据渲染出精美的画面。如果某个实体不具备这些组件,渲染器切面会忽略它。
Qt 3D 通过聚合提供额外功能的组件来构建自定义实体。Qt 3D 引擎利用方面来处理和更新具有特定组件的实体。
例如,物理方面会查找具有某种碰撞体积组件的实体,以及另一个指定此类模拟所需其他属性(如质量、摩擦系数等)的组件。一个会发出声音的实体有一个组件,该组件不仅指定其为声音发射器,还指定何时以及播放哪些声音。
由于 ECS 使用聚合而非继承,因此只需添加或移除组件,即可在运行时动态改变对象的行为。
例如,要让玩家在获得能力提升后突然能够穿墙而过,可以暂时移除该实体的碰撞体积组件,直到能力提升效果失效为止。无需为PlayerWhoRunsThroughWalls 创建一个专门的一次性子类。
Qt 3D ECS 的实现
Qt 3D 将 ECS 实现为一个简单的类层次结构。Qt 3D 的基类是 Qt3DCore::QNode,它是QObject 的子类。Qt3DCore::QNode 为QObject 增加了将属性变化自动通知给“方面”的能力,并提供了一个在整个应用程序中唯一的 ID。 这些方面运行在额外的线程中,而 Qt3DCore::QNode 简化了面向用户的对象与这些方面之间的数据传输。
通常,Qt3DCore::QNode 的子类会提供组件所引用的额外支持数据。例如,QShaderProgram 类指定了在渲染一组实体时要使用的 GLSL 代码。

Qt 3D 中的组件是通过继承 Qt3DCore::QComponent 并添加相应方面执行其工作所需的数据来实现的。例如,渲染器方面使用网格组件来检索应发送至 OpenGL 管道的每个顶点数据。
最后,Qt3DCore::QEntity 只是一个可以聚合零个或多个 Qt3DCore::QComponent 实例的对象。
扩展Qt 3D
要为Qt 3D 添加功能——无论是作为Qt XML的一部分,还是专为您的应用程序设计以利用多线程后端——需要完成以下任务:
- 确定并实现任何必要的组件和辅助数据。
- 将组件注册到 QML 引擎中(仅当您使用 QML API 时才需执行此步骤)。
- 继承 QAbstractAspect 并实现子系统功能。
Qt 3D 基于任务的引擎
在Qt 3D 中,每个帧都会向各方面(aspects)查询需执行的一组任务及其之间的依赖关系。调度器会将这些任务分配到所有已配置的核心上,以提升性能。
Qt 3D的方面
默认情况下,Qt 3D 提供了 Qt3DRender 和 Qt3DInput 方面。这些方面所提供的组件及其他支持类,请参阅相应模块的文档。
未来版本的Qt 3D 将添加更多提供扩展功能的方面。
© 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.