【Unity3D】Cesium加载大地图
1 前言
Cesium 是一个地球可视化平台和工具链,具有数据切片、数据分发、三维可视等功能。
Cesium 支持 JS、Unity、Unreal、O3DE、Omniverse 等平台,框架如下。
Cesium 相关链接如下:
- Cesium 官网:https://cesium.com
- CesiumLab 下载:https://www.cesiumlab.com/cesiumlab.html
- CesiumLab 手册:https://www.cesiumlab.com/CesiumLab地理信息基础数据处理平台使用手册.pdf
- CesiumLab viewer:http://localhost:9003/viewer
- Cesium ion:https://ion.cesium.com
- cesium-unity-samples:https://github.com/CesiumGS/cesium-unity-samples
- cesium-unity:https://github.com/CesiumGS/cesium-unity
- cesium-native:https://github.com/CesiumGS/cesium-native
- Cesium for Unity Quickstart:https://cesium.com/learn/unity/unity-quickstart
- Building Cesium for Unity:https://github.com/CesiumGS/cesium-unity/blob/main/Documentation~/developer-setup.md
- Cesium实验室-CSDN:https://blog.csdn.net/weixin_43805235
- Cesium实验室-B站:https://space.bilibili.com/346212872
本文实验完整资源见→Cesium加载大地图案例。
2 环境搭建
本节主要参考 Cesium for Unity Quickstart。
1)创建 3D (URP) 或 3D (HDRP) 项目
说明:官方建议 Unity Editor 最低版本为 2021.3.2f1,笔者 Unity Editor 版本为 2021.3.11f1c2;Cesium for Unity 可与通用渲染管线(URP)和高清渲染管线(HDRP)配合使用,但是,它不支持 Unity 的内置渲染器,如果选择 3D 项目作为模板,Cesium 加载的数据集将无法正确渲染。
2)添加作用域注册表
依次点击【Edit→Project Settings→Package Manager】,添加注册表信息如下。
Name: Cesium
URL: https://unity.pkg.cesium.com
Scope(s): com.cesium.unity
3)下载 Cesium For Unity
依次点击【Window→Package Manager】打开包管理器窗口,在 Packages 菜单中选择 My Registries,下载 Cesium for Unity,如下。
下载成功后, 菜单栏会多出一个 Cesium 菜单,如下。
4)连接到 Cesium ion
在 Cesium 窗口点击 Connect to Cesium io 按钮,跳转到 Web 网页,点击 Allow。
5)添加 Token
在 Cesium 窗口点击 Token 按钮,添加 token,如果没有 token,就创建一个 token,如果有 token,就使用已创建的 token。
6)创建世界地图
在 Cesium 窗口点击 Cesium World Terrain + Bing Maps Aerial imagery 添加世界地图。
场景显示如下。
如果看不见地图,可能是相机的位置比较远,被裁剪了,可以调整远裁剪平面的位置,如下。
7)添加动态相机
屏蔽场景中默认的相机,在 Cesium 窗口添加 Dynamic Camera,如下。此时,在 Hierarchy 窗口可以看到 CesiumGeoreference 对象下面自动生成了一个名为 DynamicCamera 的对象,该对象上挂了 Camera 组件。
运行后,可以通过鼠标和方向按键控制相机位置和姿态,如下。
说明:视觉的变化通过调整 CesiumGeoreference 组件下的 Latitude 和 Longitude 属性实现,如下。
补充:读者也可以下载 Cesium 官方 Deom 体验一下,详见→cesium-unity-samples。
3 地图切片
本节主要介绍 fbx 文件切片流程,对于其他文件的切片,可以参考 CesiumLab地理信息基础数据处理平台使用手册。
3.1 切片
下载并安装 CesiumLab 后,打开 CesiumLab 客户端,fbx 文件的切片如下。
在处理日志中可以查看任务是否处理成功,如下。如果切片失败,可能是 fbx 文件中包含相机或灯光,使用 Blender 删除相机和灯光,再重新导出 fbx 文件。
生成的文件如下,加载切片时,需要用到 tileset.json 文件。
3.2 预览切片
在分发服务中可以查看切片,步骤如下。
点击预览后,会跳转到另一个网页,显示切片如下。
用户在浏览器中输入:http://localhost:9003/viewer/index.html,再按以下步骤添加切片,也可以预览切片。
3.3 上传切片到 Cesium ion
在 Cesium ion 官网登录账号后,按以下步骤上传切片。
选择文件后,上传切片。
在 My Assets 窗口可以查看已经上传的切片,如下。
注意:第一列的 ID 在加载资源时会用到;用户也可以将 Asset Depot 中的资源添加到 My Assets 中。
4 Unity 中加载切片
4.1 加载 Cesium ion 中切片
在 Cesium 窗口单击 Add 按钮,在底部 Console 右边会出现 Cesium ion Assets 窗口,选择地图添加到场景中,如下。
在 Hierachy 窗口双击 CesiumGeoreference 下面的地图对象,使相机聚焦到地图,地图显示如下,通过修改 ion Asset ID 可以加载不同地图。
4.2 加载 CesiumLab 服务中切片
在 Cesium 窗口点击 Blank 3D Tiles Tileset,在 Hierarchy 窗口会生成 CesiumGeoreference 和 Cesium3DTileset 对象,选中 Cesium3DTileset 对象,设置切片的 url,如下。
url 来自 CesiumLab,如下。
在 Hierachy 窗口双击 Cesium3DTileset 对象,使相机聚焦到地图,地图显示如下。
可以看到,地图方位异常,在 4.4 节将介绍调整地图方位的方法。
4.3 加载本地切片
将切片拷贝到项目目录下的 Resources / city 目录下。在 Cesium 窗口点击 Blank 3D Tiles Tileset,在 Hierarchy 窗口会生成 CesiumGeoreference 和 Cesium3DTileset 对象,选中 Cesium3DTileset 对象,设置切片的 url,如下。
在 Hierachy 窗口双击 Cesium3DTileset 对象,使相机聚焦到地图,地图显示同 4.2 节。
4.4 调整地图方位
1)通过 CesiumLab 预览参数调整地图
使用 3.2 节中方法预览切片,调整好方位后,将鼠标放在屏幕正中间,记录底部的经度、纬度、高度,如下。
选中 CesiumGeoreference 对象,设置经度、纬度、高度为上面记录的值,如下。
在 Hierachy 窗口双击 CesiumGeoreference 对象,使相机聚焦到地图,地图显示如下。
可以看到,地图的方位已正确显示,用户如果对该方位还是不满意,在调整好视觉后,点击 Place Origin Here 按钮重置该视觉下的经度、纬度、高度,如下。
2)通过 tileset 文件中 transform 参数调整地图
在 CesiumLab地理信息基础数据处理平台使用手册 的 2.2.2.1 节 “输出数据的空间参考” 中,我们可以看到以下公式:
其中,3dtiles 里的 transform 矩阵是指切片文件中的 tileset.json 文件,如下。
可以看到 transform 矩阵是一个 4x4 的矩阵,并且最后一列的列向量是 [0, 0, 0, 1]',类似于平移矩阵的形式(平移矩阵详见空间和变换中 2.1.1 节,这篇文章的变换是列向量右乘,Cesium 中是行向量左乘),因此 transform 矩阵的最后一行是平移偏移量,我们将该偏移量设置到 Cesium Georeference 中,如下,地图显示效果同 4.4 1)节。
5 添加对象
5.1 CesiumGlobalAnchor
给场景中添加 DynamicCamera,并屏蔽掉 Main Camera,添加热气球对象,如下。
运行后,发现气球跟随相机一起运动,如下。
将气球对象移到 CesiumGeoreference 下面,并添加 CesiumGlobalAnchor 组件,如下。
运行效果如下,可以看到气球对象没有跟随相机一起运动了。
5.2 参考子场景
选中 CesiumGeoreference 对象,点击 Create Sub-Scene Here 添加子场景,CesiumGeoreference 对象下面会生成一个挂有 CesiumSubScene 组件的对象,重命名为 Sub-Scene。
调整 CesiumSubScene 组件中的 Activation Radius、Latitude、Longitude、Height 属性,如下。Latitude、Longitude、Height 确定了子场景的中心,Activation Radius 为子场景的半径,只有相机在子场景范围内,才激活子场景内的物体(子对象)。
将气球对象拖拽到 Sub-Scene 对象下面,如下(气球对象不需要挂 CesiumGlobalAnchor 组件)。
运行效果如下,可以看到,只有相机进入子场景范围内,才激活子场景内的物体(子对象)。
6 Native 编译
本节主要参考 Building Cesium for Unity。
1)编译环境准备
dotnet --version # 6.0 or later
cmake --version # 3.15 or later
Visual Studio 2022
Git Bash # 拉代码和编译命令都可以在 Git Bash里执行
2)拉 cesium-unity-samples 代码
cesium-unity-samples 源码。
git clone --recurse-submodules git@github.com:CesiumGS/cesium-unity-samples.git
3)拉 cesium-unity 代码
cesium-unity 源码。
cd cesium-unity-samples/Packages
git clone --recurse-submodules git@github.com:CesiumGS/cesium-unity.git com.cesium.unity
clone 时如果忘记添加 --recurse-submodules,可以通过以下命令递归拉取子模块依赖。
cd cesium-unity-samples/Packages/com.cesium.unity
git submodule update --init --recursive
注意:不要通过浏览器下载 cesium-unity 源码的 zip 文件,因为这样不会拉子模块代码,也不要试 图把所有子模块的 zip 文件下载下来后再合并,因为子模块太多了,有的子模块里面又包含子模块,很容易漏掉。cesium-unity 源码比较大,大概 1.89 GB(包含所有子模块),如果下载比较慢,可以使用 Git常用命令总结 中方法配置代理来加速下载。
以下是子模块的依赖文件。
com.cesium.unity\.gitmodules
com.cesium.unity\native~\extern\cesium-native\.gitmodules
com.cesium.unity\native~\extern\cesium-native\extern\draco\.gitmodules
com.cesium.unity\native~\extern\cesium-native\extern\earcut\.gitmodules
com.cesium.unity\native~\extern\cesium-native\extern\rapidjson\.gitmodules
com.cesium.unity.gitmodules 内容如下,可以看到 cesium-native 是 cesium-unity 的一个子模块,这正是我们要编译的 native 子模块。
[submodule "native~/extern/cesium-native"]
path = native~/extern/cesium-native
url = ../cesium-native.git
[submodule "native~/extern/tidy-html5"]
path = native~/extern/tidy-html5
url = https://github.com/htacg/tidy-html5.git
[submodule "native~/extern/enum-flags"]
path = native~/extern/enum-flags
url = https://github.com/grisumbras/enum-flags.git
4)构建 Reinterop
Reinterop 是一个 Roslyn(C# 编译器)源代码生成器,在编译 cesium-unity C# 代码时由 Unity 自动调用,并生成 C# 与 C++的交互层。
cd cesium-unity-samples/Packages/com.cesium.unity
dotnet publish Reinterop~ -o .
5)打开 cesium-unity-samples 项目
使用 Unity Editor 打卡 cesium-unity-samples 项目,Unity 将自动编译 cesium-unity C# 源代码,同时调用 Reinterop 生成 C# 和 C++ 源代码。此时 Cesium 的功能还不能正常使用,会抛出以下异常。这是因为 C++ 的代码还没编译。
DllNotFoundException: CesiumForUnityNative assembly:<unknown assembly> type:<unknown type> member:(null)
NotImplementedException: The native implementation is missing so OnValidate cannot be invoked.
生成的 C++ 源码地址为:com.cesium.unity/native~/build,用户可以通过 Visual Studio 打开 CesiumForUnityNative.sln 文件来查看源码。
6)编译 C++ 代码
关闭 cesium-unity-samples 项目,执行完以下命令行再打开项目。
构建 Debug 版本。
# compile the C++ code for use in the Editor
cd cesium-unity-samples/Packages/com.cesium.unity/native~
# 在 build 目录中生成 CMake 构建配置, 并将构建类型设置为 Debug, 以便在构建项目时启用调试信息(只需执行一次, 第二次编译时不需要执行该命令)
cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug
# 在 build 目录中执行构建操作, 使用 14 个构建线程并生成 Debug 版本的可执行文件或库, 将构建结果安装到 install 指向的目录中
cmake --build build -j14 --target install --config Debug
构建 Release 版本。
# build a release build
cd cesium-unity-samples/Packages/com.cesium.unity/native~
# 在 build 目录中生成 CMake 构建配置, 并将构建类型设置为 RelWithDebInfo, 它允许在 Release 版本中包含调试信息(只需执行一次, 第二次编译时不需要执行该命令)
cmake -B build -S . -DCMAKE_BUILD_TYPE=RelWithDebInfo
# 在 build 目录中执行构建操作, 使用 14 个构建线程并生成带有调试信息的 Release 版本的可执行文件或库, 将构建结果安装到 install 指向的目录中
cmake --build build -j14 --target install --config RelWithDebInfo
若在后面的编译过程中,报错:could not find any instance of Visual Studio,可以参考博客→解决CMake时“could not find any instance of Visual Studio”的问题。
7)查看安装目录
打开 com.cesium.unity/native~/CMakeLists.txt 文件,搜索 "CMAKE_INSTALL_PREFIX",如下。
# When building for the Editor, both Runtime and Editor assemblies are
# written to the Editor directory so that Unity won't load them in
# a standalone build.
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../Editor" CACHE PATH "Installed to the Editor directory." FORCE)
endif()
可以看到,安装目录为 "${CMAKE_CURRENT_LIST_DIR}/../Editor",即 com.cesium.unity/Editor 目录,由此得构建和安装的目录如下。
com.cesium.unity\native~\build\Editor\Debug\CesiumForUnityNative-Editor.dll ->
com.cesium.unity\Editor\CesiumForUnityNative-Editor.dll
com.cesium.unity\native~\build\Runtime\Debug\CesiumForUnityNative-Runtime.dll ->
com.cesium.unity\Editor\CesiumForUnityNative-Runtime.dll
7 修改 Native 代码案例
1)打开 native 源码工程
使用 Visual Studio 打开 CesiumForUnityNative.sln 文件来查看源码,如下。
2)修改源码
修改 CesiumForUnityNative-Runtime 模块下的 CesiumCreditSystemImpl.cpp 文件(源码位置:com.cesium.unity/native~/Runtime/src/CesiumCreditSystemImpl.cpp),如下。
3)编译源码
# compile the C++ code for use in the Editor
cd cesium-unity-samples/Packages/com.cesium.unity/native~
# 在 build 目录中生成 CMake 构建配置, 并将构建类型设置为 Debug, 以便在构建项目时启用调试信息(只需执行一次, 第二次编译时不需要执行该命令)
cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug
# 在 build 目录中执行构建操作, 使用 14 个构建线程并生成 Debug 版本的可执行文件或库, 将构建结果安装到 install 指向的目录中
cmake --build build -j14 --target install --config Debug
编译完成后,可以看到 com.cesium.unity/Editor/CesiumForUnityNative-Runtime.dll 文件修改日期发生变化。
4)修改前后对比
修改前底部有一行文字。
修改后底部文字消失。
声明:本文转自【Unity3D】Cesium加载大地图。