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. 效果

相关推荐
y先森2 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy2 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189112 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿3 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡4 小时前
commitlint校验git提交信息
前端
虾球xz5 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇5 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒5 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员5 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐5 小时前
前端图像处理(一)
前端