首先,来个最简单的粒子特效:
雨:
var rainParticleSize = 15.0;
var rainRadius = 100000.0;
var rainImageSize = new Cesium.Cartesian2(rainParticleSize, rainParticleSize * 2.0);
var rainGravityScratch = new Cesium.Cartesian3();
var rainUpdate = function (particle, dt) {
rainGravityScratch = Cesium.Cartesian3.normalize(particle.position, rainGravityScratch);
rainGravityScratch = Cesium.Cartesian3.multiplyByScalar(rainGravityScratch, -1050.0, rainGravityScratch);
particle.position = Cesium.Cartesian3.add(particle.position, rainGravityScratch, particle.position);
var distance = Cesium.Cartesian3.distance(viewer.scene.camera.position, particle.position);
if (distance > rainRadius) {
particle.endColor.alpha = 0.0;
} else {
particle.endColor.alpha = rainSystem.endColor.alpha / (distance / rainRadius + 0.1);
}
};
rainSystem = new Cesium.ParticleSystem({
modelMatrix: new Cesium.Matrix4.fromTranslation(viewer.scene.camera.position),
speed: -1.0,
lifetime: 15.0,
emitter: new Cesium.SphereEmitter(rainRadius),
startScale: 1.0,
endScale: 0.0,
image: 'images/circular_particle.png',
emissionRate: 9000.0,
startColor: new Cesium.Color(0.27, 0.5, 0.70, 0.0),
endColor: new Cesium.Color(0.27, 0.5, 0.70, 0.98),
imageSize: rainImageSize,
updateCallback: rainUpdate
});
viewer.scene.primitives.add(rainSystem);
以此,我们来分析粒子功能的一些方法和属性。
首先,我们需要创立一个粒子特效(针对于每一个粒子)。
下面,是创建粒子特效的第一步。
rainSystem = new Cesium.ParticleSystem({
modelMatrix: new Cesium.Matrix4.fromTranslation(viewer.scene.camera.position),
speed: -1.0,
lifetime: 15.0,
emitter: new Cesium.SphereEmitter(rainRadius),
startScale: 1.0,
endScale: 0.0,
image: 'images/circular_particle.png',
emissionRate: 9000.0,
startColor: new Cesium.Color(0.27, 0.5, 0.70, 0.0),
endColor: new Cesium.Color(0.27, 0.5, 0.70, 0.98),
imageSize: rainImageSize,
updateCallback: rainUpdate
});
ParticleSystem这个函数是专门的粒子功能类。
startScale:代表了粒子初始化的密集程度;
endScale:代表了粒子消失的密集程度;
Scale:它的优先级高于startScale和endScale,当它存在时,startScale和endScale都失效了。它是一个恒定值。
startColor:代表粒子刚出现时,粒子显示的颜色效果;
endColor:代表粒子结束时,粒子显示的颜色效果;
Color:它的优先级高于startColor和endColor,当它存在时,startColor和endColor都失效了。它是一个恒定值。
image:代表粒子图片的路径存放位置。Cesium中我知道的有两种粒子特效展示,一种是这个用png图片展示粒子特效,一种是用着色器来展示粒子特效。
minimumImageSize:代表粒子图片的最小值;
maximumImageSize:代表粒子图片的最大值;
imageSize:它的优先级高于minimumImageSize和maximumImageSize,当它存在时,minimumImageSize和maximumImageSize都失效了。它是一个恒定值。另外,当minimumImageSize和
maximumImageSize配合使用的时候,粒子图片的大小是在最小值和最大值之间随机选择的。
minimumSpeed:代表粒子速度的最小值;
maximumSpeed:代表粒子速度的最大值;
speed:它的优先级高于minimumSpeed和maximumSpeed,当它存在时,minimumSpeed和maximumSpeed都失效了。它是一个恒定值。并且它也有系统默认的值1.0。
minimumParticleLife:粒子持续时间的最小值;
maximumParticleLife:粒子持续时间的最大值;
particleLife:它的优先级高于minimumParticleLife和maximumParticleLife,当它存在时,minimumParticleLife和maximumParticleLife都失效了。它是一个恒定值。并且它也有系统默认的值5.0。
lifetime:代表粒子发射时间。
minimumMass:代表粒子的最小质量;
maximumMass:代表粒子的最大质量;
mass:它的优先级高于minimumMass和maximumMass,当它存在时,minimumMass和maximumMass都失效了。它是一个恒定值。并且它也有系统默认的值1.0。
sizeInMeters:代表粒子的大小的像素还是米。true:以米为单位调整粒子大小;否则,大小以像素为单位。
bursts:这个是设定某一个时间点具有爆炸效果;比如说做爆炸特效或者烟花特效等;
使用方法:
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})
],
emissionRate:代表每秒发射的粒子个数,它有一个默认值5.
emitter:代表粒子发射的形状,总共有四个:BoxEmitter、CircleEmitter、ConeEmitter、SphereEmitter。
使用方法:
BoxEmitter 类在盒子里(box)里随机一个位置,沿着盒子的6个面的法向量向外运动。它接受一个Cartesian3 参数,定义了盒子的长宽高。
emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(10.0, 10.0, 10.0));
CircleEmitter类在圆形面上随机一个位置,粒子方向是发射器的向上向量。它接受一个float参数指定了圆的半径。
emitter: new Cesium.CircleEmitter(5.0);
ConeEmitter在椎体顶点产生粒子,粒子方向在椎体内随机一个角度向外。它接受一个float参数,制定了锥角。椎的方向沿着向上轴。
emitter: new Cesium.ConeEmitter(Cesium.Math.toRadians(30.0));
SphereEmitter类在球体内随机产生粒子,初始速度是沿着秋心向外。它接受一个float参数指定了球体半径。
emitter: new Cesium.SphereEmitter(5.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);
}
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;
}
emitterModelMatrix:在粒子系统的局部坐标系内变换粒子发射器。说白了,就是在粒子进行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());
}
另外,我需要说的是,如果需要展示粒子特效,Cesium的shouldAnimate必须为true。
第二步,就是把该粒子加入到场景中:
viewer.scene.primitives.add(rainSystem);