欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

cesium模拟火箭发射

程序员文章站 2024-02-07 16:33:28
...

效果及过程如下

倒计时
cesium模拟火箭发射
点火
cesium模拟火箭发射
腾空而起
cesium模拟火箭发射
变换视角
cesium模拟火箭发射

变换视角 + 旋转
cesium模拟火箭发射

我们的目标是星辰大海
cesium模拟火箭发射

通过这个效果,可以了解到以下知识点:

1、加载模型
2、控制视角
3、烟雾效果
4、路径

代码要点

1、总体结构
cesium模拟火箭发射
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