Cesium粒子系统学习

<!DOCTYPE html>
<html lang="en">
<head>
  <!-- Use correct character set. -->
  <meta charset="utf-8">
  <!-- Tell IE to use the latest, best version. -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <title>Hello World!</title>
  <script src="../Build/Cesium/Cesium.js"></script>
  <style>
      @import url(../Build/Cesium/Widgets/widgets.css);
      html, body, #cesiumContainer {
           100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
      }
  </style>
</head>
<body>
  <div id="cesiumContainer"></div>
  <script>
 
     
 
var viewer = new Cesium.Viewer('cesiumContainer', {
    imageryProvider : Cesium.createTileMapServiceImageryProvider({
        url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
    }),
     shouldAnimate: true,//是否开始动画
    geocoder : false
});
 
 
// 画一个用于粒子显示的canves图像
var particleCanvas;
function getImage() {
    if (!Cesium.defined(particleCanvas)) {
        particleCanvas = document.createElement('canvas');
        particleCanvas.width = 20;
        particleCanvas.height = 20;
        var context2D = particleCanvas.getContext('2d');
        context2D.beginPath();
        context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);
        context2D.closePath();
        context2D.fillStyle = 'rgb(255, 255, 255)';
        context2D.fill();
    }
    return particleCanvas;
}
 
//关于粒子的一些属性项
//光学粒子属性
var Optics_options = {
    numberOfSystems : 1,
    iterationOffset :  0.1,
    cartographicStep : 0.00000001
    
};
 
 
//雷达粒子属性
var Radar_options = {
    numberOfSystems : 50,//用很多粒子组成一个形状,这里让其组成一个圆形
    iterationOffset :  0.1,
    cartographicStep : 0.00000001,
    baseRadius : 300//初始圆形的半径
 
};
 
 
// 创建粒子位置矩阵
var planePosition = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 800.0);
var particlesOffset = new Cesium.Cartesian3(-8.950115473940969, 34.852766731753945, -30.235411095432937);
var translationOffset = Cesium.Matrix4.fromTranslation(particlesOffset, new Cesium.Matrix4());
var translationOfPlane = Cesium.Matrix4.fromTranslation(planePosition, new Cesium.Matrix4());
var particlesModelMatrix = Cesium.Matrix4.multiplyTransformation(translationOfPlane, translationOffset, new Cesium.Matrix4());
 
//创建光学粒子系统,该系统只有一个粒子发射器不断发射粒子
var matrix4Scratch = new Cesium.Matrix4();
var scratchOffset = new Cesium.Cartesian3();
var imageSize = new Cesium.Cartesian2(5.0, 5.0);
var emitterModelMatrix = Cesium.Matrix4.fromTranslation(scratchOffset, matrix4Scratch);
var color = Cesium.Color.YELLOW;//设置粒子的颜色
 
//光学传感器粒子位置更新函数
var positionC= new Cesium.Cartesian3();
var positionD= new Cesium.Cartesian3();
var force = function(particle,dt) {
    dt = Cesium.Math.clamp(dt, 0.0, 1);//每次更新时间间隔
    //下面是向量计算
    var positionA=particle.position;
    var positionB=Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706,0);    
    positionC=Cesium.Cartesian3.multiplyByScalar(positionA, 0.9, positionC);
    positionD=Cesium.Cartesian3.multiplyByScalar(positionB, 0.1, positionD); 
    particle.position=Cesium.Cartesian3.add(positionC,positionD,particle.position); 
      
    };
    //
var itemOptics = viewer.scene.primitives.add(new Cesium.ParticleSystem({
        image : getImage(),//粒子图像
        startColor : color,//开始颜色
        endColor : color.withAlpha(0.5),//结束时的颜色
        particleLife : 100,//每个粒子的生存时间
        speed : 50,//粒子飞行速度
        imageSize : imageSize,//粒子大小
        emissionRate : 1.0,//每秒发射粒子的个数
        emitter : new Cesium.CircleEmitter(0.01),//粒子发射器的形式,确定了在什么样的区间里随机产生粒子
        lifetime : 100,//粒子发射器的生命周期,即发射粒子的时间
        updateCallback : force,//粒子位置更新回调函数
        modelMatrix : particlesModelMatrix,//决定粒子在空间坐标系的位置矩阵
        emitterModelMatrix : emitterModelMatrix//决定粒子相对于模型位置的位置矩阵
}));
 
 
var itemRadar=[];
//创建雷达粒子系统,该系统具有许多粒子发射器不断发射粒子
function createParticleSystems(options, systemsArray) {//创建很多个粒子系统
    var length = options.numberOfSystems;//创建的长度
    for (var i = 0; i < length; ++i) {
        scratchAngleForOffset = Math.PI * 2.0 * i / options.numberOfSystems;//一圈粒子的不同大小
        scratchOffset.x += options.baseRadius * Math.cos(scratchAngleForOffset);
        scratchOffset.y += options.baseRadius * Math.sin(scratchAngleForOffset);
        scratchOffset.z += options.baseRadius * Math.cos(scratchAngleForOffset/2);
         
        var emitterModelMatrix = Cesium.Matrix4.fromTranslation(scratchOffset, matrix4Scratch);
        var color = Cesium.Color.RED;//取一个随机颜色
    //  var color = Cesium.Color.AQUAMARINE//取天蓝色
        var force = forceFunction(options, i);
 
        itemRadar = viewer.scene.primitives.add(new Cesium.ParticleSystem({
            image : getImage(),
            startColor : color,
            endColor : color,
            particleLife : 50,
            speed : 1,
            imageSize : new Cesium.Cartesian2(2.0, 2.0),
            emissionRate : 3.0,
            emitter : new Cesium.CircleEmitter(0.1),
            lifetime : 100,
            updateCallback : force,
            modelMatrix : particlesModelMatrix,
            emitterModelMatrix : emitterModelMatrix
        }));
        systemsArray.push(itemRadar);
    }
};
//雷达传感器粒子位置更新函数
var RadarpositionC = new Cesium.Cartesian3();
var RadarpositionD = new Cesium.Cartesian3();
var forceFunction = function(options, iteration) {
    return function(particle, dt) {
     
        
        dt = Cesium.Math.clamp(dt, 0.0, 1);//每次更新时间间隔
        //下面是向量计算
        var positionA=particle.position;
        var positionB=Cesium.Cartesian3.fromDegrees(-122.0744619, 44.0503706,0);    
        positionC=Cesium.Cartesian3.multiplyByScalar(positionA, 0.9, positionC);
        positionD=Cesium.Cartesian3.multiplyByScalar(positionB, 0.1, positionD); 
        particle.position=Cesium.Cartesian3.add(positionC,positionD,particle.position); 
         
    };
};
 
 
var RadarSystems = [];
createParticleSystems(Radar_options, RadarSystems);
 
 
     
////////////////////////////////**************************************////////////////////////////////
     
var scene = viewer.scene;
//飞行轨迹
var pathPosition = new Cesium.SampledPositionProperty();
var entityPath = viewer.entities.add({
    position : pathPosition,
    name : 'path',
    path : {
        show : true,
        leadTime : 0,
        trailTime : 60,
        width : 10,
        resolution : 1,
        material : new Cesium.PolylineGlowMaterialProperty({
            glowPower : 0.3,
            color : Cesium.Color.PALEGOLDENROD
        })
    }
});
 
var camera = viewer.camera;
var r = 0;
var center = new Cesium.Cartesian3();
var hpRoll = new Cesium.HeadingPitchRoll();
var hpRange = new Cesium.HeadingPitchRange();
var speed = 500;//飞行速度
 
 
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 50000.0);//飞机初始位置
var speedVector = new Cesium.Cartesian3();//速度向量
var fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west');//坐标系
//添加飞机模型
var planePrimitive = scene.primitives.add(Cesium.Model.fromGltf({
    url : './SampleData/models/CesiumAir/Cesium_Air.glb',
    modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform),
    minimumPixelSize : 128
}));
 
//添加一个地面站
var entity1 = viewer.entities.add({
        position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
        billboard : {
            image : './Sandcastle/images/facility.gif',
         
        }
    });
     
//添加第二个地面站
var entity1 = viewer.entities.add({
        position : Cesium.Cartesian3.fromDegrees(-122.0744619, 44.0503706),
        billboard : {
            image : './Sandcastle/images/facility.gif',
 
        }
    });
 
planePrimitive.readyPromise.then(function(model) {
    // Play and loop all animations at half-speed
    model.activeAnimations.addAll({
        speedup : 0.5,
        loop : Cesium.ModelAnimationLoop.REPEAT
    });
});
 
 
viewer.scene.preUpdate.addEventListener(function(scene, time) {
    speedVector = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.UNIT_X, speed / 10, speedVector);
    position = Cesium.Matrix4.multiplyByPoint(planePrimitive.modelMatrix, speedVector, position);
    pathPosition.addSample(Cesium.JulianDate.now(), position);
    Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, planePrimitive.modelMatrix);
                 
     translationOfPlane = Cesium.Matrix4.fromTranslation(position, new Cesium.Matrix4());
     particlesModelMatrix = Cesium.Matrix4.multiplyTransformation(translationOfPlane, translationOffset, new Cesium.Matrix4());
     itemOptics.modelMatrix=particlesModelMatrix;
      
     for(var i=0;i<50;i++){
      
      RadarSystems[i].modelMatrix=particlesModelMatrix;
     }
     
 
});
 
 viewer.zoomTo(viewer.entities);
     
  </script>
</body>
</html>

Cesium中粒子系统被用来模拟飞机爆炸、雨雪天气等场景。
根据官网对其定义 ,粒子系统是由小图像组成的集合,当他们在一起形成一个更复杂的对象时,就会形成火、烟等景象。对于该系统详细的说明可以参照官网介绍:
https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/
下面还有国内公司的翻译版:
http://cesium.marsgis.cn/go.html?id=12


看完上述教程还是一头雾水,那就做个简单的粒子来分析下吧。粒子系统其实实由一个发射器不断发射出粒子对象实现的。如果是一个单个的粒子,可以将粒子发射器想象成一把枪,子弹就是该发射器发射出的粒子。不同之处在于,粒子发射器发射出粒子之后可以控制粒子的轨迹、颜色等属性。

先来看一个最简单的生成粒子系统的代码例子:

var item = viewer.scene.primitives.add(new Cesium.ParticleSystem({
        image : getImage(),//粒子图像
        startColor : color,//开始颜色
        endColor : color.withAlpha(0.5),//结束时的颜色
        particleLife : 100,//每个粒子的生存时间,即子弹被打出来后能飞多久
        speed : 50,//粒子飞行速度
        imageSize : imageSize,//粒子大小
        emissionRate : 1.0,//每秒发射粒子的个数
        emitter : new Cesium.CircleEmitter(1),//粒子发射器的形式,确定了在什么样的区间里随机产生粒子,该行表示粒子将在一个半径为1米的圆形区域不断产生
        lifetime : 100,//粒子发射器的生命周期,即发射粒子的时间,该值可理解为一把枪的弹夹可以用多长时间,loop默认属性为true理解为到时间后换上另一个弹夹继续发射。
        updateCallback : force,//粒子位置更新回调函数
        modelMatrix : particlesModelMatrix,//决定粒子在空间坐标系的位置矩阵,可以理解为用枪的人的空间位置
        emitterModelMatrix : emitterModelMatrix//决定粒子相对于模型位置的位置矩阵,可以理解为人把发射枪拿在哪里,用左手还是右手还是用脚,即发射器相对本体的位置矩阵。
}));

上述代码构成了一个粒子系统,该系统中只有一个发射器。
image : getImage()是每个粒子的样式,我们可以理解成从枪里发射出来子弹的类型,子弹的样子可以是图片,也可以用canves函数来绘制,如果使用图片的话,可以直接写作image : '../../SampleData/fire.png',
在火箭发射粒子效果里,给出了一个简单的圆形图像的绘制函数:

function getImage() {
    if (!Cesium.defined(particleCanvas)) {
        particleCanvas = document.createElement('canvas');
        particleCanvas.width = 20;
        particleCanvas.height = 20;
        var context2D = particleCanvas.getContext('2d');
        context2D.beginPath();
        context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);
        context2D.closePath();
        context2D.fillStyle = 'rgb(255, 255, 255)';
        context2D.fill();
    }
    return particleCanvas;
}

上述函数属于html中canves内容,这里不在赘述。

imageSize : imageSize是一个由二维向量定义的尺寸函数,可以由代码new Cesium.Cartesian2(1, 1)进行设置。

应该重点介绍的是updateCallback : force。该属性是一个函数形式,该函数可写作:

function force(particle, dt) {//particle是当前粒子对象,可以由很多属性,dt是时间步长。之前有一个属性是particleLife表示每个粒子被发射出来后的生存时间。dt就是将这段时间均分的步长。下面我们对粒子的位置进行改变。
   var position = particle.position;
   var positionA = Cesium.Cartesian3.normalize(position, new Cesium.Cartesian3());//将粒子的位置向量正则化为单位值。
   Cesium.Cartesian3.multiplyByScalar(positionA , 5, positionA );//将单位向量按比例进行缩放
   particle.position= Cesium.Cartesian3.add(particle.position, positionA , particle.position);//在粒子发射方向加上成比例缩放的向量,更新粒子位置
}

上述函数只是对粒子位置按粒子的生命周期进行了修改,还可以对其速度、颜色等属性按时间进行修改。

下述就是用粒子系统做的信号动态传输效果图,黄色用了一个粒子发射器。红色的圈圈用了一组发射器,沿着圆圈的方向不断发射粒子。当然该效果可以直接用entity来实现,但是粒子系统的自由度高,可以做出各种不同的波形效果。


*回忆总像个漏风的房子,起风了,都是不请自来*

本文转自 https://blog.csdn.net/dk_wyp/article/details/82024647,如有侵权,请联系删除。

原文地址:https://www.cnblogs.com/hustshu/p/15255345.html