Back to Blog home

Qt 3D的未来展望

Published on 星期四 一月 23, 2020 by Sean Harmer, KDAB [Qt Service Partner] in Biz Circuit Dev Loop Qt3D | Comments

本文翻译自:The Future of Qt 3D
原文作者:Sean Harmer
翻译:Richard Lin


如您所知,Qt推出了名为Qt Quick 3D的全新模块,它基于QML API为Qt Quick增加了3D绘图能力(预计在Qt 6提供C++ API)。这对Qt 3D有什么影响,未来在Qt世界中它又该如何定位呢?

希望本文以及后续文章可以解答这一问题,同时能深入介绍我们对Qt 3D正在进行的改进。本文将聚焦在Qt 5.x中即将发布的改进,而下一篇文章将会深入介绍在Qt 6时代我们将对Qt 3D做的一些研究和改进。

如何定位Qt 3D?

Qt 3D是一个灵活的框架。为此,它极少限制您要渲染的内容和方式。和任何技术选择一样,这么做有利有弊,需要妥协和权衡。

不利的一面是,相对其他Qt模块而言,Qt 3D要求开发者具备更多的专业知识,您可能会比预想更快地碰到需要实现自定义材质或者在frame graph上实现渲染算法的点。从好的一面来看,您可以完全掌控渲染算法,在完全自定义的着色器流水线中的映射数据。

Qt Quick 3D则试图克服这些缺点,在Qt Quick 2应用程序中可以更方便地添加简单的3D内容。当然,这同样有利有弊。它可以把在应用中添加3D变得简单,但是如果Qt Quick 3D 没有提供您想要的功能,那您还是要自定义了。

您如果想用某个内建材质显示一个3D模型并用一些2D内容盖再上面,那么Qt Quick 3D可能是很好的选择。然而,如果您想要实现更多复杂的功能,比如实现自定义反射,即通过模板缓冲区(stencil buffer)正确裁切出上下颠倒的物体外形來模仿倒影,那么您就可能需要自己写3D渲染代码或者切换到其他框架,例如Qt 3D模块。

类似情况还包括,如果您想使用延迟渲染,阴影剪裁,批量渲染或者其他数千种渲染技术。我的意思是说,的确有使用Qt Quick 3D的需求,但是Qt 3D也有适用的场景,它们包括:

  • 相比上述更复杂的用例
  • 那些愿意撸起袖子动手干的开发者
  • 那些希望使用更完整C++ API来代替或补充QML的开发者
  • 那些不能使用GPL或商业授权的开发者

还有另一个选项可以简化在程序中添加3D内容。它使用并释放了Qt 3D的强大功能,同时又使用简单。我们开发了Kuesa,它的运行时基于Qt 3D,可以方便导入各种glTF 2格式文件。我们也有导出器,可以借助Kuesa的能力, 把Blender和3DS Max中的设计导出为 C++/QML应用程序。

pipeline-diagram

Kuesa Runtime 1.1很快就要发布了,您现在也可以就通过GitHub尝试最新的版本。它能完全兼容glTF2标准,包含了变形目标动画(morph target animation),骨骼动画和基于物理渲染的粗糙金属材质(PBR metal-rough materials)。它能让你轻松加载、查看网络上各种格式的模型,并通过应用数据控制它们。

得益于一个外部代码贡献,Qt 3D中内置部分但完全兼容的glTF2格式支持,这里的工作量非常大并且需要使用与Qt3DExtras完全不同的材质处理方式。

gitf

Qt 3D的计划是什么?

首先,我要明确地说Qt 3D不会消失。Kuesa和其他项目上正在使用Qt 3D,其他公司甚至还在一些非常大的商业应用上使用Qt 3D。

我们知道Qt 3D存在不少性能问题,正如您可能已从gerrit上看到了大量的更新,我们已在非常努力地解决这些问题。下面让我们简要梳理一下正在发生的事情和未来计划。

多线程架构

从一开始,Qt 3D就被设计成多线程模式。通常来说这是件好事,但是随着异步性的增加,事情会变得棘手。在一些没有良好内存分配器或信号量实现不理想的低端嵌入式硬件上,多线程实际上可能会碍事。

为了提升这块性能,我们在Qt 5.14中去掉了所谓的Aspect Thread。仍有一个线程池来并行化任务处理,但是可以通过一个环境变量控制。

在常规场景中去掉帧缓存对象(FBO)

在执行3D内容渲染、再叠加2D UI的常规场景中,Qt 3D不再只能使用帧缓存对象(FBO)了。这种方式首先将3D内容渲染到FBO附加的颜色纹理(以及深度纹理)中,这是OpenGL必须要设置的渲染目标。然后Qt Quick把同一个颜色纹理映射到一个简单四边形上,最后与Qt Quick 2场景的其余部分合成。

这个方式在桌面和许多设备上都没有问题。然而,有些设备的FBO实现非常差,会极大降低性能。如果3D内容严格地位于UI下层并使用简单的渲染方式(通常是正向渲染),那么我们可以对其进行优化,完全避免使用FBO代码路径。这时,我们可以命令Qt 3D直接在屏幕上绘制,因为我们明白所有Qt Quick内容都会在这个基础上覆盖。要启用此优化,应使用Scener3D全新的compositingModeproperty(Qt 5.14起),并设置为Underlay。非常感谢Giuseppe D’Angelo实现了这一点,以及Paul Lemire做的集成。

优化消息系统(Notification System)

第三个大变化领域,也是仍在进行中的领域,是改变我们在Qt 3D前、后端发送/接受属性变化通知的方式。到目前为止,这是通过为每一个属性变化传递类似事件的数据包来实现。在有成千上万个实体和许多动画属性的大规模场景中,这就会让性能陷入泥沼,并成为瓶颈。

在考虑各种选择后,Mike Krus和Paul Lemire一直十分努力地重新设计这个重要的子系统,以提高性能。新机制是基于当前端和后端对象变dirty后直接同步的原理。这让一个对象上的所有属性可以一次性全部更新,而不是每次调用只更新一个属性。当前基准测试结果表明,在大规模场景(数千个实体)中,属性变更通知分发速度加快了200~300%。

如果一切顺利,以上这些修改都会在未来的Qt 5.14.x版本中落地。

总结

除了以上改进,我们还在整个代码库中引入了许多小的提升。例如,frame graph的遍历现在只在frame graph中发生了实质性影响输出的变化时发生。另外还有仅当uniforms的值改变后才会更新的优化。

在Qt 5.14系列中我们对Qt 3D进行了许多优化,并且将来还有更多。这些提升大大降低了CPU渲染帧时额外的CPU开销,同时减少了线程同步的数量,因为线程同步可能会导致有些系统上的时间浪费。

下一篇文章我们将深入探究为在Qt 6中提升Qt 3D所作的研究,以及如何利用现代图形API来实现更高的性能。

Subscribe to Our Blog

Stay up to date with the latest marketing, sales and service tips and news.