Cesium学习笔记——glb/gltf小车模型沿轨迹运动及封装

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在Cesium的学习中,学会读文档十分重要!!!在这里附上中文文档Cesium中文文档1.95
在Cesium中进行沿轨迹运动比较简单,大致分5步,先加载小车模型,然后设置当前的时间及开始时间,接下来加入轨迹点,并对其插值,然后为轨迹动画加入时间,最后为小车模型加入轨迹和朝向即可。
小车运动效果
最终效果

一、加载小车模型

我们利用viewer.entitis.add来加载模型,在这里先查看官方文档了解一下
查看文档,在viewer中
从viewer中可以找到其属性entities,中文文档描述为获取未绑定到特定数据源的实体集合,可能在这里还难以理解(可能中文文档是社区直译过来的),我们点击右侧的EntityCollection进去看看
EntityCollection
结合这里可以看出,这里是展示在地球中的entity的集合,也就是说可以通过将模型加入这个集合来展示到地球中,这正是我们需要的。查看其方法可以看见一个add方法,其可以将entity加入此集合,返回该entity对象。
add方法
所以,要展示小车模型,需先将小车模型转为entity,再加入EntityCollection。那么该如何将小车模型转为entity呢。我们点进entity看看。
entity
简单了解到entity其实就是可以展示在地球上的实体对象,在其中我们注意到一个属性model,用来设置或获取模型。
model
model
浏览文档可以发现,这正是我们要找的gltf/glb模型,其中可以通过uri属性加入路径中的模型文件,因此加入小车模型就变的简单了。这里加入minimumPixelSize和 maximumScale属性方便浏览小车模型,还可以为其添加position属性,可以看见小车的初始位置

const entityMotion = viewer.entities.add(
    new Cesium.Entity({
        model: {
            uri: url,// 模型路径
            minimumPixelSize: 128,// 最小像素大小
            maximumScale: 20000,// 最大比例尺
        },
    })
);

二、设置当前及开始时间

Cesium的动画与时间息息相关,因此我们要为运动轨迹添加起始时间及当前时间,并开启场景动画。时间可以在viewer的clock设置(这里相当于将获取与viewer绑定的clock对象),这里把起始时间和当前时间都设置成了现在的时间,Cesium.JulianDate是表示天文儒略日期,即自 -4712 年 1 月 1 日(公元前 4713 年)中午以来的天数,now获取当前的时间,clock对象的几个属性(startTime,currentTime等)的类型都是Cesium.JulianDate。
clock时间

//开启动画
viewer.clock.shouldAnimate = true;
//设置当前时间
viewer.clock.currentTime = Cesium.JulianDate.now();
//设置起始时间
const startTime = Cesium.JulianDate.now();

这里我们把起始时间先存起来,方便后续设置轨迹动画的时间

三、加入轨迹点,并对其插值

加入轨迹点的部分比较关键,首先,咱们先简单了解一下Cesium里的坐标系统里的两种,一个是三维笛卡尔坐标,一个是地理坐标系,三维笛卡尔坐标是椭球中心为原点的空间直角坐标系,在Cesium是通过 new Cesium.Cartesian3(x,y,z)创建,地理坐标系则是默认为wgs84为参考,通过new Cesium.Cartographic (lon,lat,height)创建。但是,在进行计算时,笛卡尔坐标更方便,因此,在Cesium中,entity的position属性的类型是PostionProperty,

position
再看看PositionProperty,‌它是用来定义实体在场景中位置的属性,它可以表示一个静态位置、一个随时间变化的位置,或者其他位置属性‌‌,也就是Cartesian3笛卡尔三维坐标系下的坐标与时间的集合。因此如果是坐标经纬度我们则需要将其转换为笛卡尔坐标(坐标系在我后面的专栏中会介绍)。
PositionProperty

在这里我们先假设一些轨迹点的笛卡尔三维坐标。假设小车的轨迹正是沿这些点运动。

const pos = [
    { "x": 211806.85957262348, "y": -5014329.870144445, "z": 3922801.0928523946 },
    { "x": 577385.9583266769, "y": -4938316.887198847, "z": 3981533.981599306 },
    { "x": 750598.459437521, "y": -4990762.968138716, "z": 3886760.285356019 },
    { "x": 592151.816210726, "y": -5114279.084725079, "z": 3752163.222673417 },
    { "x": 288850.23764454946, "y": -5133829.536730374, "z": 3761092.1832171273 }
];

但是如果直接为这些点附上时间会存在一些问题,因为小车直接沿两点间进行直线运动,因此小车可能会进入地球内部。所以我们在这里可以为点进行插值,并将其放入一个新数组中。在Cesium中有一个内置的线性插值静态函数。
线性插值函数
我们可以根据距离插值,也可以按特定数量插值,这里为了方便,我们为每个两点间插入98个点

const postions = [];
for (let i = 0; i < pos.length - 1; i++) {
    for (let j = 0; j <= 1; j += 0.01) {
        postions.push(Cesium.Cartesian3.lerp(pos[i], pos[i + 1], j, new Cesium.Cartesian3()));
    }
}

四、为轨迹动画加入时间

接下来是为上面的插值点加入时间,加入时间,小车才能从当前时间所在点运动到下一时间所在点。从上一节可以知道,小车的轨迹Position的类型是PositionProperty,但PositionProperty只是一个接口,SampledPositionProperty是这个接口的具体实现对象。
SampledPositionProperty
上一节已经实现了坐标插值,现在要对每个坐标加入时间。我们通过JulianDate的静态方法addSeconds来加入秒数,并将对应的坐标通过addSample方法来添加样本对象。
加入时间

const positionProperty = new Cesium.SampledPositionProperty();
postions.forEach((poss, index) => {
    const time = Cesium.JulianDate.addSeconds(startTime, index, new Cesium.JulianDate());
    positionProperty.addSample(time, poss);
})

五、为小车模型加入轨迹和朝向

最后,我们将轨迹加入小车,并根据轨迹计算小车的朝向。

entityMotion.position = positionProperty;
const orientationProperty = new Cesium.VelocityOrientationProperty(positionProperty);
entityMotion.orientation = orientationProperty;

为了方便显示,我们还可以显示线轨迹

viewer.entities.add({
    polyline: {
        positions: pos,
        clampToGround: true, //贴地
        width: 3,
        material: new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.YELLOW,
        }),
        depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.YELLOW,
        }),
    },
})

最终结果如下
小车运动

六、代码封装

上面已经完成了小车运动的基本功能,但是,上面的代码都是写死的,为了方便代码复用,我们可以对以上代码进行封装。
首先,设计一个构造函数

export default class Motion {
    /**
     * 
     * @param {*} viewer Cesium.Viewer
     */
    constructor(viewer) {
        this.viewer = viewer;
        this._entityMotion = null// 运动的模型
        this._postions = [];//运动轨迹
    }
 }

然后就是添加运动模型

    /**
    * 添加运动模型
    * @param {*} entity 运动的模型
    */
   addModle(entity) {
       this._entityMotion = this.viewer.entities.add(entity);
   }
   ```
开始运动
    /**
    * 开始运动
    * @param {*} positions 运动轨迹(点)
    */
   startMotion(positions) {
       if (!this.viewer.clock.shouldAnimate) {
           this.viewer.clock.shouldAnimate = true;
       }
       this.viewer.clock.currentTime = Cesium.JulianDate.now();// 设置当前时间
       for (let i = 0; i < positions.length - 1; i++) {
           for (let j = 0; j <= 1; j += 0.01) {
               this._postions.push(Cesium.Cartesian3.lerp(positions[i], positions[i + 1], j, new Cesium.Cartesian3()));
           }
       }
       const positionProperty = new Cesium.SampledPositionProperty();
       const startTime = Cesium.JulianDate.now();
       this._postions.forEach((pos, index) => {
           const time = Cesium.JulianDate.addSeconds(startTime, index, new Cesium.JulianDate());
           positionProperty.addSample(time, pos);
       })
       this._entityMotion.position = positionProperty;
       const orientationProperty = new Cesium.VelocityOrientationProperty(positionProperty);
       this._entityMotion.orientation = orientationProperty;
       //this.viewer.trackedEntity = this._entityMotion;//是否追踪小车
   }

在Cesium中,不用的资源要及时释放,不然会很卡。

       // 清除所有
    clearAll() {
        // 清空位置数组
        this._postions = [];
        // 移除实体运动
        this.viewer.entities.remove(this._entityMotion);
        this._entityMotion = null;
    }

这里,为了方便控制小车,我们还可以通过改变时间来改变小车的运动状态

    /**
    * 修改运动状态
    * @param {*} state 运动状态true 或 false
    */
   modifyMotionState(state) {
       this.viewer.clock.shouldAnimate = state;
   }
   /**
    * 修改运动速度
    * @param {*} speed 速度
    */
   modifySpeed(speed) {
       this.viewer.clock.multiplier = speed;
   }

后续,我们就可以通过新建一个Motion对象来直接控制小车了,并且通过视图上的按钮来控制小车的运动,线的绘制(见我的其他文章,可能暂时还没写),把绘制的线的点集合当参数调用startMotion,就可以实现绘制小车轨迹然后小车沿轨迹运动了。
在这里插入图片描述
大家对内容满意的话记得点赞关注!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凕雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值