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 沙盒示例