原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/

粒子系统介绍

这篇教程带你学习Cesium的粒子相关API,比如如何在你的项目里添加烟,火,火花等特效。

 
最终效果

什么是粒子系统?

粒子系统是一种图形学技术,用来模拟复杂的物理效果。粒子系统是由一堆很小的图片组成,看起来就像一些复杂的“含糊不清(fuzzy)”对象,就像火、烟、天气、或者 烟花。这些复杂效果其实是通过控制每一个独立的粒子的初始位置、速度、生命周期等属性来完成。
粒子系统通常在电影和游戏中应用广泛。比如,用来表示飞机的损伤过程,艺术家或者开发人员先用粒子系统来展示飞机引擎的爆炸效果,然后在用另一个粒子系统表示飞机坠毁过程中的烟雾轨迹。

粒子系统基本概念

先通过代码看下基本的粒子系统:

var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({
// Particle appearance
image : '../../SampleData/fire.png',
imageSize : new Cesium.Cartesian2(20, 20);
startScale : 1.0,
endScale : 4.0,
// Particle behavior
particleLife : 1.0,
speed : 5.0,
// Emitter parameters
emitter : new Cesium.CircleEmitter(0.5),
emissionRate : 5.0,
emitterModelMatrix : computeEmitterModelMatrix(),
// Particle system parameters
modelMatrix : computeModelMatrix(),
lifetime : 16.0
}));

效果是这样的:

 
最终效果

上述代码里创建了 ParticleSystem类的对象, 传递了一个对象参数,来控制每个独立粒子 Particle 的外观 。粒子从 ParticleEmitter中生成,它有一个位置和类型、生存一段时间后,就消亡。
部分属性可以是动态的。注意示例代码里并非用了一个color属性,而是用了startColorendColor两个颜色属性。在粒子的整个时间中,根据时间在两个颜色之间做插值。startScaleendScale属性也是类似。

其他影响粒子系统效果的是maximum和minimum 属性。对于每个有最小和最大参数配置的属性,在粒子的初始化过程中会在这个最小最大值范围内随机,然后整个粒子的生存周期内都不会变化。比如,设定粒子的初始运行速度,可以直接设置 speed变量,也可以设置 minimumSpeedmaximumSpeed 变量做为随机速度的上下边界。允许类似设置的属性包括:imageSize, speed, life, 和particleLife

通过这些参数可以创建很多很多种粒子效果,具体可以试下Sandcastle的粒子系统示例

掌握Cesium的粒子系统,等同于对这些不同参数非常熟悉。我们讨论一些属性的细节。

发射器( Emitters)

ParticleEmitter控制了粒子产生时候的位置以及初始速度方向。发射器依据 emissionRate来决定每秒产生多少粒子,根据发射器类型不同决定了粒子的随机速度方向。
Cesium内置了各种粒子发射器。

BoxEmitter

BoxEmitter 类在盒子里(box)里随机一个位置,沿着盒子的6个面的法向量向外运动。它接受一个Cartesian3 参数,定义了盒子的长宽高。

particleSystem : {
image : '../../SampleData/fire.png',
emissionRate: 50.0,
emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(10.0, 10.0, 10.0))
}
 
boxemitter

CircleEmitter
圆形发射器使用CircleEmitter类在圆形面上随机一个位置,粒子方向是发射器的向上向量。它接受一个float参数指定了圆的半径。

particleSystem : {
image : '../../SampleData/fire.png',
emissionRate: 50.0,
emitter: new Cesium.CircleEmitter(5.0)
}
 
circleemitter

如果没有指定发射器,默认使用圆形发射器。
ConeEmitter
锥形发射器类使用ConeEmitter在椎体顶点产生粒子,粒子方向在椎体内随机一个角度向外。它接受一个float参数,制定了锥角。椎的方向沿着向上轴。
The ConeEmitter class initializes particles at the tip of a cone and directs them at random angles out of the cone. It takes a single float parameter specifying the angle of the cone. The cone is oriented along the up axis of the emitter.

particleSystem : {
image : '../../SampleData/fire.png',
emissionRate: 50.0,
emitter: new Cesium.ConeEmitter(Cesium.Math.toRadians(30.0))
}
 
coneemitter

SphereEmitter
球形发射器使用SphereEmitter类在球体内随机产生粒子,初始速度是沿着秋心向外。它接受一个float参数指定了球体半径。

particleSystem : {
image : '../../SampleData/fire.png',
emissionRate: 50.0,
emitter: new Cesium.SphereEmitter(5.0)
}

[站外图片上传中...(image-90334b-1542985116768)]

配置粒子系统

Cesium有很多选项来调整粒子效果。

粒子发射速率
emissionRate 属性控制每秒生成多少个粒子,用来调整粒子密度。
可以设定一个爆炸对象的数组,用来控制在某个特定时刻产生爆炸效果。这是添加各种爆炸效果的最好方法。

给粒子增加下面的属性:

bursts : [
new Cesium.ParticleBurst({time : 5.0, minimum : 300, maximum : 500}),
new Cesium.ParticleBurst({time : 10.0, minimum : 50, maximum : 100}),
new Cesium.ParticleBurst({time : 15.0, minimum : 200, maximum : 300})
],

在给定时刻,这些爆炸效果会产生随机个粒子,在设定最少和最多值之间。

粒子的生命周期和粒子系统的生命周期
一些参数控制了粒子系统的生命周期,默认粒子系统一直运行。
设置lifetime属性控制粒子的持续时间,同时需要设置loop属性为false。比如设定一个粒子系统运行5秒:

particleSystem : {
lifetime: 5.0,
loop: false
}

设置particleLife 属性为5.0 表示设置每个粒子的生命周期是5秒。为了每个粒子都有一个随机生命周期,我们可以设置 minimumParticleLife 和 maximumParticleLife。比如下面的代码设置了粒子生命周期在5秒和10秒之间:

particleSystem : {
minimumParticleLife: 5.0,
maximumParticleLife: 10.0
}

粒子样式

颜色(Color)
除了设定image属性来控制粒子的纹理外,还可以设定一个颜色值,这个值可以在粒子的生命周期内变化。这个在创建动态变化效果非常有用。
比如,下面代码使火焰粒子产生的时候是淡红色,消亡的时候是半透明黄色。

particleSystem : {
startColor: Cesium.Color.RED.withAlpha(0.7),
endColor: Cesium.Color.YELLOW.withAlpha(0.3)
}

大小(Size)
通常粒子大小通过imageSize属性控制。如果想设置一个随机大小,每个粒子的宽度在minimumImageSize.x 和 maximumImageSize.x 之间随机,高度在minimumImageSize.y 和 maximumImageSize.y之间随机,单位为像素。
下面代码创建了像素大小在30~60之间的粒子:

particleSystem : {
minimumImageSize : new Cesium.Cartesian2(30.0, 30.0),
maximumImageSize : new Cesium.Cartesian2(60.0, 60.0)
}

和颜色一样,粒子大小的倍率在粒子整个生命周期内,会在startScale 和 endScale属性之间插值。这个会导致你的粒子随着时间变大或者缩小。
下面代码使粒子逐渐变化到初始大小的4倍:

particleSystem : {
startScale: 1.0,
endScale: 4.0
}

运行速度Speed
发射器控制了粒子的位置和方向,速度通过speed参数或者minimumSpeed和maximumSpeed 参数来控制。下面代码让粒子每秒运行5~10米:

particleSystem : {
minimumSpeed: 5.0,
maximumSpeed: 10.0
}

更新回调(UpdateCallback)

为了提升仿真效果,粒子系统有一个更新函数。这个是个手动更新器,比如对每个粒子模拟重力或者风力的影响,或者除了线性插值之外的颜色插值方式等等。
每个粒子系统在仿真过程种,都会调用更新回调函数来修改粒子的属性。回调函数传过两个参数,一个是粒子本身,另一个是仿真时间步长。大部分物理效果都会修改速率向量来改变方向或者速度。下面是一个粒子响应重力的示例代码:

var gravityScratch = new Cesium.Cartesian3();
function applyGravity(p, dt) {
// 计算每个粒子的向上向量(相对地心)
var position = p.position; Cesium.Cartesian3.normalize(position, gravityScratch);
Cesium.Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch); p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
}

这个函数计算了一个重力方向,然后使用重力加速度(-9.8米每秒平方)去修改粒子的速度方向。 .
然后设置粒子系统的更新函数:

particleSystem: {
forces: applyGravity
}

位置

粒子系统使用两个转换矩阵来定位:

  • modelMatrix : 把粒子系统从模型坐标系转到世界坐标系。
  • emitterModelMatrix : 在粒子系统的局部坐标系内变换粒子发射器。
    我们提供两个属性也是为了方便,当然可以仅仅设置一个,把另一个设置为单位矩阵。为了学习创建这个矩阵,我们尝试把我们的粒子系统相对另一个entity。
    首先创建一个entity。打开Sandcastle 的 Hello World示例,敲入下面的代码:
var entity = viewer.entities.add({
// 加载飞机模型
model : {
uri : '../../SampleData/models/CesiumAir/Cesium_Air.gltf',
minimumPixelSize : 64
},
position : Cesium.Cartesian3.fromDegrees(-112.110693, 36.0994841, 1000.0)
});
viewer.trackedEntity = entity;

在viewer里创建了一个飞机模型。
下来,我们如何在场景种摆放我们的粒子系统。我们先给飞机的一个引擎上放一团火。首先给粒子系统创建一个模型矩阵,这个矩阵和飞机的位置和朝向完全相同。意思就是飞机的模型矩阵也要做为粒子系统的矩阵,这么设置modelMatrix

function computeModelMatrix(entity, time) {
var position = Cesium.Property.getValueOrUndefined(entity.position, time, new Cesium.Cartesian3());
if (!Cesium.defined(position)) {
return undefined;
}
var orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, new Cesium.Quaternion());
if (!Cesium.defined(orientation)) {
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, new Cesium.Matrix4());
} else {
modelMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, new Cesium.Matrix3()), position, new Cesium.Matrix4());
}
return modelMatrix;
}

现在这个矩阵已经把粒子放到了飞机中心位置。可是我们想让粒子在飞机的一个引擎上产生,所以我们再创建一个在模型坐标系的平移矩阵。这么计算:

function computeEmitterModelMatrix() {
hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, new Cesium.HeadingPitchRoll());
var trs = new Cesium.TranslationRotationScale();
trs.translation = Cesium.Cartesian3.fromElements(2.5, 4.0, 1.0, new Cesium.Cartesian3());
trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion());
return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());
}

现在就可以去计算偏移矩阵了,我们先用一些基本参数创建粒子系统,代码如下:

var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({
image : '../../SampleData/fire.png',
startScale : 1.0,
endScale : 4.0,
particleLife : 1.0,
speed : 5.0,
imageSize : new Cesium.Cartesian2(20, 20),
emissionRate : 5.0,
lifetime : 16.0,
modelMatrix : computeModelMatrix(entity, Cesium.JulianDate.now()),
emitterModelMatrix : computeEmitterModelMatrix()
}));

这就做到了前面示例里描述的效果,把粒子特效放到了飞机的引擎上。

 
最终效果

注意我们可以随时更改模型或者发射器矩阵。比如,我们想通过通过去更改粒子发射器相对飞机的位置,我们只需要修改emitterModelMatrix,而保持 modelMatrix 不变。这样就非常容易的在模型空间重新定位了。
这种定位方式并非直接设定一个position属性,而是提供了一种有效的,灵活的矩阵变换方式,适应更多效果要求。
这就是粒子系统的基础知识,很期待看到你用他们做出来的效果。
更多粒子系统特效,以及更高级的技术,请看更多粒子特效教程

 
烟花

更多示例代码:

Cesium官方教程9--粒子系统的更多相关文章

  1. Cesium官方教程13--Cesium和Webpack

    原文地址:https://cesiumjs.org/tutorials/cesium-and-webpack/ Cesium 和 Webpack Webpack是非常强大非常流行的JavaScript ...

  2. 关于Cesium 官方教程

    最近一直在准备第一次QQ群的Cesium基础培训公开课,虽说使用Cesium也有段日子了,但是要说对Cesium了解有多深,还真不一定.原因是一直以来我都是用哪里学哪里.基于多年开发三维数字地球的底层 ...

  3. Cesium官方教程10--高级粒子特效

    原文地址:https://cesiumjs.org/tutorials/Particle-Systems-More-Effects-Tutorial/ 高级粒子系统特效 这篇教程学习更多的效果,包括天 ...

  4. Cesium官方教程6--相机

    相机(Camera) 相机控制了场景的观察视角.有很多相机操控方法,比如旋转.缩放.平移以及飞行定位.Cesium默认支持使用鼠标和触摸事件控制相机.Cesium也提供了一套可编程的相机控制API.这 ...

  5. Cesium官方教程8-- 几何体和外观效果

    原文地址:https://cesiumjs.org/tutorials/Geometry-and-Appearances/ 几何体和外观效果(Geometry and Appearances) 这篇教 ...

  6. Cesium官方教程7--三维模型

    原文地址:https://cesiumjs.org/tutorials/3D-Models-Tutorial/ 三维模型 (3D Models) 这篇教程给大家介绍,如何在Cesium中通过Primi ...

  7. Cesium官方教程4--影像图层

    原文地址:https://cesiumjs.org/tutorials/Imagery-Layers-Tutorial/ 影像图层 Cesium支持多种服务来源的高精度影像(地图)数据的加载和渲染.图 ...

  8. Cesium官方教程12--材质(Fabric)

    原文地址:https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric 介绍 Fabric 是Cesium中基于JSON格式来描述materi ...

  9. Cesium官方教程11--建模人员必读

    原文地址:https://cesium.com/blog/2014/12/15/gltf-tips-for-artists/ 这篇文章是Branden Coker, an artist from AG ...

随机推荐

  1. 找到你的位置(JS在页面中的位置)最常用的方式是在页面中head部分放置<script>元素,浏览器解析head部分就会执行这个代码,然后才解析页面的其余部分

    找到你的位置(JS在页面中的位置) 我们可以将JavaScript代码放在html文件中任何位置,但是我们一般放在网页的head或者body部分. 放在<head>部分 最常用的方式是在页 ...

  2. Asp.net MVC使用EasyNetQ操作RabbitMQ

    Demo下载地址:https://download.csdn.net/download/u010312811/11259742 .Net下操作RabbitMQ最常用的SDK是RabbitMQ.Clie ...

  3. PHP算法之删除最外层的括号

    有效括号字符串为空 ("")."(" + A + ")" 或 A + B,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接.例如 ...

  4. hive中,lateral view 与 explode函数

    hive中常规处理json数据,array类型json用get_json_object(#,"$.#")这个方法足够了,map类型复合型json就需要通过数据处理才能解析. exp ...

  5. Android 开发 框架系列 OkHttp文件下载功能实现(含断点续传)

    前言 此篇博客只是下载功能的记录demo,如果你还不太了解okhttp可以参考我的另一篇博客https://www.cnblogs.com/guanxinjing/p/9708575.html 代码部 ...

  6. memset 初始化 不同数值 打表

    #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #in ...

  7. leetcode-227-基本计算器②

    题目描述: 方法一:中缀转后缀 #!_*_coding:utf-8_*_ class Solution: def calculate(self, s: str) -> int: def in_t ...

  8. matlab中乘法和点乘以及除法和点除的联系是什么?

    一,*和.*的联系和区别. 1,在进行数值运行和数值乘矩阵,这两种没有区别,例如:a*b=a.*b; a*B=a.*B; B*a=B.*a (其中小写字母表示数值,大写字母表示矩阵,下同). 2,在处 ...

  9. duilib教程之duilib入门简明教程6.XML配置界面

    前面那些教程都是为了让小伙伴们从win32.MFC过渡到duilib,让大家觉得duilib不是那么陌生,如果大家现在还对duilib非常陌生的话,那就说明前面的教程做得不好,请大家在下面留言,我会一 ...

  10. dart 异步

    使用异步有两种方法 then 或者 async/await. async/await 方法更易于理解,