非科班Java出身GISer

非科班Java出身GISer

Cesium 实现大气云层效果

在实际开发中,一般会有天气的效果,雨雪雾比较常见,相关的博客也很多,但是关于云层的天气效果还是比较少,而官方只有云朵效果,没有云层,本文介绍一下大气云层的效果

本文包括三部分。


主要思路

1. 添加矩形带有高度的矩形包裹地球。

实现思路也比较简单:既然是大气云层效果,那么必然是覆盖在地球之上的,开始想着使用球体来实现地球覆盖效果。

但是经过尝试,发现不太合适,需要将球心设置在地心,半径大于地球半径,不合理,于是放弃。

后来相当,地球范围无非是 [-180, -90, 180, 90],那么在地球上覆盖一个矩形(Rectangle)应该就可以。

尝试之后,发现非常完美;大气云层应该有高度,给矩形设置高度即可。

2. 给矩形设置动态效果,使云层动起来。

添加矩形之后,添加图片材质,虽然看起来是云层,但是云层并没有动,看起来不太合理。

于是,通过着色器给图片材质增加了一个动态效果,这样看起来云层是动态的,比较切近实际。

Cesium实战 - 实现大气云层效果-LMLPHP


核心代码

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

Cesium实战 - 实现大气云层效果-LMLPHP

05-31 18:13