Cesium实战 - 实现大气云层效果
- Cesium 实现大气云层效果
- 主要思路
- 核心代码
- 在线示例
Cesium 实现大气云层效果
在实际开发中,一般会有天气的效果,雨雪雾比较常见,相关的博客也很多,但是关于云层的天气效果还是比较少,而官方只有云朵效果,没有云层,本文介绍一下大气云层的效果。
本文包括主要思路、核心代码和在线示例三部分。
主要思路
1. 添加矩形带有高度的矩形包裹地球。
实现思路也比较简单:既然是大气云层效果,那么必然是覆盖在地球之上的,开始想着使用球体来实现地球覆盖效果。
但是经过尝试,发现不太合适,需要将球心设置在地心,半径大于地球半径,不合理,于是放弃。
后来相当,地球范围无非是 [-180, -90, 180, 90]
,那么在地球上覆盖一个矩形(Rectangle
)应该就可以。
尝试之后,发现非常完美;大气云层应该有高度,给矩形设置高度即可。
2. 给矩形设置动态效果,使云层动起来。
添加矩形之后,添加图片材质,虽然看起来是云层,但是云层并没有动,看起来不太合理。
于是,通过着色器给图片材质增加了一个动态效果,这样看起来云层是动态的,比较切近实际。
核心代码
1. 初始化以及参数。
// 初始化地球
const viewer = new Cesium.Viewer("cesiumContainer");
const entities = viewer.entities;
// 云层图片
const image = 'https://openlayers.vip/examples/resources/earth_cloud.png';
// 云层颜色
const color = new Cesium.Color(1.0, 1.0, 1.0, 1);
// 用于计算云层速度
const time = 20;
// 图片材质
const imageMaterial = new Cesium.ImageMaterialProperty({
image: image
});
2. 创建矩形实体对象。
// 创建矩形实体
const entity = entities.add({
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
material: imageMaterial,
},
});
2. 创建动态效果。
// 动态云层效果类
function CloudEffectMaterialProperty() {
this._definitionChanged = new Cesium.Event();
// 速度
this.speed = 200;
// 颜色
this.color = color;
// 图层
this._image = image;
// 时间
this.time = time;
// 计算持续时间
const durationDefault = 100000;
this.duration = 100 / this.speed * durationDefault;
this._time = new Date().getTime();
}
// 定义属性
Object.defineProperties(CloudEffectMaterialProperty.prototype, {
isConstant: {
get: function() {
return false;
}
},
definitionChanged: {
get: function() {
return this._definitionChanged;
}
},
color: Cesium.createPropertyDescriptor('color')
});
CloudEffectMaterialProperty.prototype.getType = function(time) {
return 'CloudEffect';
};
CloudEffectMaterialProperty.prototype.getValue = function(time, result) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(
this._color, time, Cesium.Color.WHITE, result.color);
result.time = ((new Date().getTime() - this._time) % this.duration) / this.duration;
return result;
};
CloudEffectMaterialProperty.prototype.equals = function(other) {
return (this === other ||
(other instanceof CloudEffectMaterialProperty &&
Cesium.Property.equals(this._color, other._color) &&
Cesium.Property.equals(this.speed, other.speed)));
}
;
Cesium.Material.CloudEffectType = 'CloudEffect';
Cesium.Material.CloudEffectImage = image;
Cesium.Material.CloudEffectColor = color;
// 着色器代码
Cesium.Material.CloudEffectSource = `
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
vec4 colorImage = texture(image, vec2(fract(st.s + time),st.t));
material.alpha = colorImage.a * color.a ;
material.diffuse = color.rgb ;
return material;
}
`;
// 添加着色器
Cesium.Material._materialCache.addMaterial(Cesium.Material.CloudEffectType, {
fabric: {
type: Cesium.Material.CloudEffectType,
uniforms: {
color: Cesium.Material.CloudEffectColor,
image: Cesium.Material.CloudEffectImage,
constantSpeed: constantSpeed,
time: time
},
source: Cesium.Material.CloudEffectSource
},
translucent: function(material) {
return true;
}
});
viewer.zoomTo(viewer.entities);
Sandcastle.addToolbarButton("开启动态云层", function () {
alert('动态云层!');
entity.rectangle.height = 0;
entity.rectangle.extrudedHeight = 100000;
entity.rectangle.material = new CloudEffectMaterialProperty();
});
Sandcastle.addToolbarButton("开启静态云层", function () {
alert('静态云层!');
entity.rectangle.height = undefined;
entity.rectangle.extrudedHeight = undefined;
entity.rectangle.material = imageMaterial;
});
在线示例
示例中展示了, 三维地图大气云层效果。
Cesium 沙盒示例