Cesium实现水波纹效果,告警效果

2,807 阅读6分钟

方式一: 利用CallbackProperty+setTimeOut

function addCircleRipple(viewer,data){
    var r1=data.minR,r2=data.minR;

    function changeR1() { //这是callback,参数不能内传
        r1=r1+data.deviationR;
        if(r1>=data.maxR){
            r1=data.minR;
        }

        return r1;
    }
    function changeR2() {
      // debugger
        r2=r2+data.deviationR;
        if(r2>=data.maxR){
            r2=data.minR;
        }
        return r2;
    }
    viewer.entities.add({
        id:data.id,
        name:"",
        position:Cesium.Cartesian3.fromDegrees(data.lon,data.lat,data.height),
        ellipse : {
            semiMinorAxis :new Cesium.CallbackProperty(changeR1,false),
            semiMajorAxis :new Cesium.CallbackProperty(changeR1,false),
            height:data.height,
            material:new Cesium.ImageMaterialProperty({
                image:data.imageUrl,
                repeat:new Cesium.Cartesian2(1.0, 1.0),
                transparent:true,
                color:new Cesium.CallbackProperty(function () {
                    var alp=1-r1/data.maxR;
                    return Cesium.Color.WHITE.withAlpha(alp)  //entity的颜色透明 并不影响材质,并且 entity也会透明哦
                },false)
            })
        }
    });
    setTimeout(function () {
        viewer.entities.add({
            name:"",
            position:Cesium.Cartesian3.fromDegrees(data.lon,data.lat,data.height),
            ellipse : {
                semiMinorAxis :new Cesium.CallbackProperty(changeR2,false),
                semiMajorAxis :new Cesium.CallbackProperty(changeR2,false),
                height:data.height,
                material:new Cesium.ImageMaterialProperty({
                    image:data.imageUrl,
                    repeat:new Cesium.Cartesian2(1.0, 1.0),
                    transparent:true,
                    color:new Cesium.CallbackProperty(function () {
                        var alp=1;
                        alp=1-r2/data.maxR;
                        return Cesium.Color.WHITE.withAlpha(alp)
                    },false)
                })
            }
        });
    },data.eachInterval)
}

var lon=121.286419;
var lat=31.864436;
addCircleRipple(_viewer,{ //默认只绘制两个圆圈叠加 如遇绘制多个,请自行源码内添加。
    id:"111",
    lon:lon,
    lat:lat,
    height:500,
    maxR:3000,
    minR:0,//最好为0
    deviationR:10,//差值 差值也大 速度越快
    eachInterval:2000,//两个圈的时间间隔
    imageUrl:imgRedCircle
});

_viewer.zoomTo(_viewer.entities);

// 如果添加中心线的话:
viewer.entities.add({
    name:"",
    polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights([
            lon,lat,0,
            lon,lat, 5000,]
        ),
        width: 4,
        material : new Cesium.PolylineGlowMaterialProperty({ //发光线
            glowPower : 0.1,
            color : Cesium.Color.RED
        })
    }
});

方式二:自定义材质

参考文献: Cesium动态圆扩散效果

//材质类
function EllipsoidFadeMaterialProperty(color, duration) {
    this._definitionChanged = new Cesium.Event();
    this._color = undefined;
    this._colorSubscription = undefined;
    this.color = color;
    this.duration = duration;
    this._time = (new Date()).getTime();
}

Object.defineProperties(EllipsoidFadeMaterialProperty.prototype, {
    isConstant: {
        get: function() {
            return false;
        }
    },
    definitionChanged: {
        get: function() {
            return this._definitionChanged;
        }
    },
    color: Cesium.createPropertyDescriptor('color')
});

EllipsoidFadeMaterialProperty.prototype.getType = function(time) {
    return 'EllipsoidFade';
}

EllipsoidFadeMaterialProperty.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;
}

EllipsoidFadeMaterialProperty.prototype.equals = function(other) {
    return this === other ||
        (other instanceof EllipsoidFadeMaterialProperty &&
            Cesium.Property.equals(this._color, other._color))
}

Cesium.EllipsoidFadeMaterialProperty = EllipsoidFadeMaterialProperty;
Cesium.Material.EllipsoidFadeType = 'EllipsoidFade';
// Cesium.Material.EllipsoidFadeSource =...

Cesium.Material._materialCache.addMaterial(Cesium.Material.EllipsoidFadeType, {
    fabric: {
        type: Cesium.Material.EllipsoidFadeType,
        uniforms: {
            color: new Cesium.Color(1.0, 0.0, 0.0, 1),
            time: 0
        },
        source: Cesium.Material.EllipsoidFadeSource
    },
    translucent: function(material) {
        return true;
    }
});

//使用entity
_viewer.entities.add({
            name: 'EllipsoidFade',
            position: vm.clickPosition3,
            ellipse: {
                height: 0,
                semiMinorAxis: 130.0,
                semiMajorAxis: 130.0,
                material: new Cesium.EllipsoidFadeMaterialProperty(Cesium.Color.RED, 2000)
            }
        });

方式三:自定义着色器的方式

参考文献: blog.csdn.net/A873054267/… blog.csdn.net/Apple_Coco/…

/*
        添加扫描线 depth关闭   lon:-74.01296152309055 lat:40.70524201566827 height:129.14366696393927
        viewer
        cartographicCenter 扫描中心
        maxRadius 最大半径 米
        scanColor 扫描颜色
        duration 持续时间 毫秒
        */
export function AddCircleScanPostStage(Cesium, viewer, cartographicCenter, maxRadius, scanColor, duration) {
    console.log("cesium, ", Cesium);
    var ScanSegmentShader =
        "uniform sampler2D colorTexture;\n" +  //颜色纹理
        "uniform sampler2D depthTexture;\n" + //深度纹理
        "varying vec2 v_textureCoordinates;\n" + //纹理坐标
        "uniform vec4 u_scanCenterEC;\n" +  //扫描中心
        "uniform vec3 u_scanPlaneNormalEC;\n" +  //扫描平面法向量
        "uniform float u_radius;\n" +   //扫描半径
        "uniform vec4 u_scanColor;\n" +   //扫描颜色
        //根据二维向量和深度值 计算距离camera的向量
        "vec4 toEye(in vec2 uv, in float depth)\n" +
        " {\n" +
        " vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));\n" +//
        " vec4 posInCamera =czm_inverseProjection * vec4(xy, depth, 1.0);\n" +//看看源码中关于此函数的解释是,cesium系统自动生成的4*4的反投影变换矩阵,从clip坐标转为眼睛坐标,clip坐标是指顶点着色器的坐标系统gl_position输出的

        " posInCamera =posInCamera / posInCamera.w;\n" +  //将视角坐标除深度分量
        " return posInCamera;\n" +
        " }\n" +
        //点在平面上的投影,输入参数为 平面法向量,平面起始点,测试点
        "vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point)\n" +
        "{\n" +
        //计算测试点与平面起始点的向量
        "vec3 v01 = point -planeOrigin;\n" +
        //平面法向量与 测试点与平面上的点 点积  点积的几何意义,b在a上的投影长度,
        //即v01在平面法向量上的长度
        "float d = dot(planeNormal, v01) ;\n" +
        //planeNormal * d 即为v01在平面法向量上的投影向量
        //根据三角形向量相加为0的原则 即可得点在平面上的投影
        "return (point - planeNormal * d);\n" +
        "}\n" +
        //获取深度值,根据纹理坐标获取深度值
        "float getDepth(in vec4 depth)\n" +
        "{\n" +
        "float z_window = czm_unpackDepth(depth);\n" +  //源码解释将一个vec4向量还原到0,1内的一个数
        "z_window = czm_reverseLogDepth(z_window);\n" + //czm_reverseLogDepth解开深度
        "float n_range = czm_depthRange.near;\n" +//
        "float f_range = czm_depthRange.far;\n" +
        "return (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n" +
        "}\n" +

        "void main()\n" +
        "{\n" +
        "gl_FragColor = texture2D(colorTexture, v_textureCoordinates);\n" +  //片元颜色
        "float depth = getDepth( texture2D(depthTexture, v_textureCoordinates));\n" +//根据纹理获取深度值
        "vec4 viewPos = toEye(v_textureCoordinates, depth);\n" +//根据纹理坐标和深度值获取视点坐标
        //点在平面上的投影,平面法向量,平面中心,视点坐标
        "vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz, u_scanCenterEC.xyz, viewPos.xyz);\n" +
        //计算投影坐标到视点中心的距离
        "float dis = length(prjOnPlane.xyz - u_scanCenterEC.xyz);\n" +
        //如果在扫描半径内,则重新赋值片元颜色
        "if(dis < u_radius)\n" +
        "{\n" +
        //计算与扫描中心的距离并归一化
        "float f =  dis/ u_radius;\n" +
        //原博客如下,实际上可简化为上式子
        //"float f = 1.0 -abs(u_radius - dis) / u_radius;\n" +
        //四次方
        "f = pow(f, 2.0);\n" +
        //mix(x, y, a): x, y的线性混叠, x(1-a) + y*a;,
        //效果解释:在越接近扫描中心时,f越小,则片元的颜色越接近原来的,相反则越红
        "gl_FragColor = mix(gl_FragColor, u_scanColor, f);\n" +
        "}\n" +
        "}\n";
    debugger;
    var _Cartesian3Center = Cesium.Cartographic.toCartesian(cartographicCenter);
    var _Cartesian4Center = new Cesium.Cartesian4(_Cartesian3Center.x, _Cartesian3Center.y, _Cartesian3Center.z, 1);

    var _CartographicCenter1 = new Cesium.Cartographic(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height + 500);
    var _Cartesian3Center1 = Cesium.Cartographic.toCartesian(_CartographicCenter1);
    var _Cartesian4Center1 = new Cesium.Cartesian4(_Cartesian3Center1.x, _Cartesian3Center1.y, _Cartesian3Center1.z, 1);

    var _time = (new Date()).getTime();

    var _scratchCartesian4Center = new Cesium.Cartesian4();
    var _scratchCartesian4Center1 = new Cesium.Cartesian4();
    var _scratchCartesian3Normal = new Cesium.Cartesian3();

    var ScanPostStage = new Cesium.PostProcessStage({
        fragmentShader: ScanSegmentShader,
        uniforms: {
            u_scanCenterEC: function () {
                return Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
            },
            u_scanPlaneNormalEC: function () {
                var temp = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
                var temp1 = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1);
                _scratchCartesian3Normal.x = temp1.x - temp.x;
                _scratchCartesian3Normal.y = temp1.y - temp.y;
                _scratchCartesian3Normal.z = temp1.z - temp.z;

                Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal);
                return _scratchCartesian3Normal;
            },
            u_radius: function () {
                return maxRadius * (((new Date()).getTime() - _time) % duration) / duration;
            },
            u_scanColor: scanColor
        }
    });


    viewer.scene.postProcessStages.add(ScanPostStage);
    return (ScanPostStage);
}





// const DynamicCircle = `
// uniform sampler2D colorTexture;    //颜色纹理
// uniform sampler2D depthTexture;    //深度纹理
// varying vec2 v_textureCoordinates; //纹理坐标
// uniform vec4 u_scanCenterEC;       //扫描中心
// uniform vec3 u_scanPlaneNormalEC;  //扫描平面法向量
// uniform float u_radius;            //扫描半径
// uniform vec4 u_scanColor;          //扫描颜色

// // 根据二维向量和深度值 计算距离camera的向量
// vec4 toEye(in vec2 uv, in float depth) {
//     vec2 xy = vec2((uv.x * 2.0 - 1.0), (uv.y * 2.0 - 1.0));
//     // 看看源码中关于此函数的解释是,cesium系统自动生成的4*4的反投影变换矩阵
//     // 从clip坐标转为眼睛坐标,clip坐标是指顶点着色器的坐标系统gl_position输出的
//     vec4 posInCamera = czm_inverseProjection * vec4(xy, depth, 1.0);
//     posInCamera = posInCamera / posInCamera.w; //将视角坐标除深度分量
//     return posInCamera;
// }

// // 点在平面上的投影,输入参数为 平面法向量,平面起始点,测试点
// vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point) {
//     // 计算测试点与平面起始点的向量
//     vec3 v01 = point - planeOrigin;
//     // 平面法向量与 测试点与平面上的点 点积  点积的几何意义,b在a上的投影长度,
//     // 即v01在平面法向量上的长度
//     float d = dot(planeNormal, v01);
//     // planeNormal * d 即为v01在平面法向量上的投影向量
//     // 根据三角形向量相加为0的原则 即可得点在平面上的投影
//     return (point - planeNormal * d);
// }

// // 获取深度值,根据纹理坐标获取深度值
// float getDepth(in vec4 depth) {
//     float z_window = czm_unpackDepth(depth);  //源码解释将一个vec4向量还原到0,1内的一个数
//     z_window = czm_reverseLogDepth(z_window); // czm_reverseLogDepth解开深度
//     float n_range = czm_depthRange.near;      //
//     float f_range = czm_depthRange.far;
//     return (2.0 * z_window - n_range - f_range) / (f_range - n_range);
// }

// void main() {
//     gl_FragColor = texture2D(colorTexture, v_textureCoordinates);          //片元颜色
//     float depth = getDepth(texture2D(depthTexture, v_textureCoordinates)); //根据纹理获取深度值
//     vec4 viewPos = toEye(v_textureCoordinates, depth);                     //根据纹理坐标和深度值获取视点坐标
//     // 点在平面上的投影,平面法向量,平面中心,视点坐标
//     vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz, u_scanCenterEC.xyz, viewPos.xyz);
//     // 计算投影坐标到视点中心的距离
//     float dis = length(prjOnPlane.xyz - u_scanCenterEC.xyz);
//     // 如果在扫描半径内,则重新赋值片元颜色
//     if (dis < u_radius) {
//         // 计算与扫描中心的距离并归一化
//         float f = dis / u_radius;
//         // 原博客如下,实际上可简化为上式子
//         // float f = 1.0 -abs(u_radius - dis) / u_radius;
//         // 四次方
//         f = pow(f, 2.0);
//         // mix(x, y, a): x, y的线性混叠, x(1-a)  y*a;,
//         // 效果解释:在越接近扫描中心时,f越小,则片元的颜色越接近原来的,相反则越红
//         gl_FragColor = mix(gl_FragColor, u_scanColor, f);
//     }
// }
// `

// export function createDynamicCircleStage(viewer, Cesium, cartographicCenter, maxRadius, scanColor, duration) {
//     // 中心点
//     var _Cartesian3Center = Cesium.Cartographic.toCartesian(cartographicCenter);
//     var _Cartesian4Center = new Cesium.Cartesian4(_Cartesian3Center.x, _Cartesian3Center.y, _Cartesian3Center.z, 1);

//     // 中心点垂直高度上升500m的坐标点,目的是为了计算平面的法向量
//     var _CartographicCenter1 = new Cesium.Cartographic(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height + 500);
//     var _Cartesian3Center1 = Cesium.Cartographic.toCartesian(_CartographicCenter1);
//     var _Cartesian4Center1 = new Cesium.Cartesian4(_Cartesian3Center1.x, _Cartesian3Center1.y, _Cartesian3Center1.z, 1);

//     // 当前时间
//     var _time = (new Date()).getTime();

//     // 转换成相机参考系后的中心点,上升高度后的中心点以及平面法向量
//     var _scratchCartesian4Center = new Cesium.Cartesian4();
//     var _scratchCartesian4Center1 = new Cesium.Cartesian4();
//     var _scratchCartesian3Normal = new Cesium.Cartesian3();

//     // 自定义PostProcessStage
//     var dynamicCircle = new Cesium.PostProcessStage({
//         fragmentShader: DynamicCircle,
//         uniforms: {
//             // 将中心点坐标转化到相机参考系
//             u_scanCenterEC: function () {
//                 return Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
//             },
//             // 计算相机参考系下的平面法向量
//             u_scanPlaneNormalEC: function () {
//                 var temp = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center, _scratchCartesian4Center);
//                 var temp1 = Cesium.Matrix4.multiplyByVector(viewer.camera._viewMatrix, _Cartesian4Center1, _scratchCartesian4Center1);
//                 _scratchCartesian3Normal.x = temp1.x - temp.x;
//                 _scratchCartesian3Normal.y = temp1.y - temp.y;
//                 _scratchCartesian3Normal.z = temp1.z - temp.z;

//                 Cesium.Cartesian3.normalize(_scratchCartesian3Normal, _scratchCartesian3Normal);
//                 return _scratchCartesian3Normal;
//             },
//             // 动态半径
//             u_radius: function () {
//                 return maxRadius * (((new Date()).getTime() - _time) % duration) / duration;
//             },
//             u_scanColor: scanColor
//         }
//     });
//     return dynamicCircle;
// }

使用:

var CartographicCenter = new Cesium.Cartographic(Cesium.Math.toRadians(lon), Cesium.Math.toRadians(lat), 0);
var scanColor = new Cesium.Color(1.0, 0.0, 0.0, 1);
AddCircleScanPostStage(Cesium, _viewer, CartographicCenter, 1500, scanColor, 4000 );