本文对 Sandcastal中的给出的粒子系统实例Particle System进行解析,参照网上一些大神的解析结合个人理解所写,有不对之处望大家留言指出,本人在此不胜感激!
总体思路:首先建立entity和particleSystem;在particleSystem里设置粒子系统的各种参数,例如粒子发射速率emissionRate 粒子的生命周期particleLife,粒子颜色、大小、运行速度等参数;如果在运行过程中要更改粒子系统的属性, 则需要在ParticleSystem中调用UpdateCallback更新函数(回调函数传过两个参数,一个是粒子本身,另一个是仿真时间步长) 粒子系统使用modelMatrix(把粒子系统从模型坐标系转到世界坐标系)和emitterModelMatrix(在粒子系统的局部坐标系内变换粒子发射器) 两个转换矩阵来定位。另外:我们可以随时更改模型或者发射器矩阵。比如,我们想通过通过去更改粒子发射器相对飞机的位置, 我们只需要修改emitterModelMatrix,而保持 modelMatrix 不变。这样就非常容易的在模型空间重新定位了。这种定位方式并非直接设定 一个position属性,而是提供了一种有效的,灵活的矩阵变换方式,适应更多效果要求。
核心代码如下:
var viewer = new Cesium.Viewer('cesiumContainer');
//Set the random number seed for consistent results.
Cesium.Math.setRandomNumberSeed(3);
//Set bounds of our simulation time
// 时长设置为120秒
var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16));
var stop = Cesium.JulianDate.addSeconds(start, 120, new Cesium.JulianDate());
//Make sure viewer is at the desired time.
// 设置时钟
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;
//Set timeline to simulation bounds
viewer.timeline.zoomTo(start, stop);
var viewModel = {
emissionRate : 5.0,
gravity : 0.0,
minimumParticleLife : 1.2,
maximumParticleLife : 1.2,
minimumSpeed : 1.0,
maximumSpeed : 4.0,
//startScale endScale 代替scale设置粒子在生命周期内显示的初始和结束尺寸,也是动态混合的作用。
startScale : 1.0,
endScale : 5.0,
particleSize : 25.0
};
Cesium.knockout.track(viewModel);
var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);
var entityPosition = new Cesium.Cartesian3();
var entityOrientation = new Cesium.Quaternion();
var rotationMatrix = new Cesium.Matrix3();
var modelMatrix = new Cesium.Matrix4();
//计算entity的4x4矩阵
function computeModelMatrix(entity, time) {
//根据指定的时间为实体的转换计算模型矩阵
return entity.computeModelMatrix(time, new Cesium.Matrix4());
}
var emitterModelMatrix = new Cesium.Matrix4();
var translation = new Cesium.Cartesian3();
var rotation = new Cesium.Quaternion();
var hpr = new Cesium.HeadingPitchRoll();
var trs = new Cesium.TranslationRotationScale();
//计算粒子发射模型矩阵,是一个4x4变换矩阵,用于在粒子系统内部坐标系中转换粒子系统发射器。
function computeEmitterModelMatrix() {
hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr);
//设置尾气和实体之间的距离,参数分别为 x, y and z coordinates
trs.translation = Cesium.Cartesian3.fromElements(-4.0, 0.0, 1.4, translation);
trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);
//从TranslationRotationScale创建一个4x4矩阵
//Creates a Matrix4 instance from a TranslationRotationScale instance.
return Cesium.Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix);
}
var pos1 = Cesium.Cartesian3.fromDegrees(-75.15787310614596, 39.97862668312678);
var pos2 = Cesium.Cartesian3.fromDegrees(-75.1633691390455, 39.95355089912078);
var position = new Cesium.SampledPositionProperty();
position.addSample(start, pos1);//开始时间和坐标
position.addSample(stop, pos2);//结束时间和坐标
var entity = viewer.entities.add({
availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
start : start,
stop : stop
})]),
model : {
uri : '../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck-kmc.glb',
minimumPixelSize : 64
},
viewFrom: new Cesium.Cartesian3(-100.0, 0.0, 100.0),
position : position,
//VelocityOrientationProperty(速度方向属性):基于所给的位置属性的速度来得出一个四元旋转属性
orientation : new Cesium.VelocityOrientationProperty(position)
});
viewer.trackedEntity = entity;
var scene = viewer.scene;
//初始化设置ParticleSystem的各项参数,因为这是一个动态变化的粒子,所以有start、end和min、max等参数设置
var particleSystem = scene.primitives.add(new Cesium.ParticleSystem({
image : '../../SampleData/smoke.png',
//startColor endColor,代替color使得粒子的颜色在粒子的生命过程中会在这两种颜色之间平滑地混合。
startColor : Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7),
endColor : Cesium.Color.WHITE.withAlpha(0.0),
//startScale endScale代替scale设置粒子在生命周期内显示的初始和结束尺寸,也是动态混合的作用。
// 值越大,初始时粒子图的大小越大
startScale : viewModel.startScale,
endScale : viewModel.endScale,
//particleLife:设置改值将会覆盖minimumParticleLife和maximumParticleLife
//minimumParticleLife:设置粒子寿命的可能持续时间的最小界限(以秒为单位),粒子的实际寿命将随机生成
//maximumParticleLife:设置粒子寿命的可能持续时间的最大界限(以秒为单位),粒子的实际寿命将随机生成
//值越大,尾巴越长
minimumParticleLife : viewModel.minimumParticleLife,
maximumParticleLife : viewModel.maximumParticleLife,
//设置粒子图发射之后的最小/最大边界(以米/秒为单位)
//值越大,尾巴飘的越高
minimumSpeed : viewModel.minimumSpeed,
maximumSpeed : viewModel.maximumSpeed,
//设置发射出的图像大小
imageSize : new Cesium.Cartesian2(viewModel.particleSize, viewModel.particleSize),
//每秒发射的粒子数。
//数值越大,越浓密
emissionRate : viewModel.emissionRate,
//粒子系统生命周期内,按照指定周期,爆发一定数量的粒子。三个参数(time,minimum,maximum)
bursts : [
// these burst will occasionally sync to create a multicolored effect
// 爆炸出的粒子的密度
new Cesium.ParticleBurst({time : 5.0, minimum : 10, maximum : 100}),
new Cesium.ParticleBurst({time : 10.0, minimum : 50, maximum : 100}),
new Cesium.ParticleBurst({time : 15.0, minimum : 200, maximum : 300})
],
//lifetime:粒子系统会发射多久粒子,以秒为单位。默认为最大值
lifetime : 16.0,
// emitter:粒子系统的粒子发射器;包括四种发射器:圆形、锥体、球体、长方体
emitter : new Cesium.CircleEmitter(2.0),
//emitterModelMatrix:4x4变换矩阵,用于在粒子系统内部坐标系中转换粒子系统发射器。
emitterModelMatrix : computeEmitterModelMatrix(),
//一组强制回调。回调被传递一个粒子和上次的差值
//updateCallback :每帧都要调用的回调函数来更新粒子。
//此updateCallback作用是用来改变粒子系统在每一个时间步长的属性,可以强制改变粒子系统的颜色、大小等值
//在updateCallback更改gravity重力参数,值越大,烟雾离模型越近的地方飘的越高,可能出现负值,此时烟雾会向下方飘
updateCallback : applyGravity
}));
var gravityScratch = new Cesium.Cartesian3();
//参数p-Particle是需要被更新的粒子,dt-自上次更新之后的秒数
function applyGravity(particle, dt) {
// We need to compute a local up vector for each particle in geocentric space.
var position = particle.position;
Cesium.Cartesian3.normalize(position, gravityScratch);
Cesium.Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch);
particle.velocity = Cesium.Cartesian3.add(particle.velocity, gravityScratch, particle.velocity);
}
/*
viewer.scene.preUpdate获取在更新或呈现场景之前将引发的事件。事件的订阅者接收Scene实例作为第一个参数,将当前时间作为第二个参数。
这个函数调用非常频繁,相当于每帧刷新之前都会调用此函数。
*/
viewer.scene.preUpdate.addEventListener(function(scene, time) {
//modelMatrix-将粒子系统从模型转换为世界坐标的4x4变换矩阵
particleSystem.modelMatrix = computeModelMatrix(entity, time);
// Account for any changes to the emitter model matrix.
//emitterModelMatrix-4x4变换矩阵,在粒子系统本地坐标系中变换粒子系统发射器。
particleSystem.emitterModelMatrix = computeEmitterModelMatrix();
// Spin the emitter if enabled.
if (viewModel.spin) {
viewModel.heading += 1.0;
viewModel.pitch += 1.0;
viewModel.roll += 1.0;
}
});
Particle System例子中后面的代码参照cesium