Cesium从已知的自定义材质扩展其他效果

基于动态扩散效果,自定义的其他效果。上篇文章链接,防止自己找不到:

Cesium自定义材质Material以及一些思考_GhostPaints的博客-CSDN博客Cesium已有的材质,无法实现一些特定的功能。所以需要一些自定义的材质来实现。从git上找到了一个项目,里面有一两个实现自定义材质的方法。在此记录一下并学习。这是一个扩散效果的圆形。代码如下:function EllipsoidFadeMaterialProperty(color, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorhttps://blog.csdn.net/GhostPaints/article/details/124382690

基于动态扩散效果,更改为动态收缩效果

material材质重要的代码在于glsl中的逻辑,下面的glsl代码可以实现一个由中心向外部扩散的,并且由中心到外部颜色透明度从0.0到1.0的效果。glsl代码:

"czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
"{\n" +
    "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
        "material.diffuse = 1.5 * color.rgb;\n" +
        "vec2 st = materialInput.st;\n" +
        "float dis = distance(st, vec2(0.5, 0.5));\n" +
        "float per = fract(time);\n" +
        "if(dis > per * 0.5){\n" +
            "material.alpha = 0.0;\n" +
            "discard;\n" +
        "}else {\n" +
            "material.alpha = color.a  * dis / per / 1.0;\n" +
        "}\n" +
    "return material;\n" +
"}"

fract方法取小数部分,time是一个变化值。意味着per变量的取值范围:0.0~1.0。从0.0变化到1.0逐渐变大的过程。形成了从中心向外面扩散的效果。

通过逆向思维,只要per从1.0~0.0变化,那么它就可以实现从外面向中心点收缩的功能。只要将per替换成(1.0 - per)就可以实现。

下面的glsl代码就可以实现:

"czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
"{\n" +
    "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
        "material.diffuse = 1.5 * color.rgb;\n" +
        "vec2 st = materialInput.st;\n" +
        "float dis = distance(st, vec2(0.5, 0.5));\n" +
        "float per = fract(time);\n" +
        "if(dis > (1.0 - per) * 0.5){\n" +
            "material.alpha = 0.0;\n" +
            "discard;\n" +
        "}else {\n" +
            "material.alpha = color.a  * dis / (1.0 - per) / 1.0;\n" +
        "}\n" +
    "return material;\n" +
"}"

基于动态扩散效果material,制订三重圆material。

地图上的坐标点,项目上经常需要绘制出影响范围。比如现在需要绘制三个缓冲范围。通常的实现方式是使用三个entity的polygon。用turf.js计算出缓冲范围,然后绘制。最内圈的entity不镂空,记录内圈的坐标数组,用内圈的坐标数组镂空第二个中圈;用第二个的坐标数组镂空第三个外圈。

假设,每一个缓冲范围是上个圆的范围加上一个固定值,那么这个效果就可以看成是最大的外圈圆的半径三等分之后,每一个圈内颜色不同的效果。这样我们就只需要考虑material材质的glsl代码,绘制的时候只要大小设定为最大外圈就行了。

和动态扩散效果不同,这次,就不需要一个动态的时间time值。只需要让这个材质可以接收三个颜色值,分别是内圈,中圈,外圈的颜色值。

function ThreeCircleMaterialProperty(color1, color2, color3) {
    this._definitionChanged = new Cesium.Event();
    this._color1 = undefined;
    this._color2 = undefined;
    this._color3 = undefined;
    this._color1Subscription = undefined;
    this._color2Subscription = undefined;
    this._color3Subscription = undefined;
    this.color1 = color1;
    this.color2 = color2;
    this.color3 = color3;
}
Object.defineProperties(ThreeCircleMaterialProperty.prototype, {
    isConstant: {
        get: function () {
            return false;
        }
    },
    definitionChanged: {
        get: function () {
            return this._definitionChanged;
        }
    },
    color1: Cesium.createPropertyDescriptor('color1'),
    color2: Cesium.createPropertyDescriptor('color2'),
    color3: Cesium.createPropertyDescriptor('color3')
});
ThreeCircleMaterialProperty.prototype.getType = function (time) {
    return 'ThreeCircle';
}
ThreeCircleMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
        result = {};
    }
    result.color1 = Cesium.Property.getValueOrClonedDefault(this._color1, time, Cesium.Color.RED, result.color1);
    result.color2 = Cesium.Property.getValueOrClonedDefault(this._color2, time, Cesium.Color.GREEN, result.color2);
    result.color3 = Cesium.Property.getValueOrClonedDefault(this._color3, time, Cesium.Color.BLUE, result.color3);
    return result;
}
ThreeCircleMaterialProperty.prototype.equals = function (other) {
    return this === other ||
        (other instanceof ThreeCircleMaterialProperty &&
            Property.equals(this._color1, other._color1) &&
            Property.equals(this._color2, other._color2) &&
            Property.equals(this._color3, other._color3))
}
Cesium.ThreeCircleMaterialProperty= ThreeCircleMaterialProperty;
Cesium.Material.ThreeCircleType = 'ThreeCircle';
Cesium.Material.ThreeCircleSource =
    "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
    "{\n" +
    "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
    "vec2 st = materialInput.st;\n" +
    "float dis = distance(st, vec2(0.5, 0.5));\n" +
    "if(dis > 0.5 * (2.0 / 3.0)){\n" +
    "material.diffuse = 1.0 * color1.rgb;\n" +
    "}else if(dis > 0.5 * (1.0 / 3.0)){\n" +
    "material.diffuse = 1.0 * color2.rgb;\n" +
    "}else {\n" +
    "material.diffuse = 1.0 * color3.rgb;\n" +
    "}" +
    "return material;\n" +
    "}";
Cesium.Material._materialCache.addMaterial(Cesium.Material.ThreeCircleType , {
    fabric: {
        type: Cesium.Material.ThreeCircleType,
        uniforms: {
            color1: new Cesium.Color(1.0, 0.0, 0.0, 1),
            color2: new Cesium.Color(0.0, 1.0, 0.0, 1),
            color3: new Cesium.Color(0.0, 0.0, 1.0, 1)
        },
        source: Cesium.Material.ThreeCircleSource
    },
    translucent: function (material) {
        return true;
    }
});

viewer.entities.add({
    name: 'ThreeCircle',
    position: Cesium.Cartesian3.fromDegrees(104.0, 30.0, 100.0),
    ellipse: {
        height: 0,
        semiMinorAxis: 30000.0,
        semiMajorAxis: 30000.0,
        material: new Cesium.ThreeCircleMaterialProperty(Cesium.Color.RED,Cesium.Color.ORANGE,Cesium.Color.GREENYELLOW)
    }
});

viewer.zoomTo(viewer.entities)

 最主要的glsl代码里面。和fabric里面是有区别的。首先去除了time时间,增加了两个颜色值。fabric的uniform同时也多了两个颜色值color2,color3。只要uniform里面有的变量名称,在glsl中就可以用变量名来获取颜色值了。

在glsl代码中。因为把半径三等分,所以有三个if判断,为了避免一直进入最小的if判断中,if的首个判断优先判断最外圈。然后是中圈和内圈。

diffuse是入射光,通过更改入射光,就可以改变区域内的颜色值。最终效果如图:

基于三圆材质,增加比例参数

现在这个material材质适用性不是很强,只适用于内部的圆按固定值扩大的效果。如果这个扩大的值不是固定的,那就不能用了。于是更改它,让它能接收一个比例值。

在上面的材质glsl代码中,使用了(2.0/3.0)和(1.0/3.0)来固定分割。那么不使用固定值,直接接受传入的比例值就好了。

于是就有这样的算法逻辑:

已知一个坐标 =》
需要有三个圆形的影响范围 =》
第一个内圈影响范围半径:500。从坐标扩散500的圆 =》
第二个中圈影响范围半径:700。从坐标扩散700的圆,但不会遮住内圈 =》
第三个外圈影响范围半径:1000。从坐标扩散1000的圆,但不会遮住内圈和中圈


于是可以多接收两个比例参数,500/1000 和 700/1000

更改上面的三重圆材质,让它支持接收两个比例值。

function ThreeCircleMaterialProperty(color1, color2, color3) {
    this._definitionChanged = new Cesium.Event();
    this._color1 = undefined;
    this._color2 = undefined;
    this._color3 = undefined;
    this._color1Subscription = undefined;
    this._color2Subscription = undefined;
    this._color3Subscription = undefined;
    this.color1 = color1;
    this.color2 = color2;
    this.color3 = color3;
    this._bili1 = undefined;
    this._bili1Subscription = undefined;
    this.bili1 = bili1;
    this._bili2 = undefined;
    this._bili2Subscription = undefined;
    this.bili2 = bili2;
}
Object.defineProperties(ThreeCircleMaterialProperty.prototype, {
    isConstant: {
        get: function () {
            return false;
        }
    },
    definitionChanged: {
        get: function () {
            return this._definitionChanged;
        }
    },
    color1: Cesium.createPropertyDescriptor('color1'),
    color2: Cesium.createPropertyDescriptor('color2'),
    color3: Cesium.createPropertyDescriptor('color3'),
    bili1: Cesium.createPropertyDescriptor('bili1'),
    bili2: Cesium.createPropertyDescriptor('bili2')
});
ThreeCircleMaterialProperty.prototype.getType = function (time) {
    return 'ThreeCircle';
}
ThreeCircleMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
        result = {};
    }
    result.color1 = Cesium.Property.getValueOrClonedDefault(this._color1, time, Cesium.Color.RED, result.color1);
    result.color2 = Cesium.Property.getValueOrClonedDefault(this._color2, time, Cesium.Color.GREEN, result.color2);
    result.color3 = Cesium.Property.getValueOrClonedDefault(this._color3, time, Cesium.Color.BLUE, result.color3);
    result.bili1 = Cesium.Property.getValueOrClonedDefault(this._bili1, time, parseFloat('1.0'), result.bili1);
    result.bili2 = Cesium.Property.getValueOrClonedDefault(this._bili2, time, parseFloat('1.0'), result.bili2);
    return result;
}
ThreeCircleMaterialProperty.prototype.equals = function (other) {
    return this === other ||
        (other instanceof ThreeCircleMaterialProperty &&
            Property.equals(this._color1, other._color1) &&
            Property.equals(this._color2, other._color2) &&
            Property.equals(this._color3, other._color3))
}
Cesium.ThreeCircleMaterialProperty= ThreeCircleMaterialProperty;
Cesium.Material.ThreeCircleType = 'ThreeCircle';
Cesium.Material.ThreeCircleSource =
    "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
    "{\n" +
    "czm_material material = czm_getDefaultMaterial(materialInput);\n" +
    "vec2 st = materialInput.st;\n" +
    "float dis = distance(st, vec2(0.5, 0.5));\n" +
    "if(dis > 0.5 * (bili2 * 1.0)){\n" +
    "material.diffuse = 1.0 * color1.rgb;\n" +
    "}else if(dis > 0.5 * (bili1 * 1.0)){\n" +
    "material.diffuse = 1.0 * color2.rgb;\n" +
    "}else {\n" +
    "material.diffuse = 1.0 * color3.rgb;\n" +
    "}" +
    "return material;\n" +
    "}";
Cesium.Material._materialCache.addMaterial(Cesium.Material.ThreeCircleType , {
    fabric: {
        type: Cesium.Material.ThreeCircleType,
        uniforms: {
            color1: new Cesium.Color(1.0, 0.0, 0.0, 1),
            color2: new Cesium.Color(0.0, 1.0, 0.0, 1),
            color3: new Cesium.Color(0.0, 0.0, 1.0, 1),
            bili1: 1.0,
            bili2: 1.0
        },
        source: Cesium.Material.ThreeCircleSource
    },
    translucent: function (material) {
        return true;
    }
});

viewer.entities.add({
    name: 'ThreeCircle',
    position: Cesium.Cartesian3.fromDegrees(104.0, 30.0, 100.0),
    ellipse: {
        height: 0,
        semiMinorAxis: 30000.0,
        semiMajorAxis: 30000.0,
        material: new Cesium.ThreeCircleMaterialProperty(Cesium.Color.RED,Cesium.Color.ORANGE,Cesium.Color.GREENYELLOW,0.1,0.6)
    }
});

viewer.zoomTo(viewer.entities)

于是,一个可以设置三个圆圈占比的material材质出现了。效果如图:

 目前这个三圆材质可以不受内中圈大小的限制了,但是受限的地方在于数量了。如果是四个等值扩大的圆呢?五个六个怎么办?十个呢?难道要传十个颜色值?

可以在glsl中设置一个for循环,不再接收多个颜色值,而是只接收最中心的颜色,其他的颜色都基于中心颜色变换。所以,新增一个材质,接收两个变量值。一个是中心点的颜色,一个是圆圈数量。

猜你喜欢

转载自blog.csdn.net/GhostPaints/article/details/124443620
今日推荐