本篇文章请搭配
[3D地图-CesiumJS系列] 一、快速上手
[3D地图-CesiumJS系列] 二、建立飞航轨迹及动画
今天要来介绍CesiumJS的粒子系统。
粒子系统是什麽呢?
粒子系统(Particle system)是一种图形技术,可以把许多小图像的集合来模拟物理现象。
当它们计算过後叠在一起时,会形成复杂的模糊对象,
可以仿造出烟雾、火、天气现象等效果。
↓ 今天使用的粒子图像如下,为官方SampleData中提供的smoke.png档
↓ 将它们叠在一起仿制的烟雾图像
那就让我们一步一步开始吧!
在根目录下建立一个html页面,取名为Cesium_particle.html。
如果还不会CesiumJS专案建置的人,请参考前天的文章。
↓ 建立一个存放地图的div
<div id="cmap"></div>
↓ 引入Cesium.js
<script src="../Build/Cesium/Cesium.js"></script>
↓ 引入css
<link rel="stylesheet" href="../Build/Cesium/Widgets/widgets.css" />
↓ css让地图满版
<style>
html,
body,
#cmap {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
↓ 初始化地图,新建一个Cesium.Viewer的物件,第一个参数存放地图的容器Id,第二个参数为设定(选填)。
const viewer = new Cesium.Viewer('cmap');
↓ 结果
const start = Cesium.JulianDate.fromDate(new Date("2020-10-14T21:00:00Z"));
const stop = Cesium.JulianDate.addSeconds(start, 100, 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;
viewer.timeline.zoomTo(start, stop);
↓ 时间轴
↓ 设定起始座标及终点座标
const positionStart = Cesium.Cartesian3.fromDegrees(
-75.15787310614596,
39.97862668312678
);
const positionEnd = Cesium.Cartesian3.fromDegrees(
-75.1633691390455,
39.95355089912078
);
↓ Cesium.SampledPositionProperty的物件提供内插计算方法,可以计算每个时间区间相对应的座标
let position = new Cesium.SampledPositionProperty();
position.addSample(start, positionStart); // 填入起始时间及座标
position.addSample(stop, positionEnd); // 填入结束时间及座标
↓ 在地图上新增车机模型
let entity = viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: start,
stop: stop,
}),
]),
model: {
uri: "Apps/SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb",
minimumPixelSize: 64,
},
viewFrom: new Cesium.Cartesian3(-150.0, -100.0, 100.0), // 右方150,前方100,上方100
position: position,
orientation: new Cesium.VelocityOrientationProperty(position),
});
↓ 将车机实体设定在地图上
viewer.trackedEntity = entity;
↓ 结果
要计算粒子随机排放,并且用4x4矩阵去储存当下粒子集合的状态,要使用以下CesiumJS提供的物件及方法。
↓ 排放模型计算工具
const emitterModelMatrix = new Cesium.Matrix4(); // 4x4矩阵
const translation = new Cesium.Cartesian3(); // 3维座标点
const trs = new Cesium.TranslationRotationScale(); // 座标转换
// 除了3维座标外,加入旋转角度
const rotation = new Cesium.Quaternion();
// 一种旋转表达方式,heading表示z轴,pitch表示y轴,roll表示x轴
let hpr = new Cesium.HeadingPitchRoll();
↓ 计算排放模型的阵列
function ComputeEmitterModelMatrix() {
hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr);
trs.translation = Cesium.Cartesian3.fromElements(-4.0, 0.0, 1.4, translation);
trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);
return Cesium.Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix);
}
↓ 新增一个物件,用来做为粒子系统的参数设定
let viewModel = {
emissionRate: 5.0,
minimumParticleLife: 1.2,
maximumParticleLife: 1.2,
minimumSpeed: 1.0,
maximumSpeed: 4.0,
startScale: 1.0,
endScale: 5.0,
};
Cesium.ParticleSystem设定
↓ 在地图上新增粒子系统物件
let particleSystem = viewer.scene.primitives.add(
new Cesium.ParticleSystem({
image: "Apps/SampleData/smoke.png",
startColor: Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7),
endColor: Cesium.Color.WHITE.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: viewModel.emissionRate,
bursts: [
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: ComputeEmitterModelMatrix(),
updateCallback: ApplyGravity,
})
);
↓ 粒子系统的updateCallback function
const gravityScratch = new Cesium.Cartesian3();
function ApplyGravity(p, dt) {
Cesium.Cartesian3.normalize(p.position, gravityScratch);
Cesium.Cartesian3.multiplyByScalar(gravityScratch
, viewModel.gravity * dt, gravityScratch);
p.velocity = Cesium.Cartesian3.add(p.velocity
, gravityScratch, p.velocity);
}
↓ 地图新增视觉更新前的事件,并且在每次更新时,重新计算粒子系统的烟雾排放。
viewer.scene.preUpdate.addEventListener(function (scene, time) {
particleSystem.modelMatrix = entity.computeModelMatrix(time, new Cesium.Matrix4());
particleSystem.emitterModelMatrix = ComputeEmitterModelMatrix();
});
↓ 结果
可以用Cesium.knockout来把粒子设定参数跟dom标签进行绑定,这边就不赘述作法,直接使用UI面板修改粒子设定。
↓ 当scale设定很小时,烟雾范围很小
↓ 当scale设定很大时,烟雾范围很大
↓ gravity设定很高时,烟雾往上飘
↓ life设定很长时,粒子存在时间很久,烟雾会拉很长
↓ rate设定很快时,烟雾较为密集
假如要计算整个城市里面的车辆废气排放,
或者要监测工厂黑烟排放,
活用CesiumJS的粒子系统想必能一目了然!
>>: [Day 29]-【STM32系列】实作-步进马达 + ULN2003 控制
有些公司永远在徵人(人员一直在流动),实际去应徵过後,会深刻理解到为什麽。 前几天提到GitHub时...
前言 档案架构是在开发前应该要先了解的事,可以让我们在对的地方做对的事情,以节省宝贵的时间。主要有四...
想说CBPR是什麽? 与GDPR不同的是,CBPR并非是一套要求所有国家遵循的规范, 而更像是一种参...
上一篇,提到了可以在 tableView(_:willDisplay:forRowAt:) 中发动 ...
由於 Mautic 是一个自动化行销利器,那麽寄发电子邮件便是一个必须的功能。不过在开发时一再的利用...