EQ-雪梨蛋花汤头像
关注
【Cesium for Unity】普通 Cube 为何会跟随相机漂移?CesiumOriginShift 与 SubScene 原点机制解析封面图

【Cesium for Unity】普通 Cube 为何会跟随相机漂移?CesiumOriginShift 与 SubScene 原点机制解析

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

问题现象

在 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

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--