Appearance
RoamEffect 相机跟随漫游(路径巡航 + 相机跟随)
把一组路径点 + 移动速度换算成时间轴,驱动漫游实体沿路径移动,并通过
viewer.trackedEntity让相机自动跟随——第一/第三人称视角沿真实路径巡航。对齐源案例TrackRoam/Roam1;loop支持循环漫游,可叠加全路径发光轨迹线与可选跟随模型。纯相机漫游(不传
modelUri)时自动在漫游实体上挂一个黄色跟随点标记:它既是 Cesium 相机跟随的包围球来源(见下方「实现说明」),也直观标出漫游当前位置。
能力定位
RoamEffect 适合:
- 巡检漫游 / 数字孪生大屏巡航:沿既定路线自动飞行,相机自动跟随;
- 历史轨迹复盘:按真实路径与速度重放运动过程,
loop循环播放; - 第一/第三人称漫游:可选
modelUri挂载跟随模型(如车辆),实现带车头的视角跟随。
与同类能力的分工:
| 能力 | API | 行为 |
|---|---|---|
| 相机跟随漫游(本类) | RoamEffect | SampledPositionProperty 时间轴驱动实体 + trackedEntity 相机跟随 + 可叠加发光轨迹线 |
| 轨迹回放 + 尾迹 | TrailLineEffect | 同样基于时间轴,但开启/不开启相机跟随,轨迹为 CallbackProperty 尾迹(俯瞰观察用) |
两者的机制底座相同(路径 + 速度 → 采样时间轴 → 实体沿路径运动)。
RoamEffect的独有增量是 相机跟随视角(viewer.trackedEntity)+ 循环漫游(loop)。
构造函数
ts
constructor(options: RoamEffectOptions)ts
interface RoamEffectOptions {
positions: Cartesian3[] // 漫游路径点(世界坐标,至少 2 个点),必填
speed?: number // 移动速度(米/秒),默认 25
loop?: boolean // 是否循环漫游,默认 true
showPath?: boolean // 是否绘制全路径轨迹线,默认 true
pathColor?: Color // 轨迹线颜色,默认 Color.YELLOW
pathWidth?: number // 轨迹线宽度(像素),默认 10
pathGlowPower?: number // 轨迹线辉光强度,默认 0.1
modelUri?: string // 可选跟随模型 URI(glTF/glb),缺省纯相机漫游
modelScale?: number // 跟随模型缩放,默认 1
}| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
positions | Cartesian3[] | (必填) | 漫游路径点(≥2 点;每点需为有限坐标的 Cartesian3,含 NaN/Infinity 抛错) |
speed | number | 25 | 移动速度(米/秒),必须为正数 |
loop | boolean | true | 循环漫游;false 时播放一次后在终点停止 |
showPath | boolean | true | 是否绘制全路径发光轨迹线 |
pathColor | Color | Color.YELLOW | 轨迹线颜色 |
pathWidth | number | 10 | 轨迹线宽度(像素) |
pathGlowPower | number | 0.1 | 轨迹线辉光强度 |
modelUri | string | (无) | 可选跟随模型 URI;不传则不创建模型(纯相机漫游) |
modelScale | number | 1 | 跟随模型缩放 |
生命周期与操作
实现 Lifecycle<Viewer> 契约,on/off/destroy 均幂等:
ts
on(viewer: Viewer): void // 创建漫游实体 → viewer.trackedEntity = 漫游实体 → 接管 viewer.clock 时间轴播放
off(viewer: Viewer): void // 移除 onTick 监听、移除漫游实体、恢复被接管的 trackedEntity 与 clock 原值
destroy(viewer: Viewer): void // 等价于 off(幂等)状态接管与恢复:on 时保存 viewer.trackedEntity 与 viewer.clock(start/stop/currentTime、 clockRange、multiplier、shouldAnimate)原值;off/destroy 原样恢复。绝不 removeAll 触碰调用方实体。
基础示例
ts
import { RoamEffect } from '@nexa/gis-cesium'
// 漫游路径(成都二环上空 3000m 矩形环线)
const positions = [
Cesium.Cartesian3.fromDegrees(104.02, 30.62, 3000),
Cesium.Cartesian3.fromDegrees(104.1, 30.62, 3000),
Cesium.Cartesian3.fromDegrees(104.1, 30.7, 3000),
Cesium.Cartesian3.fromDegrees(104.02, 30.7, 3000),
]
// 先高空俯瞰环线,随后相机自动跟随漫游实体沿路径巡航
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(104.06, 30.66, 45000),
orientation: { heading: 0, pitch: -Cesium.Math.PI_OVER_TWO, roll: 0 },
})
const effect = new RoamEffect({
positions,
speed: 180, // 米/秒
loop: true, // 循环漫游直到 destroy
})
effect.on(viewer)
// 页面或场景退出时由创建方负责清理(幂等)
effect.destroy(viewer)进阶示例
- 播放一次后停止:
loop: false→ 到达终点后shouldAnimate自动置为false,不再重置回起点; - 带跟随模型:
modelUri: '/models/car.glb'、modelScale: 0.1→ 漫游实体挂载车辆模型,视角跟随车头方向 (VelocityOrientationProperty依据运动方向自动定向); - 自定义轨迹线:
pathColor: Color.AQUA、pathWidth: 6、pathGlowPower: 0.3; - 隐藏轨迹线:
showPath: false→ 只保留漫游实体与相机跟随,不画路径。
实现说明
- 距离计算:用
EllipsoidGeodesic.surfaceDistance求两点大地线地表距离,再与高度差合成欧氏距离 (对齐源案例spaceDistance,并修复其toFixed(2)返回字符串导致的「数字 + 字符串」拼接缺陷,返回number); - 采样时间轴:按
distance / speed逐点累加得到每个采样点相对startTime的秒数,写入SampledPositionProperty;实体position随时间插值运动,orientation由VelocityOrientationProperty跟随方向; - 相机跟随:
viewer.trackedEntity的逐帧跟随依赖getBoundingSphere返回DONE(Cesium 1.133.1CesiumWidget._onTick仅在此时调用EntityView.update)——PathVisualizer没有getBoundingSphere, 因此仅 position+path 的实体会让相机只定位一次、随后冻结。纯相机漫游(无modelUri)时在实体上自动挂一个 黄色跟随点标记(PointVisualizer提供逐帧包围球,同时标出当前位置),并设置viewFrom相机跟随偏移 (实体局部 ENU 帧东/北/上 = 0 / -1500 / 800,抬高后置获得巡航视角);传modelUri时由模型自身提供 包围球,不额外挂点(对齐源案例 Roam1 的车辆模型跟随); - 循环漫游:
clockRange = CLAMPED+clock.onTick监听,到达stopTime时若loop重置回startTime继续循环,否则停shouldAnimate; - 轨迹线:
path不显式设positions(复用实体position属性 + 默认trailTime尾迹), 材质为PolylineGlowMaterialProperty(YELLOW / 10px / glowPower 0.1); - 资源所有权:
on保存 viewer 全局状态(trackedEntity+clock),off/destroy恢复原值, 只移除自建漫游实体,绝不removeAll触碰调用方实体。
清理责任
ts
effect.destroy(viewer) // 或 effect.off(viewer),等价且幂等重复调用 destroy/off 安全(未 on 时为空操作)。destroy 后重新 on 可再次漫游。 loop: false 播放结束后,再次 off/on 会从起点重新播放。
限制与组合
- 路径点要求:
positions至少 2 点,每点为有限坐标的Cartesian3;speed必须 > 0; - 纯相机漫游:不依赖 3D Tiles / 模型资产,任何底图上均可运行(示例用内置单图底图);
- 与
DrawManager组合:可让用户在地图上绘制路径后漫游:drawManager.onDrawComplete(({ positions }) => new RoamEffect({ positions, speed: 50 }).on(viewer)); - 与
TrailLineEffect(轨迹回放尾迹)共享时间轴底座,但开启相机跟随为RoamEffect独有——两者不宜同时 作用于同一路径,相机跟随会接管视角。
Cesium 版本限制
- 依赖 Cesium 公共
SampledPositionProperty/VelocityOrientationProperty/EllipsoidGeodesic/Clock/ClockRange/PolylineGlowMaterialProperty,不使用私有 API; - 已验证目标版本:Cesium 1.133.1。