随着汽车由单纯的交通工具、“硬件为主”的工业产品向智能化终端、“第三空间”转变。3D HMI 已成为整车厂打造极致沉浸感与数字豪华感的“标配”。实时光影、昼夜交替、天气变化、地面反射、动态植被……高沉浸感、自然交互的 3D 地图为驾驶者营造身临其境的视觉享受,让每一次导航都变成一种探索的乐趣。Unity 3D 地图基于团结引擎车机版打造,以游戏中的开放世界为概念原型,按照 SDK 设计,采用分层架构,可轻松集成到不同平台的车机系统,并支持定制化效果,开启次世代车载地图导航,多种优化性能的技术手段更为应用的运行稳定提供了保障。
Unity 中国高级技术经理雷达夫在 Unite Shanghai 2024 智能座舱专场演讲中带来了《3D 地图技术实现》的分享,详细讲解 Unity 3D 地图的架构、技术实现细节以及性能优化措施。
传统地图和 3D 地图的对比
传统的 2D 地图,整体是扁平的 2D 风格,这类地图一般来说信息量很少,缺乏沉浸度。现在也出现传统意义上的 3D 地图,即整体画面是 3D 的,能旋转、平移、地图缩放,地图上的基本元素如建筑、道路是 3D 风格的,这类地图比前面的地图信息量好一些、多一些,但也有一些缺点:画面不够真实、沉浸度也缺少。
这里是 Unity 3D 地图跑在高通 8295 设备上的效果。整个地图的渲染效果十分丰富,有实时光影、昼夜变换、天气系统、地面实时反射、楼块的动态生长、万家灯火、动态水面波纹、水面反射、多层水体、随机植被的生成,AOI 的挤出以及全物件样式的实时高清渲染。
Unity 3D 地图是一款基于团结引擎车机版打造的次世代车载地图导航软件。以游戏开放世界为概念原型来构架,将渲染品质全面升级到次世代实时 3D 地图导航,目前可以作为一个量产方案,并在高通的 8155、8295 上都有不错的表现。
路网方面,我们开放了样式配置,可以定制材质、定制车道级道路要素模型,大概二十多种的路网样式可供挑选。
在天空和天光的氛围方面,实现了动态天空24小时-分钟级变换,实时天气系统,根据车辆所在地的外部天气动态更新当前地图上的天气效果,比如阴晴雨雪等各类天气都已经全部实现。
导航中必要的比如 3D 蚯蚓线,3D 的 POI 已经实现如上图所示,其中 3D POI 是可以被其他物件比如建筑遮挡,这样就起到了一定沉浸度的效果。车道级导航效果如图所示,完成了包括环境绘制、车道级导航引导线绘制等。
我们还根据不同的品牌属性和节日做了各种定制化的效果实现。
比如给 4S 店或者研发中心等特定建筑 POI 图标定制、替换,根据不同需求进行 3D 建筑定制替换,给楼宇增加 logo 标识,另外还有节日彩蛋的定制,比如情人节,圣诞节,在节日当天会对车机的地图实时在线更新,以达到更加沉浸度和可交互性。
为了更好地定制各种效果和实现样式设计的需求,我们在项目中实现了一套自定义地图效果编辑器,方便美术师或设计师去调用实现各类设计效果。
左边四类编辑器是我们自己实现的,实现了按导航要素配置和按比例尺配置的编辑器,在各种不同的渲染元素在不同的缩放比例尺下材质的选择。比如要实现郊区的效果,郊区在 15 级比例尺下用什么材质,绿地在 17 级比例尺下用什么渲染风格,都可以通过编辑器的配置达到编辑器里面所见即所得的作用。
还有按照主题、场景定义渲染样式的编辑器,方便设计师和美术师根据不同的地图使用场景来设计不同的渲染样式,比如白天的导航状态,晚上的巡航状态的地图样式,都可以在编辑器里面配置。左下角是根据渲染风格,有按常见类型渲染要素配置的编辑器,比如类型为线条背景的样式在白天巡航状态下是什么样的效果;编辑器本身也可以实时预览相关的资源和渲染效果,达到帮助设计师、美术师所见即所得的作用。我们创作的任何东西都可以在编辑器里面实时地看到。
3D 地图效果除了可以用在导航上,其实也用在我们的 NOP 智驾项目上,目前已经在北京车展上展示过了。如视频所示,NOP 的高精道路、车道级和两旁的建筑,以及动态感知的数据都来自四维地图,右侧的 3D 地图数据来源是腾讯地图,不同的图商可以在主流的 4K 屏上实时展示。
3D 地图技术架构剖析
这样效果的地图是怎么实现的呢?我们现在来详细看下地图的架构是怎样的。
目前整个 3D 地图是按照 sdk 设计的,可以集成到车机系统上,厂商在集成的时候可以根据自己的设计风格来修改默认的地图样式和一些自定义扩展的功能。
我们把地图 sdk 分层级架构主要分为四大块,从下到上的层级依次为:Engine Layer 引擎层、Map Layer 地图层、Design Layer 设计层、HMI Layer。
-
引擎层(Engine Layer)主要由团结引擎车机版提供编辑器的所见即所得的开发和运行时的高性能,主要包括 URAS、自定义渲染管线以及 dots,还有各种有用的 Packages。
-
地图层(MapLayer)是整个地图内容的设计、创作、数据的解析、业务逻辑和地图渲染元素的实时构建和渲染所在。包括了两大 sdk(地图 sdk、导航 sdk)的接入。通过图商的数据来构建整个地图世界,以及为各类 mesh 网格增加渲染效果,比如天气系统、昼夜变换、天光系统、全局光照等等,实时构建我们的 Mesh。然后就是根据导航 sdk 传过来的导航的各类动态渲染元素数据和业务的调用,包括导航引导线,蚯蚓线,各类路标,路口放大图等,相关的业务包括:定位、检索、算路、引导等等,这些业务本身会在 java 侧实现,然后把相关的渲染数据和需要跟 Unity 交互的数据通过团结引擎车机版的 URAS 来在 Render Service 和 Client 通信,就可以渲染出来了。
-
设计层(Design Layer)是开放给厂商使用的,通过地图样式编辑器自定义修改团结引擎里面自带的资产。默认的地图 SDK 带了一套前面视频的效果样式和配置,当然设计师和美术师可以在集成的时候通过地图样式编辑器自定义地修改、控制资源的更新和资源的加载方式。因为团结引擎本身也自带了 assetbundle 的功能,也就是即使在量产发布后,不需要通过 OTA 空推的方式就可以完成资源和业务的启动更新,满足项目内各类资源的打包更新。
-
最后是 HMI Layer,这一层也是给车厂集成用的,主要是用来负责地图 sdk 的车机集成和跟 Android 侧的交互,包括和 RenderService 通信,把同步过来的渲染画面 Prensent 到 URAS Client,以及安卓原生的一些 Overlay、Layout、UI 的显示,还有屏幕上的各种输入操作,比如点击、拖拽、双指多指的操作交互逻辑。这些都是在 HMI 层实现的。
3D 地图技术实现细节
接下来我们看下每层架构中的具体的技术细节。
1. 以游戏开放世界为概念原型
首先 3D 地图底图的构建思路我们是基于游戏开放世界为原型来架构的。
因为地图图商的本身的数据结构一般都是基于瓦片(tile)的形式来组织的,跟游戏的开放世界、大世界是非常一致的。每个瓦片(tile)上的物件也是按照层次组织的,从路网到建筑,再到细小的道路标志都可以通过更新当前自车的经纬度坐标决定去加载/卸载瓦片来实现,不需要通过每帧加载卸载和移动整个地图,而是按需来加载卸载相应的瓦片(tile),就可以完成整个地图的更新。
2. 地图数据结构
地图的数据结构是按照图层来分的,分为 BMD(背景数据)、Obj3D(3D数据)、HD(高精道路数据)三个图层,每个图层分了很多类别,比如 POI、AOI 归为背景图层。3D 建筑、3D 精模、3D 模型归为 3D 模型,可以按照层次去组织地图的渲染方式。
为了更好地了解3D地图技术细节,这里对项目中使用的坐标做个解释。目前 Unity 3D 地图使用了 3 种坐标系:(1)经纬度(2)墨卡托投影坐标(3)Unity 坐标。
经纬度坐标是图商地图 sdk 几何数据接入时的初始形式。再经过墨卡托投影坐标通过近似将经纬度投影到平面上,每个经纬度转换后有唯一的二维坐标。转换后的墨卡托坐标一般数值非常大,为了比较好地在 Unity 坐标里面渲染,需要进一步转换得到 Unity 坐标,转换到 Unity 坐标需要用墨卡托的参考点和当前缩放的尺度,这两个值加上转换规则就可以转换到 Unity 可渲染的坐标了。转换之后可渲染的数据会在 dots 的 JobSystem 中进行三角化处理,之后网格数据以及设计师、美术师创建的资产可以实时地传到 GPU,完成实时渲染。
3. Tile 加载卸载
再来看一下 3D 地图的 tile 的加载卸载、相机的高度、地图比例尺缩放这三者的关系。
在 3D 地图的每一帧画面中,Unity 相机的视域体和地平面会有四个交点,如图所示相机的四条白色射线(相机视域体)与地平面构成一个地图加载范围框(图中红色框),然后通过调用图商地图 sdk,从而得到当前所需要的瓦片的具体数据。在每一帧更新当中,在墨卡托参考点和缩放比例尺确定的情况下,红框所表示的范围将从 Unity 坐标反过来转换回经纬度坐标(原始坐标),经纬度坐标通过图商地图 sdk 调用,就得到了每一帧真正需要用到的那些瓦片数据和地图的数据。同时把红框之外的 tile 卸载,这样就完成 tile 的加载和卸载操作。
4. 使用 DOTS 开发地图 Layer
为了更好的性能,项目使用 DOTS 来开发整个地图 Layer,上图是地图 Layer 的所有 ECS 相应的 SystemGroup 和每个 Group 内部的各类 System,按照业务需要可以创建各种 System。有负责更新地图数据的 group,有用来负责数据转换的 group,还有帮助 TA 和设计需求来处理数据的 group,以及动态查询相关的 Entity 和动态地调整个地图的整体坐标,保证在远距离移图和导航的时候的动态校准的 group,然后还有 Mesh 创建的 group,还有负责最终可渲染的 Entity 创建的 group,最后还有负责 UnLoad 卸载各类资源的 group,保证内存。
这里是我们在团结引擎编辑器中使用 DOTS 开发的界面。DOTS 具有很多相关的工具集和工具包,左上就是开启了检测当前运行时中每一帧所有 Component 的使用情况,运行时查看当前的使用情况,就能了解到 DOTS 当前具体的运行情况,极大地方便我们在项目开发中使用和调试 DOTS。
5. 3D 地图运行时整体时序图
最左边是车机系统,包括 Android, QNX, Embedded Linux 等。当在车机系统启动后,一般来说会启动相应的服务,这个时候会启动对应的桌面 Launcher,Launcher 在启动的时候会把座舱需要用到的各种服务按照优先级按序启动起来,那么 3D 地图本身因为是 URAS 架构,可以把 Render Service 在这个时候做启动,极大地加速启动时间。
Render Service 在启动的时候会异步初始化 3D 地图 sdk,这个操作是通过安卓主线程直接调用 SDK,不需要通过 Unity,这样安卓线程相关的工作可以和 Unity 本身的初始化工作并行处理,极大地加速了 3D 地图的启动时间。在 Render Service 启动的时候,会把 Unity 主线程启动,Unity 相关的工作也开始启动起来了,当 Unity 第一个场景加载完毕的时候,我们会开始根据当前自车的 GPS 定位数据,异步通过地图 sdk 拉取周边的地图 tile 数据,返回的是 NDS 数据,我们会做相应的转换,把 NDS 数据通过刚刚讲到的墨卡托投影转为 Unity 坐标,这些转换后的地图数据会在 job system 中进行三角面化,从而得到相对应的可渲染元素的网格。
这些网格数据加上设计师提供的资源,一起会被提交给渲染线程。拿到这些网格和资源之后会提交给 GPU,做实时渲染。最后这些渲染画面会根据车厂的设计到底是在中控屏上显示地图,还是投屏到仪表上,都是可以的,因为这也是 URAS 的重要功能。
性能优化分析
现在智能座舱上的应用越来越多,越来越卷。在有限的硬件资源下,可供每个应用分配的资源也是越来越少。为了保证应用的运行稳定,Unity 对上车的各个应用都会做深度极致的性能优化。接下来详细了解下现在我们 3D 地图项目用到哪些优化性能的技术。
1. 按需渲染
首先,我们地图是基于开放大世界的方式来开发,并不是传统的直接对地图进行平移等各种操作。我们是按需根据当前的渲染需要从地图数据中加载并实时构建相应的内容,画面不可见的部分我们尽可能不去加载和处理,保障实时渲染的高性能和稳定。
2. 资源最优运行
其次,很重要的是地图里面所有的资源,包括贴图、Shader、材质等等资源都是在编辑器里经过最优化处理后,在运行时从本地加载,保证资源是以最优的状态运行,而不像其他运行方式在运行时加载一些贴图,这样运行持续加载的贴图本身就没有做过压缩,做压缩也是费时间的,所以我们保证了运行时的性能。运行当中我们会利用 Unity 本身各种优化技术,包括静态合批、动态合批、Burst 等等,对图商和车厂都做了相应的 sdk 适配,保证两头都能高效地集成和适配不同的图商和车厂。
3. 跨平台多平台
团结引擎本身不管是编辑器还是运行时,都是跨平台的,所以不管图商的 sdk 和车厂的 sdk 是基于哪个平台,都能集成进来,比如开发平台包括Windows,Mac,Linux 等常用的开发集成平台,然后运行时平台可以为Android,QNX,Embedded Linux,iOS,甚至将来可能是 Web 端,都是可以的。
我们3D地图是用团结引擎车机版开发的,团结引擎目前已经实现了支持 HMI Android、QNX、EmbeddedLinux 等车机系统相关的平台。在这些平台上专注做了特定的优化,比如车机重点关注的启动时间,内存占用,线程使用数量都有相应的优化。
4. URAS
另外有一个重大的功能就是 URAS (Unity Render As Service),这个可以在启动和内存方面有很大的提升。
如图所示,这里是团结引擎车机版使用 URAS 的测试数据,可以看到使用团结引擎车机版和普通的 Unity 版本相比在启动时间上有比较大的提升。
URAS, Unity Render As Service,是团结引擎车机版的一个重要的功能,它区别于传统的 UAAL Unity As a Library,在传统的 UAAL 里面,一个进程中只能存在一个实例中,只能为当前进程服务。但是在 URAS 中,可以支持引擎可以作为渲染服务被嵌入原生 APP 中,多个工程共用一个渲染服务,互不干扰,从而提升开发效率和节省车机资源。
如图所示,这是 3D 地图使用 URAS 的方式,我们轻 Client 端和重 RenderService 端,可以看到,Client 端只有跟安卓相关的显示内容和为 RenderService 提供的 SurfaceView。其他所有的内容和业务逻辑都是放在 RenderService 端,Client 端和Service 端通过 aidl 通信。
另外,在传统非 URAS 的方式启动的时候,画面的第一帧渲染需要有很多的依赖加载项,而且是在用户点击地图导航的时候才做启动,这样启动速度很慢,但如果用了 URAS 的方式,在车点火系统启动的时候,下面 RenderService 就开始做异步启动了,极大地提升了用户体验,而且在给车厂集成的时候,用的是 Client 端,它是一个轻量的,而不是 Service 端,我们给车厂做集成的时候,非常方便地加速我们的效率。
5. 基于 DOTS 开发
我们的 3D 地图项目是基于 DOTS 开发实现的,DOTS 本身就有很多提升性能的特点:
-
ECS loop,我们的整个业务都是规划为各种 System,和 SystemGroup 的数据和行为分开,使得数据访问极其高效,提高 CPU cache 的命中率。
-
Job System,我们的很多业务都是放在 Job 中去做的,比如地图数据的整理、筛选、组织、Mesh 构建等等工作都是放在 Job 中跟其他线程并行完成,能极大地提高资源的利用率以及降低功耗。
-
Burst,几乎所有的 Job System 都用 Burst 编译,使得在做三角面化和其他执行效率在某些数学库调用上比一般的 C++ 还要快。
-
Entity Graphics,Entity Graphics 是 2022.3LTS 的 DOTS 1.0 版本中很重要的一个特性,可以更加快速地设置 Drawcall 和组织渲染元素和命令,利用更高效的 Instancing 模式的 Shader 和 DOTS Instancing 来组合合批并实例化,极大极少 DrawCall 的数量,从而更有效地渲染大量实例物件类似 3D 地图这样的场景。
6. 针对特定硬件平台使用了特定的优化功能
为了更加极致地提升 GPU 的性能,我们还针对特定硬件平台使用了特定的优化功能,比如高通的 GPU 在 8295 上就支持 GLES 的 VRS,VRS 也就是可变着色率,可以控制 GPU 渲染器在光栅化物体的时候,不一定要按照固定的每个像素点一次采样计算的方式,而是可以用2个或自定义的三个、多个像素行列来做一次 Fragment Shader 计算。在项目当中,可以针对画面中颜色变动很小的物件材质使用比如 1x2 或者 2x1 的 VRS,在地图 SDK 里面,我们目前是对地面、普通建筑、天空使用了 VRS,对于精模比较贴近相机的物体,精细化的模型我们是没有使用的。这样在不影响画面的情况下,极大地提升了 GPU 性能和帧率。
如图所示可以看到,在关闭和开启 VRS 的情况下,帧率从 39 帧提升到 51 帧,提升了近 30%,带来的收益是 CPU 的各个线程的工作时间直接减少,GPU 的开销也降低,同时 CPU 在等 GPU 的时间也并行地减少,这样在不影响画面质量的情况下,极大地提升帧率和降低硬件的算力和功耗。
7. Map 层优化
除了在引擎层做了优化之外,我们在 Map 层我们做了这些优化内容:包括 Shader 变体的裁剪,Tile 做了一些 cache,把最近一段时间没有被用到的 Tile 清除掉,这个时间和缓存大小目前都是可配置的。我们还加入了异步加载 tile 的方式,使得加载卸载 Tile 的时候不会卡主线程,保证帧率的稳定。
我们后续 3D 地图 sdk 的规划内容如下:
后续我们会继续尝试 SGSR 超分的 GPU 优化方法,以及尝试使用 Shader LOD 对场景中的物件材质根据 LOD 来选择不同消耗的 Shader 和动态 LOD,来最优化 GPU 性能。
以上是我分享的内容,谢谢大家。
团结引擎车机套件是基于团结引擎车机版及相关开发工具打造的智能座舱 3D HMI 应用集合(车模车控、导航智驾、游戏娱乐、3D Launcher 等)支持主流座舱系统和平台,覆盖座舱主要应用场景,并提供一流的视觉效果体验。作为车载应用渲染方案的最佳实践集合,能够有效缩短项目开发周期,降低成本。截止五月,智能电动车品类中超过 85% 的主机厂用 Unity 来打造中控屏、仪表盘。Unity 中国已与 35 家车厂合作,推出了 68 款量产车型。
[1]团结引擎官网:
https://unity.cn/tuanjie/tuanjieyinqing
[2]团结引擎专区:
https://developer.unity.cn/plate/tuanjie-engine
[3]团结引擎问答专区:
https://developer.unity.cn/plate/tuanjie-engine?tab=ask