开源|cesium自主漫游实战教程(附完整源码)②
接上文;本文介绍一下关于汽车位置的计算
关于汽车的位置计算:
我们可以使用之前学过的本地坐标的计算方法,首先计算前一帧小车的位置,然后根据这个坐标得到模型矩阵,然后再通过小车的朝向与速度,计算下一帧的位置

在监听事件中添加前进和后退的逻辑
// 开始自主漫游
startRoam() {
if (this.carEntity) {
document.addEventListener("keydown", this.keyDonwCallback.bind(this));
document.addEventListener("keyup", this.keyUpCallback.bind(this));
this.roamEvent = () => {
this.traceHandler();
if (this.flag.moveLeft) {
this.hpRoll.heading -= this.radian;
}
if (this.flag.moveRight) {
this.hpRoll.heading += this.radian;
}
if (this.flag.moveUp) {
this.moveCar(1);
}
if (this.flag.moveDown) {
this.moveCar(-1);
}
};
this.viewer.clock.onTick.addEventListener(this.roamEvent);
}
}
代码功能解读
该代码段实现了一个名为startRoam()的方法,用于启动一个基于键盘交互的自主漫游功能。核心功能包括键盘事件监听和根据按键状态更新物体运动。
代码结构分析
键盘事件监听
通过document.addEventListener绑定keydown和keyup事件,分别调用keyDonwCallback和keyUpCallback方法(注意拼写错误应为keyDownCallback)。这两个方法用于设置移动方向标志位(如this.flag.moveLeft)。
漫游逻辑执行this.roamEvent是一个箭头函数,会在每次时钟 tick 时触发:
- 调用
traceHandler()处理轨迹逻辑(具体实现未展示)。 - 根据方向标志位更新物体的旋转角度或位移:
- 左/右键调整
this.hpRoll.heading角度(this.radian为旋转弧度值)。 - 上/下键调用
moveCar()方法控制前后移动(参数1和-1表示方向)。
- 左/右键调整
时钟事件绑定
通过this.viewer.clock.onTick.addEventListener将漫游逻辑绑定到时钟的 tick 事件,实现逐帧更新。
关键变量说明
this.carEntity:被控制的物体对象(如车辆模型)。this.flag:存储按键状态的标志位对象(需外部初始化)。this.hpRoll.heading:物体的水平旋转角度。this.radian:单次旋转的弧度增量。this.moveCar():控制物体移动的方法(参数为方向系数)。
典型应用场景
适用于 3D 场景中的交互式物体控制(如游戏角色、模拟驾驶),需配合以下外部实现:
- 方向标志位(
this.flag)的初始化与管理。 moveCar()方法的具体移动逻辑。- 视图对象(
this.viewer)的时钟系统支持。
其中moveCar函数,处理小车的位置逻辑
具体逻辑如下:
-
我们将当前小车的位置clone一份,用来计算下一帧小车会出现的位置
-
通过当前小车的速度,如果isUp为true,说明按下的是前进键,这时候我们会得到一个X轴方向的向量,这个向量的模为速度*时间,同理,如果是后退,我们将朝着-X轴构造一个向量
-
根据当前的hpRoll小车朝向,以及当前的世界坐标clonePosition,通过headingPitchRollToFixedFrame构造一个方向和hpRoll一致的模型矩阵
-
通过模型矩阵左乘我们刚刚构造出来的向量,得到下一帧小车的位置position
-
然后把position丢给sampleHeight处理一下真实的地形高度,避免小车跑到地下去
-
还可以对比上一帧和下一帧的位置地形高,做一个碰撞检测
moveCar(isUp) {
const clonePosition = _.clone(this.position);
const {height:prevHeight}=this.setHeight(clonePosition)
// 位移的距离
const distance = this._speed / 20;
let speedVectorX = new Cesium.Cartesian3();
// 计算速度矩阵x轴方向
if (isUp > 0) {
speedVectorX = Cesium.Cartesian3.multiplyByScalar(
Cesium.Cartesian3.UNIT_X,
distance,
speedVectorX
);
} else if (isUp < 0) {
speedVectorX = Cesium.Cartesian3.multiplyByScalar(
Cesium.Cartesian3.UNIT_X,
-distance,
speedVectorX
);
} else {
speedVectorX = Cesium.Cartesian3.multiplyByScalar(
Cesium.Cartesian3.UNIT_X,
0,
speedVectorX
);
}
let fixedFrameTransforms =
Cesium.Transforms.localFrameToFixedFrameGenerator("east", "north");
let modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
clonePosition,
this.hpRoll,
Cesium.Ellipsoid.WGS84,
fixedFrameTransforms
);
let position = Cesium.Matrix4.multiplyByPoint(
modelMatrix,
speedVectorX,
new Cesium.Cartesian3()
);
const { lng: lng1, lat: lat1, height: real } = this.setHeight(position);
const heightDiff=real-prevHeight
// 碰撞检测
if(heightDiff>1){
return
}
this.position = Cesium.Cartesian3.fromDegrees(lng1, lat1, real);
}
代码功能概述
这段代码属于三维场景(基于Cesium.js)中控制车辆移动的逻辑,主要实现以下功能:
- 根据输入参数
isUp决定车辆的移动方向(前进/后退/停止) - 计算位移距离并生成速度向量
- 通过局部坐标系转换处理车辆姿态(考虑航向、俯仰、横滚角)
- 执行碰撞检测(高度差限制)
- 更新车辆位置
核心逻辑分解
变量初始化
const clonePosition = _.clone(this.position);
const {height:prevHeight} = this.setHeight(clonePosition);
- 深拷贝当前车辆位置对象,避免直接修改原始数据
setHeight方法提取当前位置的海拔高度并保存为prevHeight
位移计算
const distance = this._speed / 20;
let speedVectorX = new Cesium.Cartesian3();
- 根据速度
this._speed计算帧位移量(假设20为帧率调节系数) - 初始化空的三维向量
speedVectorX用于存储速度方向
方向控制
if (isUp > 0) {
speedVectorX = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.UNIT_X, distance, speedVectorX);
} else if (isUp < 0) {
speedVectorX = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.UNIT_X, -distance, speedVectorX);
}
isUp > 0:车辆前进,沿X轴正方向移动isUp < 0:车辆后退,沿X轴负方向移动- 未处理
isUp = 0的情况(默认速度向量为0)
坐标系转换
let fixedFrameTransforms = Cesium.Transforms.localFrameToFixedFrameGenerator("east", "north");
let modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
clonePosition,
this.hpRoll,
Cesium.Ellipsoid.WGS84,
fixedFrameTransforms
);
- 生成东北天(ENU)局部坐标系到固定坐标系的转换矩阵
- 根据车辆的航向角(
heading)、俯仰角(pitch)、横滚角(roll)构建模型矩阵
位移应用
let position = Cesium.Matrix4.multiplyByPoint(modelMatrix, speedVectorX, new Cesium.Cartesian3());
- 将速度向量从局部坐标系转换到全局坐标系
- 计算结果存储在
position中
碰撞检测
const { lng: lng1, lat: lat1, height: real } = this.setHeight(position);
const heightDiff = real - prevHeight;
if(heightDiff > 1) return;
- 计算移动后的新位置海拔高度
- 若高度差超过阈值
1(单位:米),判定为碰撞并终止移动
位置更新
this.position = Cesium.Cartesian3.fromDegrees(lng1, lat1, real);
- 将经纬度和高度转换为
Cartesian3坐标并更新车辆位置
关键依赖说明
- Cesium.js:提供三维地理空间计算能力(坐标系转换、向量运算等)
- Lodash (
_.clone):用于深拷贝对象 - 坐标系约定:
- 局部坐标系:X轴为东,Y轴为北,Z轴为天(ENU)
- 全局坐标系:WGS84椭球体下的笛卡尔坐标
改进建议
- 参数校验:检查
isUp是否为数字类型 - 停止状态显式处理:
else分支可添加日志或状态标记 - 高度差阈值可配置化:将
1改为变量提升灵活性 - 错误处理:捕获
setHeight或矩阵运算可能出现的异常
完整代码:
最后我们可以将自主漫游封装为一个class,方便调用
由于文章篇幅有限
需要完整代码的同学+小编无偿分享

PS:本文为新中地原创,转载请标注来源。
本文学习前提需要具备一定的GIS开发能力,若你还不熟悉 Cesium 基础,建议学习《Cesium 零基础入门教程》,掌握坐标转换、图元操作等知识,助力理解标绘原理!

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)