Skip to content

RoamEffect 相机跟随漫游(路径巡航 + 相机跟随)

把一组路径点 + 移动速度换算成时间轴,驱动漫游实体沿路径移动,并通过 viewer.trackedEntity相机自动跟随——第一/第三人称视角沿真实路径巡航。对齐源案例 TrackRoam/Roam1loop 支持循环漫游,可叠加全路径发光轨迹线与可选跟随模型。

纯相机漫游(不传 modelUri)时自动在漫游实体上挂一个黄色跟随点标记:它既是 Cesium 相机跟随的包围球来源(见下方「实现说明」),也直观标出漫游当前位置。


能力定位

RoamEffect 适合:

  • 巡检漫游 / 数字孪生大屏巡航:沿既定路线自动飞行,相机自动跟随;
  • 历史轨迹复盘:按真实路径与速度重放运动过程,loop 循环播放;
  • 第一/第三人称漫游:可选 modelUri 挂载跟随模型(如车辆),实现带车头的视角跟随。

与同类能力的分工:

能力API行为
相机跟随漫游(本类)RoamEffectSampledPositionProperty 时间轴驱动实体 + 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
}
参数类型默认值描述
positionsCartesian3[](必填)漫游路径点(≥2 点;每点需为有限坐标的 Cartesian3,含 NaN/Infinity 抛错)
speednumber25移动速度(米/秒),必须为正数
loopbooleantrue循环漫游;false 时播放一次后在终点停止
showPathbooleantrue是否绘制全路径发光轨迹线
pathColorColorColor.YELLOW轨迹线颜色
pathWidthnumber10轨迹线宽度(像素)
pathGlowPowernumber0.1轨迹线辉光强度
modelUristring(无)可选跟随模型 URI;不传则不创建模型(纯相机漫游)
modelScalenumber1跟随模型缩放

生命周期与操作

实现 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.trackedEntityviewer.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.AQUApathWidth: 6pathGlowPower: 0.3
  • 隐藏轨迹线showPath: false → 只保留漫游实体与相机跟随,不画路径。

实现说明

  • 距离计算:用 EllipsoidGeodesic.surfaceDistance 求两点大地线地表距离,再与高度差合成欧氏距离 (对齐源案例 spaceDistance,并修复其 toFixed(2) 返回字符串导致的「数字 + 字符串」拼接缺陷,返回 number);
  • 采样时间轴:按 distance / speed 逐点累加得到每个采样点相对 startTime 的秒数,写入 SampledPositionProperty;实体 position 随时间插值运动,orientationVelocityOrientationProperty 跟随方向;
  • 相机跟随viewer.trackedEntity 的逐帧跟随依赖 getBoundingSphere 返回 DONE(Cesium 1.133.1 CesiumWidget._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 点,每点为有限坐标的 Cartesian3speed 必须 > 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。