SuperMap iClient3D for WebGL绘制河流

作者:kele

前言

在三维地理信息系统中,河流是重要的组成部分,如何在三维场景中展示河流成为我们重点探讨的对象;在以往的方法中,我们可以通过iDesktop制作水面特效来展示河流,但这种方式的局限性在于不能改变河流的走向以及水流的方向,今天,小编为大家介绍一种前端绘制河流的方法~

一、实现思路

1.绘制entity实体线
2.给实体线赋予动态材质贴图
3.根据相机高度改变实体线宽
其中主要的障碍应该是第二点,如何自定义动态纹理材质,我们一起来看下吧

二、实现代码

1.构建自定义动态纹理材质
color:材质颜色
duration:纹理流动循环周期
texture2D(image, vec2(fract(st.s5.0-time1.0), st.t)):纹理运动方向及速度

function PolylineTrailLinkMaterialProperty(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(PolylineTrailLinkMaterialProperty.prototype, {
  isConstant: {
    get: function () {
      return false;
    }
  },
  definitionChanged: {
    get: function () {
      return this._definitionChanged;
    }
  },
  color: Cesium.createPropertyDescriptor('color')
});
PolylineTrailLinkMaterialProperty.prototype.getType = function (time) {
  return 'PolylineTrailLink';
};
PolylineTrailLinkMaterialProperty.prototype.getValue = function (time, result) {
  if (!Cesium.defined(result)) {
    result = {};
  }
  result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
  result.image = Cesium.Material.PolylineTrailLinkImage;
  result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
  return result;
};
PolylineTrailLinkMaterialProperty.prototype.equals = function (other) {
  return this === other ||
      (other instanceof PolylineTrailLinkMaterialProperty &&
          Property.equals(this._color, other._color))
};
Cesium.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty;
Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink';
Cesium.Material.PolylineTrailLinkImage = "./images/movingRiver.png";
Cesium.Material.PolylineTrailLinkSource = "\
    uniform vec4 color;\n\
    uniform float time;\n\
    uniform sampler2D image;\n\
    czm_material czm_getMaterial(czm_materialInput materialInput)\n\
    {\n\
      czm_material material = czm_getDefaultMaterial(materialInput);\n\
      vec2 st = materialInput.st;\n\
      vec4 colorImage = texture2D(image, vec2(fract(st.s*5.0-time*1.0), st.t));\n\
      material.alpha = colorImage.a * color.a;\n\
      material.diffuse = colorImage.rgb;\n\
      return material;\n\
    }";
Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, {
  fabric: {
    type: Cesium.Material.PolylineTrailLinkType,
    uniforms: {
      color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
      image: Cesium.Material.PolylineTrailLinkImage,
      time: 0,
      repeat: 3
    },
    source: Cesium.Material.PolylineTrailLinkSource
  },
  translucent: function (material) {
    return true;
  }
});

2.绘制实体线,并赋予第一步定义的材质

river = viewer.entities.add({
  name : 'river',
  polyline : {
    positions : new Cesium.Cartesian3.fromDegreesArrayHeights(positions),
    width: 20,
    followSurface : true,
    material : new Cesium.PolylineTrailLinkMaterialProperty(Cesium.Color.SKYBLUE,10000),
    clampToGround: true,
    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 30000)
  }
});

三、控制河流宽度

因为polyline的线宽是像素宽度,不会随着场景高度变化而变化,导致在场景缩放过程中河流宽度不真实,我们用以下方法来动态改变河流宽度

scene.postRender.addEventListener(function(){ // 每一帧都去计算气泡的正确位置
  if(flag === true){
    var position = viewer.scene.camera._position;
    var cartographic = Cesium.Cartographic.fromCartesian(position);
    var currtenHeight = cartographic.height;
    for(var i=1;i<=10;i++){
      if(currtenHeight>=perHeight*i && currtenHeight<=(perHeight*i+perHeight)){
        if(currtenHeight<3500){
          river.polyline.width = maxWidth
        }
        else if(currtenHeight>3500 && river.polyline.width._value !== maxWidth-perWidth*i){
          river.polyline.width = maxWidth-perWidth*i
        }
      }
    }
  }
});

四、效果图


你可能感兴趣的:(三维GIS,javascript)