需求
需要实现粒子爆炸/气体泄漏的效果
图片直接用cesium自带的smoke那个透明的粒子图片即可
sizeInMeters这个参数控制是否随米而变化
代码
javascript
const viewer = new Cesium.Viewer("cesiumContainer");
// 设置时间范围
const start = Cesium.JulianDate.fromDate(new Date());
const stop = Cesium.JulianDate.addSeconds(start, 30, new Cesium.JulianDate());
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 1;
viewer.clock.shouldAnimate = true;
// 粒子系统视图模型
const viewModel = {
emissionRate: 0, // 初始不发射粒子
minimumParticleLife: 1.0,
maximumParticleLife: 2.0,
minimumSpeed: 5.0,
maximumSpeed: 10.0,
startScale: 1.0,
endScale: 5.0,
particleSize: 20.0,
};
const particleSystem = viewer.scene.primitives.add(
new Cesium.ParticleSystem({
image: "../SampleData/smoke.png", // 替换为你自己的粒子图片
startColor: Cesium.Color.YELLOW.withAlpha(0.7),
endColor: Cesium.Color.RED.withAlpha(0.0),
startScale: viewModel.startScale,
endScale: viewModel.endScale,
minimumParticleLife: viewModel.minimumParticleLife,
maximumParticleLife: viewModel.maximumParticleLife,
minimumSpeed: viewModel.minimumSpeed,
maximumSpeed: viewModel.maximumSpeed,
imageSize: new Cesium.Cartesian2(viewModel.particleSize, viewModel.particleSize),
emissionRate: 20,
bursts: [
new Cesium.ParticleBurst({
time: 0.0, // 粒子爆炸立即发生
minimum: 100,
maximum: 200,
}),
],
lifetime: 5.0, // 粒子系统的生存时间
emitter: new Cesium.SphereEmitter(2.0), // 粒子爆炸范围
emitterModelMatrix: Cesium.Matrix4.fromTranslation(Cesium.Cartesian3.fromDegrees(114.25, 30.5, 500)), // 定点爆炸的位置
})
);
![[Pasted image 20241019141500.png]]
调试
如果要在Cesium沙盒调试请用以下代码
javascript
const viewer = new Cesium.Viewer("cesiumContainer");
//Set the random number seed for consistent results.
Cesium.Math.setRandomNumberSeed(3);
//Set bounds of our simulation time
const start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16));
const 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);
const viewModel = {
emissionRate: 5.0,
gravity: 0.0,
minimumParticleLife: 1.2,
maximumParticleLife: 1.2,
minimumSpeed: 1.0,
maximumSpeed: 4.0,
startScale: 1.0,
endScale: 5.0,
particleSize: 25.0,
};
Cesium.knockout.track(viewModel);
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);
const entityPosition = new Cesium.Cartesian3();
const entityOrientation = new Cesium.Quaternion();
const rotationMatrix = new Cesium.Matrix3();
const modelMatrix = new Cesium.Matrix4();
function computeModelMatrix(entity, time) {
return entity.computeModelMatrix(time, new Cesium.Matrix4());
}
const emitterModelMatrix = new Cesium.Matrix4();
const translation = new Cesium.Cartesian3();
const rotation = new Cesium.Quaternion();
let hpr = new Cesium.HeadingPitchRoll();
const trs = new Cesium.TranslationRotationScale();
const position2 = Cesium.Cartesian3.fromDegrees(94.875771, 43.596378, 10);
function computeEmitterModelMatrix() {
return Cesium.Matrix4.fromTranslation(position2);
}
const entity = viewer.entities.add({
position: position2,
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 红色
outlineColor: Cesium.Color.BLACK, // 边框颜色
outlineWidth: 2 // 边框宽度
}
});
viewer.trackedEntity = entity;
const scene = viewer.scene;
const particleSystem = scene.primitives.add(
new Cesium.ParticleSystem({
image: "../SampleData/fire.png",
startColor: Cesium.Color.YELLOW.withAlpha(0.7),
endColor: Cesium.Color.RED.withAlpha(0.3),
startScale: viewModel.startScale,
endScale: viewModel.endScale,
minimumParticleLife: viewModel.minimumParticleLife,
maximumParticleLife: viewModel.maximumParticleLife,
minimumSpeed: viewModel.minimumSpeed,
maximumSpeed: viewModel.maximumSpeed,
imageSize: new Cesium.Cartesian2(
viewModel.particleSize,
viewModel.particleSize,
),
emissionRate: viewModel.emissionRate,
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: 16.0,
emitter: new Cesium.CircleEmitter(2.0),
emitterModelMatrix: Cesium.Matrix4.fromTranslation(position2),
// updateCallback: applyGravity,
}),
);
const gravityScratch = new Cesium.Cartesian3();
function applyGravity(p, dt) {
// We need to compute a local up vector for each particle in geocentric space.
const 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);
}
Cesium.knockout
.getObservable(viewModel, "emissionRate")
.subscribe(function (newValue) {
particleSystem.emissionRate = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "particleSize")
.subscribe(function (newValue) {
const particleSize = parseFloat(newValue);
particleSystem.minimumImageSize.x = particleSize;
particleSystem.minimumImageSize.y = particleSize;
particleSystem.maximumImageSize.x = particleSize;
particleSystem.maximumImageSize.y = particleSize;
});
Cesium.knockout
.getObservable(viewModel, "minimumParticleLife")
.subscribe(function (newValue) {
particleSystem.minimumParticleLife = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "maximumParticleLife")
.subscribe(function (newValue) {
particleSystem.maximumParticleLife = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "minimumSpeed")
.subscribe(function (newValue) {
particleSystem.minimumSpeed = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "maximumSpeed")
.subscribe(function (newValue) {
particleSystem.maximumSpeed = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "startScale")
.subscribe(function (newValue) {
particleSystem.startScale = parseFloat(newValue);
});
Cesium.knockout
.getObservable(viewModel, "endScale")
.subscribe(function (newValue) {
particleSystem.endScale = parseFloat(newValue);
});
const options = [
{
text: "Circle Emitter",
onselect: function () {
particleSystem.emitter = new Cesium.CircleEmitter(2.0);
},
},
{
text: "Sphere Emitter",
onselect: function () {
particleSystem.emitter = new Cesium.SphereEmitter(2.5);
},
},
{
text: "Cone Emitter",
onselect: function () {
particleSystem.emitter = new Cesium.ConeEmitter(
Cesium.Math.toRadians(45.0),
);
},
},
{
text: "Box Emitter",
onselect: function () {
particleSystem.emitter = new Cesium.BoxEmitter(
new Cesium.Cartesian3(10.0, 10.0, 10.0),
);
},
},
];
Sandcastle.addToolbarMenu(options);