Qt 3D 概述
Qt 3D RHI 提供了一个完全可配置的渲染器,使开发人员能够快速实现所需的任何渲染管道。此外, 还为渲染之外的近实时模拟提供了通用框架。Qt 3D
Qt 3D 渲染器被清晰地分离成一个核心和任意数量的方面,这些方面可以实现它们希望实现的任何功能。这些方面与组件和实体交互,以提供部分功能。方面的例子包括物理、音频、碰撞、人工智能(AI)和路径查找。
基本三维功能
Qt 3D 是一个三维框架,可用于绘制三维图形、移动三维图形以及移动摄像头。它支持以下基本功能:
- 用于 C++ 和Qt Quick 应用程序的 2D 和 3Drendering
- Meshes 几何图形
- Materials
- 着色器
- 阴影映射
- Ambient occlusion
- 高动态范围
- 延迟渲染
- 多重贴图
- 实例渲染
- 统一缓冲对象
- 移植到 RHI
- 专业提示
材质
Qt 3D RHI Pro 的材质系统功能强大且非常灵活,可进行多层次的自定义。它可满足不同平台或 OpenGL 版本上的不同渲染方法,启用具有不同状态集的多个渲染传递,提供在不同级别重写参数的机制,并允许轻松切换着色器。所有这些都可以通过 C++ 或 QML 属性绑定实现。
Material 类型的属性可以很容易地映射到 GLSL 着色程序中的统一变量,而 GLSL 着色程序本身就是在引用的效果属性中指定的。
有关使用材质的示例,请参阅以下示例:
着色器
Qt 3D 支持所有 OpenGL 可编程渲染流水线阶段:顶点、细分控制、细分评估、几何和片段着色器。计算着色器计划在未来发布。
有关使用着色器的示例,请参阅Qt 3D: 线框 QML 示例。
阴影映射
OpenGL 不直接支持阴影,但有无数种技术可用于生成阴影。阴影映射可以简单地生成美观的阴影,同时性能成本很低。
阴影映射通常使用两道渲染来实现。第一遍生成阴影信息。在第二道工序中,使用特定的渲染技术生成场景,同时使用第一道工序中收集的信息绘制阴影。
阴影映射背后的理念是,只有离光线最近的片段才会被点亮。其他片段后面的片段会被遮挡,因此处于阴影中。
因此,在第一次绘制时,场景是从光线的角度绘制的。所存储的信息仅仅是光照空间中最近片段的距离。用 OpenGL 术语来说,这就相当于一个带有深度纹理的帧缓冲对象(Framebuffer Object,简称 FBO)。事实上,与眼睛的距离就是深度的定义,而 OpenGL 默认的深度测试实际上只会存储最近片段的深度。
甚至不需要附加颜色纹理,因为不需要对片段进行阴影处理,只需计算其深度即可。
下图显示了一个带有自阴影平面和三叶草结的场景:
下图显示了该场景的夸张阴影贴图纹理:
该图显示了从光线角度渲染场景时存储的深度。颜色越深代表深度越浅(即离摄像机越近)。在这个场景中,光线被放置在场景中物体的上方,相对于主摄像头的右侧(与第一张截图比较)。这与玩具飞机比其他物体更靠近摄像机的事实相吻合。
生成阴影贴图后,就可以进行第二次渲染。在第二遍渲染中,使用正常场景的摄像机进行渲染。这里可以使用任何效果,例如 Phong 阴影。在片段着色器中应用阴影贴图算法非常重要。也就是说,最靠近光线的片段要绘制成亮的,而其他片段则绘制成阴影。
第一遍生成的阴影贴图提供了片段与光线距离的必要信息。然后,只需在光线空间中重新映射片段,从而从光线角度计算出片段的深度,以及片段在阴影贴图纹理上的坐标位置。然后就可以根据给定的坐标对阴影贴图纹理进行采样,并将片段的深度与采样结果进行比较。如果片段距离较远,则处于阴影中;反之,则点亮。
实例渲染
实例化是一种让 GPU 绘制多个基本对象副本(实例)的方法,每个副本都会以某种方式发生变化。Qt 3D 提供了与Qt Quick Repeater 元素类似的 API。在这种情况下,委托是基本对象,而模型提供每个实例的数据。因此,带有Mesh 组件的实体最终会转化为对 glDrawElements 的调用,而带有实例组件的实体则会转化为对 glDrawElementsInstanced 的调用。
实例渲染计划在未来的版本中推出。
统一缓冲对象
统一缓冲对象(UBO)可绑定到 OpenGL 着色程序,以便随时提供大量数据。UBO 的典型用例是材质或照明参数集。
实用技巧
本页提供了一些非常有用的 3D 渲染编程技巧: Qt 3D 渲染专业技巧。
可配置的渲染器
为了将对 C++ 和 QML API 的支持与完全可配置的渲染器相结合,我们引入了场景图的概念。场景图是对渲染内容的数据驱动描述,而框架图则是对渲染方式的数据驱动描述。
通过框架图,开发人员可以选择使用简单的前向渲染器(包括 z 填充通道),或使用延迟渲染器(例如)。开发人员还可以控制何时渲染透明对象等。由于这一切都是纯粹根据数据配置的,因此即使在运行时进行动态修改也非常容易,无需接触任何 C++ 代码。您可以通过创建自己的框架图来扩展Qt 3D ,从而实现自定义的渲染算法。
三维扩展
除了在屏幕上显示 3D 内容的基本功能外,Qt 3D 还具有足够的可扩展性和灵活性,可以作为与 3D 对象相关的以下类型扩展的主机:
- 物理模拟
- 碰撞检测
- 3D 定位音频
- 刚体、骨骼和变形目标动画
- 路径查找和其他人工智能
- 拾取
- 粒子
- 物体生成
性能
Qt 3D 由于现代硬件是通过增加内核数量而非基本时钟速度来提高性能的,因此《Project.Active.php》在设计时考虑到了性能和可用 CPU 内核数量的可扩展性。使用多个内核的效果很好,因为许多任务是相互独立的。例如,路径查找模块执行的操作与渲染器执行的任务不会有太多重叠,除非是在渲染调试信息或统计数据时。
Qt 3D 架构
Qt 3D 的主要用例是近乎实时地模拟对象并将这些对象的状态渲染到屏幕上。太空侵略者》示例包含以下对象:
- 玩家的地面加农炮
- 地面
- 防御块
- 敌方太空入侵者飞船
- 敌方老大飞碟
- 敌人和玩家射出的子弹
在传统的 C++ 设计中,这些类型的对象通常会以某种继承树形式排列的类来实现。继承树中的不同分支可能会为根类添加额外的功能,例如
- 接受用户输入
- 播放声音
- 动画效果
- 与其他对象碰撞
- 在屏幕上绘制
太空入侵者 "示例中的类型可以根据这些特征进行分类。然而,即使是为这样一个简单的例子设计一个优雅的继承树也并非易事。
这种方法和其他继承变体都会带来许多问题:
- 深而宽的继承层次结构难以理解、维护和扩展。
- 继承分类法在编译时就已定型。
- 类继承树中的每一级只能根据单一标准或轴进行分类。
- 随着时间的推移,共享功能往往会在类层次结构中涌现。
- 我们无法预测开发人员想要做什么。
扩展深度和广度继承树通常需要理解并同意原作者使用的分类标准。因此,Qt 3D 将重点放在聚合上,而不是将继承作为向对象实例传授功能的手段。具体来说,Qt 3D 实现了实体组件系统(ECS)。
使用 ECS
在 ECS 中,实体代表一个模拟对象,但实体本身不具备任何特定行为或特征。通过让实体聚合一个或多个组件,可以将额外的行为嫁接到实体上。每个组件都是一个对象类型行为的垂直切片。
在 "太空入侵者 "示例中,地面是一个带有附加组件的实体,该组件告诉系统该实体需要渲染以及需要何种渲染。敌方的太空入侵者飞船是另一个实体,它带有附加组件,不仅能使飞船进行渲染,还能发出声音、与之碰撞、制作动画,并由简单的人工智能进行控制。
玩家的地面加农炮实体与敌方太空入侵者飞船的组件基本相似,只是没有人工智能组件。取而代之的是一个输入组件,让玩家可以移动大炮并发射子弹。
ECS 后端
Qt 3D 的后台以方面的形式实现了 ECS 模式的系统部分。一个方面实现了由一个或多个聚合组件组合而成的实体功能的特定垂直切片。
例如,渲染器方面会查找具有网格、材料和可选变换组件的实体。如果渲染器方面找到了这样的实体,它就知道如何获取这些数据并从中绘制出漂亮的效果。如果实体没有这些组件,渲染器会忽略它。
Qt 3D 通过聚合提供附加功能的组件来创建自定义实体。 引擎使用方面来处理和更新具有特定组件的实体。Qt 3D
例如,物理方面可查找具有某种碰撞体积组件和另一种指定此类模拟所需的其他属性(如质量、摩擦系数等)组件的实体。发出声音的实体有一个指定其为声音发射器的组件,以及指定何时播放和播放哪些声音的组件。
由于 ECS 使用聚合而非继承,因此只需添加或删除组件,就可以在运行时动态改变对象的行为方式。
例如,为了让玩家能在开机后突然穿墙而过,可以暂时移除该实体的碰撞音量组件,直到开机时间结束。无需为PlayerWhoRunsThroughWalls
创建专门的一次性子类。
Qt 3D ECS 实现
Qt 3D ECS 是一个简单的类层次结构。 的基类是 ,它是 的子类。 在 的基础上,增加了自动将属性变化传达给各个方面的功能,以及在整个应用程序中唯一的 ID。方面存在于额外的线程中, 简化了面向用户的对象与方面之间的数据传输。Qt 3D Qt3DCore::QNode QObject Qt3DCore::QNode QObject Qt3DCore::QNode
通常情况下,Qt3DCore::QNode 的子类会提供组件引用的附加支持数据。例如,QShaderProgram 类指定了渲染一组实体时使用的 GLSL 代码。
Qt 3D 中的组件是通过子类化Qt3DCore::QComponent 并添加相应方面工作所需的数据来实现的。例如,渲染器方面使用网格组件来获取应发送到 OpenGL 管道的每个顶点数据。
最后,Qt3DCore::QEntity 只是一个可以聚合零个或多个Qt3DCore::QComponent 实例的对象。
扩展Qt 3D
为Qt 3D 添加功能,无论是作为 Qt 的一部分,还是为您自己的应用程序添加特定功能,以便从多线程后端中获益,这包括以下任务:
- 确定并实现任何必要的组件和支持数据。
- 向 QML 引擎注册组件(仅当您使用 QML API 时)。
- 子类化 QAbstractAspect 并实现子系统功能。
Qt 3D 基于任务的引擎
在Qt 3D 中,每个框架都会要求各方面执行一组任务以及它们之间的依赖关系。这些任务由调度程序分配给所有配置的内核,以提高性能。
Qt 3D方面
默认情况下,Qt 3D 提供 Qt3DRender 和 Qt3DInput 方面。这些方面提供的组件和其他支持类将在这些模块的文档中讨论。
在Qt 3D 的未来版本中,还将添加提供更多功能的其他方面。
© 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.