Cesium粒子系统--Particle System FireWorks原理

Cesium为我们提供了非常棒的烟花的粒子特效,我们可以在沙盒中的Particle System FireWorks.html中看到

image

考虑到篇幅问题,我会把自己认为比较关键的代码拿出来,进行分析

首先我们放重头戏,我们看看粒子系统是如何放入场景中的

scene.primitives.add(
    new Cesium.ParticleSystem({
          image: getImage(),
          startColor: color,
          endColor: color.withAlpha(0.0),
          particleLife: life,
          speed: 100.0,
          imageSize: particlePixelSize,
          emissionRate: 0,
          emitter: new Cesium.SphereEmitter(0.1),
          bursts: bursts,
          lifetime: lifetime,
          updateCallback: force,
          modelMatrix: modelMatrix,
          emitterModelMatrix: emitterModelMatrix,
    })
);

我们可以看到,粒子发射器的发射速率为0个/s(即不发射粒子),而烟花效果依靠的是bursts,使其在一定的时间间隔中,瞬间释放大量粒子

我们看看getImage的过程:

这里使用canvas2D生成一张20*20像素的图片,图片中绘制了一个半径为8的圆

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;
}

如果你认真一些,你会发现这个圆其实并不是在20*20的图片的中心位置

颜色和偏移量、爆发时间间隔

color和粒子发射器的位置offset粒子爆发间隔burst的time都是系统根据参数在一定范围内生成的随机数

var colorOptions = [
      {
            minimumRed: 0.75,
            green: 0.0,
            minimumBlue: 0.8,
            alpha: 1.0,
      },
      {
            red: 0.0,
            minimumGreen: 0.75,
            minimumBlue: 0.8,
            alpha: 1.0,
      },
      {
            red: 0.0,
            green: 0.0,
            minimumBlue: 0.8,
            alpha: 1.0,
      },
      {
            minimumRed: 0.75,
            minimumGreen: 0.75,
            blue: 0.0,
            alpha: 1.0,
      },
];

for (var i = 0; i < numberOfFireworks; ++i) {
    var x = Cesium.Math.randomBetween(xMin, xMax);
    var y = Cesium.Math.randomBetween(yMin, yMax);
    var z = Cesium.Math.randomBetween(zMin, zMax);
    var offset = new Cesium.Cartesian3(x, y, z);
    var color = Cesium.Color.fromRandom(
        colorOptions[i % colorOptions.length]
    );

    var bursts = [];
    for (var j = 0; j < 3; ++j) {
        bursts.push(
            new Cesium.ParticleBurst({
                time: Cesium.Math.nextRandomNumber() * lifetime,
                minimum: burstSize,
                maximum: burstSize,
            })
        );
    }

    createFirework(offset, color, bursts);
}

而offset则用来计算出粒子的emitterModelMatrix,我们使用emitterModelMatrix用来表示粒子发射区域相对于modelMatrix的偏移量

这里通过在不同的位置,分别创建粒子系统,使得一个粒子系统负责一处位置、一种颜色的粒子发射效果

核心功能createFirework

function createFirework(offset, color, bursts) {
    var position = Cesium.Cartesian3.add(emitterInitialLocation, offset, new Cesium.Cartesian3());
    var emitterModelMatrix = Cesium.Matrix4.fromTranslation(position, emitterModelMatrixScratch);
    var particleToWorld = Cesium.Matrix4.multiply(modelMatrix, emitterModelMatrix, new Cesium.Matrix4());
    var worldToParticle = Cesium.Matrix4.inverseTransformation(particleToWorld, particleToWorld);

    var size = Cesium.Math.randomBetween(minimumExplosionSize,maximumExplosionSize);
    var particlePositionScratch = new Cesium.Cartesian3();
    var force = function (particle) {
        var position = Cesium.Matrix4.multiplyByPoint(
            worldToParticle,
            particle.position,
            particlePositionScratch
        );
        if (Cesium.Cartesian3.magnitudeSquared(position) >= size * size) {
            Cesium.Cartesian3.clone(
            Cesium.Cartesian3.ZERO,
            particle.velocity
            );
        }
    };

    var normalSize = (size - minimumExplosionSize) / (maximumExplosionSize - minimumExplosionSize);
    var minLife = 0.3;
    var maxLife = 1.0;
    var life = normalSize * (maxLife - minLife) + minLife;

    scene.primitives.add(
        new Cesium.ParticleSystem({
            image: getImage(),
            startColor: color,
            endColor: color.withAlpha(0.0),
            particleLife: life,
            speed: 100.0,
            imageSize: particlePixelSize,
            emissionRate: 0,
            emitter: new Cesium.SphereEmitter(0.1),
            bursts: bursts,
            lifetime: lifetime,
            updateCallback: force,
            modelMatrix: modelMatrix,
            emitterModelMatrix: emitterModelMatrix,
        })
    );
}

我们先看上面代码中的回调函数force,我们认真看就会发现,这个回调函数force其实非常的鸡肋,它通过计算发射出的粒子距离粒子发射器中心的距离,如果距离大于size,则让粒子的速度变成0,使其不再移动

particleToWorld作为粒子相对于世界坐标系的位置,而worldToParticle则是上一个矩阵的逆。因为每个粒子的位置都是世界坐标系下的位置,因此需要使用worldToParticle乘以这个粒子的位置,从而得到粒子相对于粒子发射器的位置。

可以看到这里根据offset计算出emitterModelMatrix,得到每个粒子系统最后的位置,而size则是粒子最大发射的距离(在数学上,因为有负数的存在,所以我们使用两个值的平方进行距离的比较)

因为初次写博客,文笔生涩,还望大家见谅,同时欢迎大家一起讨论学习。

如果觉得粒子系统的使用还是有难度,那么建议大家使用earthUI,在其中完全可以通过操作UI得到想要的效果(教程在bilibili)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350