cesium模拟火箭发射
效果及过程如下
倒计时
点火
腾空而起
变换视角
变换视角 + 旋转
我们的目标是星辰大海
通过这个效果,可以了解到以下知识点:
1、加载模型
2、控制视角
3、烟雾效果
4、路径
代码要点
1、总体结构
2、调用
require(['rocket'],function(Rocket){
//viewer = var viewer = new Cesium.Viewer("cesiumViewer",....
var rocket = new Rocket(viewer,Cesium,"./images/model/");
closePopWin = function(){//当关闭窗口时擦除发射效果
rocket.clear();
};
rocket.emit();//开启发射
});
3、要点
代码太长了,只说一些要点。
1)飞行路径
定义飞行路径,里面包含起始、结束高度,以及中间的各种临界点。飞行过程中,突破临界点后,速度有所提升,视角也可能会变换
//飞行路径
var path = {
lng: 109.48,
lat: 19.19,
startH: 50,
stopH: 300000,
points: [
{h:51,s:0.2,v:new Cesium.Cartesian3(450, -450, 0)},//点火瞬间参数
{h:60,s:3,v:new Cesium.Cartesian3(450, -450, 0)},
{h:150,s:10,v:new Cesium.Cartesian3(450, -450, 0)},//h,高度;s,速度,米/秒; v:视角;
{h:200,s:20,v:new Cesium.Cartesian3(450, -450, 0)},
{h:300,s:40,v:new Cesium.Cartesian3(450, -450, 0)},
{h:700,s:80,v:new Cesium.Cartesian3(450, -450, 0)},
{h:1000,s:120,v:new Cesium.Cartesian3(450, -450, 0)},
{h:2000,s:300,v:new Cesium.Cartesian3(250, -150, 350)},
{h:4000,s:450,v:new Cesium.Cartesian3(250, -150, 150)},
{h:6000,s:500,v:new Cesium.Cartesian3(50, -50, 450)},
{h:9000,s:800,v:new Cesium.Cartesian3(50, -50, 350)},
{h:12000,s:1000,v:new Cesium.Cartesian3(50, -50, 250)},
{h:30000,s:7000,v:new Cesium.Cartesian3(250, 50, 150),r:-45.0}, //r,roll,转屏角度
{h:150000,s:10000,v:new Cesium.Cartesian3(450, 50, 50),r:-90.0}//突破第一宇宙速度7.9km/秒
]
};
2)装配好参数:
装配好路径,赋给变量position
计算出整个路程需耗费的总时间
设置好viewer.clock
//装配路径参数
var ps = (function setup() {
var position = new Cesium.SampledPositionProperty();
var start = Cesium.JulianDate.fromDate(new Date(2020, 8, 1, 10));
var posS = Cesium.Cartesian3.fromDegrees(path.lng, path.lat, path.startH);
position.addSample(start, posS);
var time = 0;
var ht = path.startH;
var st = 0;
for (var i in path.points) {
var p = path.points[i];
time += Math.round((p.h - ht) / p.s);
position.addSample(Cesium.JulianDate.addSeconds(start, time, new Cesium.JulianDate()),
Cesium.Cartesian3.fromDegrees(path.lng, path.lat, p.h));
ht = p.h;
st = p.s;
}
time += Math.round((path.stopH - ht) / st);
var stop = Cesium.JulianDate.addSeconds(start, time, new Cesium.JulianDate());
position.addSample(stop, Cesium.Cartesian3.fromDegrees(path.lng, path.lat, path.stopH));
//Make sure viewer is at the desired time.
clock = viewer.clock;//保存下当前的viewer.clock,
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
viewer.clock.multiplier = 1;
viewer.clock.shouldAnimate = true;
return {
position: position,
posS: posS,
start: start,
stop: stop
};
})();
飞行过程中根据设定作出视角变换等反应。
var ellipsoid = viewer.scene.globe.ellipsoid;
var turnH = path.startH;
flyListener = function (scene, time) {
if (!entity) return;
var center = entity.position.getValue(viewer.clock.currentTime);
if (!center) return;
var height = ellipsoid.cartesianToCartographic(center).height;
if (height < path.points[0].h) {
viewer.camera.lookAt(center, path.points[0].v);
turnH = path.startH;
if (smoke) smoke.reset();
} else {
for (var i = path.points.length - 1; i >= 0; i--) {
var p = path.points[i];
if (height >= p.h) {
viewer.camera.lookAt(center, p.v);
if (p.r) { //旋转
viewer.camera.rotate(viewer.camera.direction, Cesium.Math.toRadians(p.r));
}
if (turnH < p.h) { //突破每个高度临界点
if (smoke)
smoke.speedUp(); //烟雾喷射提速
turnH = p.h;
console.log(height + "," + p.h);
}
break;
}
}
}
if (smoke) smoke.fly(entity, time);
};
变换视角主要由方法viewer.camera.lookAt()
来完成。但旋转要靠viewer.camera.rotate();
。刚开始我们设定的视角,是飞船机头垂直向上的,无论怎么lookAt,这个机头垂直向上的方向都不会改变,只能旋转。但是这个旋转函数的参数也是一个世界坐标(Cesium.Cartesian3),按照说明,应该是某一个轴才对,坐标怎么跟轴对应起来?其实是类似这样:
viewer.camera.rotate(viewer.camera.direction, 角度);
3)火箭模型
一个Entity
//火箭实体
var entity = (function init() {
var position = ps.position;
var start = ps.start;
var stop = ps.stop;
var posS = ps.posS;
var entity = viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: start,
stop: stop,
}),
]),
model: {
uri: modelPath + "Cesium_Air.glb",
scale: 3.5,
},
position: posS,
orientation: new Cesium.VelocityOrientationProperty(position), //朝向前进方向
});
viewer.camera.lookAt(
posS, //target
path.points[0].v);
return entity;
})();
4)发射
到目前为止,飞船还是不能动的。要怎么才可以动呢?这样:
entity.position = ps.position;//ps就是上面那个装配好的参数
viewer.trackedEntity = entity;
配合倒计时,烟雾效果。
5)烟雾
烟雾是Cesium提供的粒子系统(Cesium.ParticleSystem)。用了一张烟雾图片。cesium提供的例子中,也有自己画粒子的,但每个粒子都需要计算,消耗很大,直接用烟雾照片不亦快哉。
由于飞船有加速度,越飞越快,导致烟雾会被抛在身后,且距离越拉越远。应对之策是缩短粒子的生命周期,并加大粒子发射器的喷发速度。注意,粒子喷发速度跟显卡性能有关,设得过高,会引起机器卡顿,甚至崩溃。
this.speedUp = function () {
var p = particleSystem;
p.lifetime *= 0.75;
var rate = p.emissionRate + 150;
if (rate > 2000)
rate = 2000;
p.emissionRate = rate;
p.particleSize -= 2;
if (p.particleSize < 25)
p.particleSize = 25;
};
参考效果,路径及烟雾效果均来源于此
https://sandcastle.cesium.com/?src=Particle%20System.html