• 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,如有侵权,请联系删除。

  • 相关阅读:
    GCD介绍(二): 多核心的性能
    GCD介绍(一): 基本概念和Dispatch Queue
    iOS 中如何监测某段代码运行的时间
    DSOframer 无法正常加载的解决方案
    Hexo 官方主题 landscape-plus 优化
    在 Parallels Desktop 中,全屏模式使用 Win7,唤醒时黑屏
    VS2015 企业版不支持 JavaScript 语法高亮、智能提醒
    解决 Boot Camp 虚拟机升级到 Windows 10 后 Parallels Desktop 不能识别的问题
    利用SkyDrive Pro 迅速批量下载SharePoint Server 上已上传的文件
    SharePoint Server 2013 让上传文件更精彩
  • 原文地址:https://www.cnblogs.com/hustshu/p/15255345.html
Copyright © 2020-2023  润新知