摘要:在 Cesium for Unity 场景中,普通 Unity 对象如果直接放在场景根节点,可能会随着 DynamicCamera 移动而出现“漂移”或“跟随相机”的现象。本文从
CesiumGeoreference、CesiumOriginShift和CesiumSubScene三者的关系出发,分析这一现象背后的坐标原点切换机制。

文章目录
问题现象
在 Cesium for Unity 示例场景中,通常会将 DynamicCamera 放在 CesiumGeoreference 节点下:
Scene
├── CesiumGeoreference
│ ├── DynamicCamera
│ ├── Cesium World Terrain
│ └── Cesium3DTileset
└── Cube

此时,如果在场景根节点创建一个普通 Cube,进入运行模式并控制相机移动,会发现一个异常现象:
Cube 看起来会跟随相机移动
或者
Cube 相对于地球场景发生漂移
但 Cube 并不是相机的子节点,Transform 也没有主动更新。

之后,通过 CesiumGeoreference 组件上的 Create Sub-Scene Here 按钮创建 CesiumSubScene,再将 Cube 挂载到 SubScene 下:

Scene
└── CesiumGeoreference
├── DynamicCamera
├── Cesium World Terrain
└── Local Sub-Scene
└── Cube
再次运行,Cube 不再发生漂移。
这并不是 SubScene 简单地“锁定了 Cube”,而是因为它改变了当前区域内的原点管理方式。
原因分析
1.CesiumGeoreference 不只是一个普通父节点
普通 Unity 场景使用一个固定的世界坐标系,场景原点始终是:
World Origin = (0, 0, 0)
但 Cesium 面向的是地球级场景。
地球半径约为数百万米,而 Unity 的 Transform 使用单精度浮点数。在距离 Unity 原点很远时,坐标精度会逐渐下降,最终表现为模型抖动、顶点闪烁、物理不稳定等问题。
CesiumGeoreference 的作用,是将某个真实地理位置映射到 Unity 场景的原点,并在 ECEF 地心地固坐标与 Unity 本地坐标之间进行转换。在默认的局部坐标中,X 指向东,Y 指向上,Z 指向北。([Cesium][1])
可以简单理解为:
真实地球坐标
↓
CesiumGeoreference
↓
Unity 原点附近的局部坐标
所以,CesiumGeoreference 定义的并不是一个固定不变的普通坐标空间,而是“当前 Unity 原点对应地球上的什么位置”。
2.真正导致 Cube 漂移的是 CesiumOriginShift

Cesium 示例中的 DynamicCamera 通常包含:
DynamicCamera
├── Camera
├── CesiumCameraController
├── CesiumGlobeAnchor
└── CesiumOriginShift
其中,CesiumOriginShift 会监控相机与 Unity 原点之间的距离。
当相机移动超过指定距离时,CesiumOriginShift不会继续让相机的 Unity 坐标无限增大,而是修改 CesiumGeoreference 的原点,使 Unity 原点重新移动到相机附近。这样可以让相机附近的对象始终保持较小的坐标值,从而提高渲染精度。
从视觉上看,是相机正在地球上向前飞行;但从 Unity 坐标系的角度看,更接近下面这种过程:
相机向前移动
↓
相机离 Unity 原点过远
↓
CesiumOriginShift 修改 Georeference 原点
↓
相机重新回到 Unity 原点附近
↓
Cesium 地球内容根据新原点重新计算位置
也就是说,Cesium 使用了一种类似“浮动原点”的机制:
例如,调节Distance,相机则在移动距离大于12米时,触发原点修正。
不是让相机无限远离原点,
而是让坐标原点不断跟随相机。
官方文档也说明,CesiumOriginShift 通常挂载在相机上,并通过不断调整 CesiumGeoreference 原点,将相机附近的坐标值控制在较小范围内。(Cesium)
3.为什么根节点 Cube 会看起来跟随相机
根节点 Cube 只是普通 Unity 对象:
Cube
└── Transform
它没有:
CesiumGlobeAnchor
CesiumSubScene
因此,它只知道自己的 Unity 世界坐标,例如:
Position = (0, 1, 5)
但是它并不知道这个坐标在地球上对应哪个经纬度。
当 CesiumOriginShift 修改 CesiumGeoreference 原点时,Cesium 地形、3D Tiles、DynamicCamera 和带有 CesiumGlobeAnchor 的对象都会根据新的原点重新计算 Unity Transform。
普通 Cube 则不会参与这次地理坐标重算。
于是出现了两套不同的对象行为:
Cesium 对象:
保存全球坐标
Georeference 改变后重新计算 Unity Transform
普通根节点 Cube:
只保存 Unity Transform
Georeference 改变后位置保持不变
由于相机也被持续维持在 Unity 原点附近,而 Cube 同样保持在原来的 Unity 世界坐标附近,所以从相机视角观察,Cube 就像一直跟着相机移动。
实际上并不是 Cube 被移动了,而是:
Cube 的 Unity 坐标没变,
但 Unity 坐标系在地球上的对应位置变了。
Cesium 官方文档明确指出,启用原点移动后,基于旧 Unity 坐标系定义的普通对象 Transform 会失效;没有被注册到地理参考系统中的对象,可能在原点改变时被放置到错误的位置。
4.为什么放入 CesiumSubScene 后不再漂移
点击 Create Sub-Scene Here 后,Cesium 会创建一个带有 CesiumSubScene 组件的对象。
创建时,Cesium 会将当前编辑器相机的位置转换为全球坐标,并将这个位置设置为 SubScene 的地理原点。同时,父级 CesiumGeoreference 的原点也会被设置到相同位置。(Cesium)
一个 SubScene 可以理解成地球上的一块“局部 Unity 场景中心”:
全球 Cesium 场景
└── 某个确定的地理位置
└── 局部 SubScene
├── Cube
├── Character
├── Rigidbody
├── Collider
└── ParticleSystem

当带有 CesiumOriginShift 的相机进入 SubScene 的 Activation Radius 后,Cesium 会执行以下操作:
1. 激活当前 SubScene
2. 将 CesiumGeoreference 原点设置为 SubScene 原点
3. 暂停相机驱动的连续 Origin Shift
4. 启用 SubScene 内部的对象
官方文档明确说明:相机位于 SubScene 内部时,普通的原点移动不会继续执行,从而允许开发者在该区域内使用相对正常的 Unity 场景逻辑。([Cesium][2])
因此,将 Cube 放入 SubScene 后,运行期间的坐标关系变为:
CesiumGeoreference 原点
↓ 固定在 SubScene 中心
CesiumSubScene
↓
Cube.localPosition
只要相机仍处于该 SubScene 的激活范围内,Georeference 原点就不会持续跟随相机移动。
Cube 的局部坐标所依赖的参考系变得稳定,因此不再出现跟随相机漂移的现象。
解决方案
这里需要特别区分两种解决方案。
CesiumGlobeAnchor
CesiumGlobeAnchor 用于将单个对象绑定到一个确定的全球位置。
它会保存对象的高精度全球坐标。当 CesiumGeoreference 原点改变时,GlobeAnchor 会根据保存的全球坐标重新计算对象的 Unity Transform,使对象仍然位于正确的地理位置。
适合:
地理标注
兴趣点
全球分布的模型
经纬度定位对象
需要跨区域持续存在的对象
推荐结构:
CesiumGeoreference
└── BuildingAnchor
├── CesiumGlobeAnchor
└── Building
CesiumSubScene
CesiumSubScene 不是给所有子对象分别保存全球坐标,而是为一组对象建立一个局部地理原点。

它的目的,是让一个局部区域内的对象像普通 Unity 场景一样运行。官方将其定位为全球地理位置与局部 Unity 功能之间的一种折中方案。

适合:
建筑内部场景
城市中的局部交互区域
带有 Rigidbody 的物理场景
角色活动区域
数字孪生园区
局部粒子、动画和特效系统
推荐结构:
CesiumGeoreference
├── DynamicCamera
├── Global Tilesets
└── Factory SubScene
├── CesiumSubScene
├── Building
├── Cube
├── Character
└── PhysicsObjects
二者的核心区别可以概括为:
| 方案 | 管理对象 | 原点变化时的处理方式 | 典型用途 |
|---|---|---|---|
CesiumGlobeAnchor | 单个对象或对象组根节点 | 根据全球坐标更新 Transform | 全球定位对象 |
CesiumSubScene | 一个局部区域 | 激活后固定局部原点,暂停 Origin Shift | 局部交互和物理场景 |
| 普通 Transform | 普通 Unity 坐标 | 不响应 Georeference 变化 | 仅适合固定原点的小范围场景 |
注意事项
1.SubScene 的激活范围需要注意
CesiumSubScene 中有一个重要参数:
Activation Radius
它表示相机距离 SubScene 原点多近时,SubScene 才会被激活。
当相机进入该范围:
SubScene 激活
原点切换到 SubScene 原点
Origin Shift 暂停
子对象启用
当相机离开该范围:
SubScene 禁用
子对象禁用
Origin Shift 恢复
Georeference 原点重新跟随相机
CesiumSubScene 官方类说明也指出,当带有 CesiumOriginShift 的对象靠近 SubScene 时,该 SubScene 会被激活,其他 SubScene 会被禁用;如果多个 SubScene 激活范围重叠,通常会优先选择距离更近的一个。([Cesium][7])
因此,使用时要避免以下问题:
Activation Radius 过小:
相机轻微移动后 SubScene 突然被关闭
Activation Radius 过大:
原点长时间固定,远离中心后精度逐渐下降
多个 SubScene 范围严重重叠:
可能频繁切换当前激活区域
局部园区、建筑或者交互区域,应根据实际活动半径设置合理范围。
2.推荐的 Cesium 场景组织方式
对于包含全球地形、城市数据和局部 Unity 交互内容的项目,可以采用以下结构:
Scene
└── CesiumGeoreference
├── DynamicCamera
│ ├── CesiumGlobeAnchor
│ └── CesiumOriginShift
│
├── Cesium World Terrain
├── Photogrammetry Tileset
├── OSM Buildings
│
├── CityA SubScene
│ ├── CesiumSubScene
│ ├── Building
│ ├── Character
│ └── InteractionObjects
│
└── GlobalPOI
├── CesiumGlobeAnchor
└── Marker
场景划分原则如下:
全球地理对象
使用 CesiumGlobeAnchor
局部完整场景
使用 CesiumSubScene
UI、准星、相机附件
放在 Camera 或 XR Origin 下
不需要地理定位的管理对象
可以放在场景根节点,但不要依赖其世界位置
总结
根节点 Cube 跟随 DynamicCamera,并不是 Unity 的父子关系异常,也不是相机控制脚本主动修改了 Cube。
真正原因是:
DynamicCamera 上的 CesiumOriginShift
持续修改 CesiumGeoreference 原点
普通 Cube 没有全球坐标信息
无法在原点变化后重新计算 Transform
相机和 Cube 都保持在 Unity 原点附近
因此视觉上像是 Cube 跟随相机移动
将 Cube 放入 CesiumSubScene 后,Cesium 会在相机进入激活范围时,将 Georeference 原点固定到 SubScene 的地理位置,并暂停常规的 Origin Shift。
因此:
SubScene 提供了稳定的局部坐标系,
Cube 可以继续按照普通 Unity Transform 工作,
从而不再出现漂移。
对于 Cesium for Unity 项目,不能只考虑 Unity 层级关系,还需要明确对象属于哪一种坐标体系:
普通 Unity 局部坐标
全球地理坐标
还是 SubScene 局部地理坐标
一旦这三种坐标关系划分清楚,类似的模型漂移、物理跳动和相机跟随问题就会更容易定位。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_41140324/article/details/163052303





