cesium 鼠标动态绘制墙及墙动效

实现在cesium中基于鼠标动态绘制墙功能

1. 基本架构设计

绘制墙的交互与绘制线的交互几乎一模一样,只是一些生成wall实体的计算方法不一样,所以可以看这篇文章 cesium 鼠标动态绘制线及线动效 juejin.cn/post/728826... 了解相关的架构设计

2. 关键代码实现

2.1 绘制线交互相关事件

事件绑定相关与动态绘制线一样,这里不再重复代码

绘制形状代码有区别: 为了实现墙贴地,要实时计算minimumHeights,maximumHeights的值,min中算出地形高度,max中再地形高度的基础上再加上墙的高度

ts 复制代码
  /**
   * 绘制形状,用于内部临时画墙
   * @param positionData 位置数据
   * @param config 墙的配置项
   * @returns
   */
  private drawShape(positionData: Cartesian3[], config?: WallConfig) {
    const wallConfig = config || new WallConfig();
    const material = this.createMaterial(wallConfig);
    // @ts-ignore
    const pArray = positionData._callback();

    const shape = this.app.viewerCesium.entities.add({
      wall: {
        positions: positionData,
        material: material,
        maximumHeights: new CallbackProperty(() => {
          let heights: number[] = [];
          for (let i = 0; i < pArray.length; i++) {
            const cartographic = Cartographic.fromCartesian(pArray[i]);
            const height = cartographic.height;
            heights.push(height);
          }
          const data = Array.from(heights, (x) => x + wallConfig.height);
          return data;
        }, false),
        minimumHeights: new CallbackProperty(() => {
          let heights: number[] = [];
          for (let i = 0; i < pArray.length; i++) {
            const cartographic = Cartographic.fromCartesian(pArray[i]);
            const height = cartographic.height;
            heights.push(height);
          }
          const data = Array.from(heights);
          return data;
        }, false)
      }
    });
    return shape;
  }

2.2 创建材质相关

ts 复制代码
  /**
   * 创建材质
   * @param config 墙的配置项
   * @returns
   */
  private createMaterial(config: WallConfig) {
    let material = new ColorMaterialProperty(Color.fromCssColorString(config.style.color));
    if (config.style.particle.used) {
      material = new WallFlowMaterialProperty({
        image: config.style.particle.image,
        forward: config.style.particle.forward ? 1.0 : -1.0,
        horizontal: config.style.particle.horizontal,
        speed: config.style.particle.speed,
        repeat: new Cartesian2(config.style.particle.repeat, 1.0)
      });
    }

    return material;
  }

创建WallFlowMaterialProperty.js(具体为何如此请看这篇文章,cesium自定义材质 juejin.cn/post/728795...

js 复制代码
import { Color, defaultValue, defined, Property, createPropertyDescriptor, Material, Event, Cartesian2 } from 'cesium';

const defaultColor = Color.TRANSPARENT;
import defaultImage from '../../../assets/images/effect/line-color-yellow.png';
const defaultForward = 1;
const defaultHorizontal = false;
const defaultSpeed = 1;
const defaultRepeat = new Cartesian2(1.0, 1.0);

class WallFlowMaterialProperty {
  constructor(options) {
    options = defaultValue(options, defaultValue.EMPTY_OBJECT);

    this._definitionChanged = new Event();
    // 定义材质变量
    this._color = undefined;
    this._colorSubscription = undefined;
    this._image = undefined;
    this._imageSubscription = undefined;
    this._forward = undefined;
    this._forwardSubscription = undefined;
    this._horizontal = undefined;
    this._horizontalSubscription = undefined;
    this._speed = undefined;
    this._speedSubscription = undefined;
    this._repeat = undefined;
    this._repeatSubscription = undefined;
    // 变量初始化
    this.color = options.color || defaultColor; //颜色
    this.image = options.image || defaultImage; //材质图片
    this.forward = options.forward || defaultForward;
    this.horizontal = options.horizontal || defaultHorizontal;
    this.speed = options.speed || defaultSpeed;
    this.repeat = options.repeat || defaultRepeat;
  }

  // 材质类型
  getType() {
    return 'WallFlow';
  }

  // 这个方法在每次渲染时被调用,result的参数会传入glsl中。
  getValue(time, result) {
    if (!defined(result)) {
      result = {};
    }

    result.color = Property.getValueOrClonedDefault(this._color, time, defaultColor, result.color);
    result.image = Property.getValueOrClonedDefault(this._image, time, defaultImage, result.image);
    result.forward = Property.getValueOrClonedDefault(this._forward, time, defaultForward, result.forward);
    result.horizontal = Property.getValueOrClonedDefault(this._horizontal, time, defaultHorizontal, result.horizontal);
    result.speed = Property.getValueOrClonedDefault(this._speed, time, defaultSpeed, result.speed);
    result.repeat = Property.getValueOrClonedDefault(this._repeat, time, defaultRepeat, result.repeat);

    return result;
  }

  equals(other) {
    return (
      this === other ||
      (other instanceof WallFlowMaterialProperty &&
        Property.equals(this._color, other._color) &&
        Property.equals(this._image, other._image) &&
        Property.equals(this._forward, other._forward) &&
        Property.equals(this._horizontal, other._horizontal) &&
        Property.equals(this._speed, other._speed) &&
        Property.equals(this._repeat, other._repeat))
    );
  }
}

Object.defineProperties(WallFlowMaterialProperty.prototype, {
  isConstant: {
    get: function get() {
      return (
        Property.isConstant(this._color) &&
        Property.isConstant(this._image) &&
        Property.isConstant(this._forward) &&
        Property.isConstant(this._horizontal) &&
        Property.isConstant(this._speed) &&
        Property.isConstant(this._repeat)
      );
    }
  },

  definitionChanged: {
    get: function get() {
      return this._definitionChanged;
    }
  },

  color: createPropertyDescriptor('color'),
  image: createPropertyDescriptor('image'),
  forward: createPropertyDescriptor('forward'),
  horizontal: createPropertyDescriptor('horizontal'),
  speed: createPropertyDescriptor('speed'),
  repeat: createPropertyDescriptor('repeat')
});

Material.WallFlowType = 'WallFlow';
Material._materialCache.addMaterial(Material.WallFlowType, {
  fabric: {
    type: Material.WallFlowType,
    uniforms: {
      // uniforms参数跟我们上面定义的参数以及getValue方法中返回的result对应,这里值是默认值
      color: defaultColor,
      image: defaultImage,
      forward: defaultForward,
      horizontal: defaultHorizontal,
      speed: defaultSpeed,
      repeat: defaultRepeat
    },
    // source编写glsl,可以使用uniforms参数,值来自getValue方法的result
    source: `czm_material czm_getMaterial(czm_materialInput materialInput)
    {
      czm_material material = czm_getDefaultMaterial(materialInput);

      vec2 st = materialInput.st;
      vec4 fragColor;
      if (horizontal) {
        fragColor = texture(image, fract(vec2(st.s - speed*czm_frameNumber*0.005*forward, st.t)*repeat));
      } else {
        fragColor = texture(image, fract(vec2(st.t - speed*czm_frameNumber*0.005*forward, st.t)*repeat));
      }

      material.emission = fragColor.rgb;
      material.alpha = fragColor.a;

      return material;
    }`
  },
  translucent: true
});

export { WallFlowMaterialProperty };

2.3 添加wall实体

ts 复制代码
  /**
   * 根据已知数据添加一个墙
   * @param config 墙的配置项
   */
  add(config: WallConfig) {
    const configCopy = cloneDeep(config);

    const positions = configCopy.positions;

    const material = this.createMaterial(configCopy);

    let distance = new DistanceDisplayCondition();
    if (configCopy.distanceDisplayCondition) {
      distance = new DistanceDisplayCondition(
        configCopy.distanceDisplayCondition.near,
        configCopy.distanceDisplayCondition.far
      );
    }

    let heights: number[] = [];
    for (let i = 0; i < positions.length; i++) {
      const cartographic = Cartographic.fromCartesian(positions[i]);
      const height = cartographic.height;
      heights.push(height);
    }

    this.app.viewerCesium.entities.add({
      id: 'wallEntity_' + configCopy.id,
      wall: {
        positions: positions,
        maximumHeights: Array.from(heights, (x) => x + configCopy.height),
        minimumHeights: Array.from(heights),
        material: material,
        distanceDisplayCondition: distance
      }
    });

    this._wallConfigList.set('wallEntity_' + configCopy.id, config);
  }

3. 业务端调用

调用方式与动态绘制线一样,是同一种架构设计,这里不再重复代码

4. 效果

相关推荐
耶啵奶膘5 分钟前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic3 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
枝上棉蛮4 小时前
GISBox VS ArcGIS:分别适用于大型和小型项目的两款GIS软件
arcgis·gis·数据可视化·数据处理·地理信息系统·gis工具箱·gisbox
John.liu_Test5 小时前
js下载excel示例demo
前端·javascript·excel
Yaml45 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理