Cesium 使用primitive实现水面抬高效果

2,071 阅读2分钟

前言

之前做淹没分析的时候网上找了很多资料得到的反馈是使用`primitive`时不能动态改变它的`extrudedHeight`
因此就放弃了这种方式采用了不带水波纹的`entity`方式加载(效果比较丑),
今天偶然在网上发现有大佬给出了修改`primitive`属性的方法就立马去实践了一下发现可行
原文链接: https://blog.csdn.net/qq_39142804/article/details/122825831
在这里记录一下加深自己的印象,也贴一下两种实现水面抬高的方法

entity

  `entit`y是`Cesium`提供的封装好的api可以通过`CallbackProperty`的方式动态修改`extrudedHeight`方式实现水面抬高的效果代码如下
  
const boundary = [121.4797, 29.7913, 121.4795, 29.7911, 121.4799, 29.7911, 121.4799, 29.7914]
const riverHeight = 10
const maxHeight = 15
window.viewer.entities.add({
    polygon: {
      hierarchy: new Cesium.Cartesian3.fromDegreesArray(boundary),
      fill: true,
      material: new Cesium.Color(255, 255, 255, 0.1) //水面颜色,
      extrudedHeight: new Cesium.CallbackProperty(() => {
        return riverHeight
      }, false),
      clampToGround: true,
    },
  })
   setInterval(() => {
    riverHeight += 0.25
    if (riverHeight >= maxHeight) {
      riverHeight = maxHeight
      clearInterval(timer)
      timer = null
    }
  }, 500)

primitive

primitive是比较底层的一个api具体就不介绍了(我也不熟)可以看一下官网 cesium.xin/cesium/cn/D… primitive方式加载水面的方法如下

/**
 *  绘制水面
 * @param boundary 边界点位 [112.23, 22.25, 112.24, 22.24]
 * @param waterImg 水面贴图
 * @param extrudedHeight 水面高度
 * @returns 水面实例
 */
function useDrawRiver(
  boundary: number[],
  Cesium: any,
  waterImg: any,
  extrudedHeight = 18
) {
  let riverHeight = extrudedHeight
  const polygon = useCreatePolygonGeometry(boundary,riverHeight)
  let river = null as any
    river = new Cesium.Primitive({
      geometryInstances: new Cesium.GeometryInstance({
        geometry: polygon,
      }),
      appearance: new Cesium.EllipsoidSurfaceAppearance({
        aboveGround: true,
      }),
      show: true,
      asynchronous: false,
      releaseGeometryInstances: false,
    })
  
  const riverMaterial = new Cesium.Material({
    fabric: {
      type: 'Water',
      uniforms: {
        baseWaterColor: new Cesium.Color(64 / 255.0, 157 / 255.0, 253 / 255.0, 0.5), // 水的基本颜色
        normalMap: waterImg, // 水的法线贴图
        frequency: 500.0, // 水波纹的数量
        animationSpeed: 0.05, // 水的流速
        amplitude: 5, // 水波纹振幅
        specularIntensity: 5, // 镜面反射强度
      },
    },
  })
  const scene = window.viewer.scene
  river.appearance.material = riverMaterial
  scene.primitives.add(river) //添加到场景
  river.appearance.material = riverMaterial
  return river
}
function useCreatePolygonGeometry(boundary: number[], extrudedHeight: number) {
  const polygon = new Cesium.PolygonGeometry({
    polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(boundary)),
    extrudedHeight,
    vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
  })
  return polygon
}

修改extrudedHeight高度实现水面抬升效果

这里我们可以利用Object.defineProperty监听extrudedHeight属性然后再去修改河面的状态触发cesium的update方法最后改变extrudedHeight值的时候就可以实现动态高度的效果了

  Object.defineProperty(river, 'extrudedHeight', {
    get() {
      return riverHeight
    },
    set(newVal) {
      if (typeof newVal !== 'number') {
        return
      }
      riverHeight = newVal
      river._state = 3 // 重置primitive状态触发cesium update方法
      river._appearance = undefined
      river.geometryInstances.geometry = useCreatePolygonGeometry(boundary, riverHeight)
    },
  })

代码合并

/**
 *  绘制水面
 * @param boundary 边界点位 [112.23, 22.25, 112.24, 22.24]
 * @param waterImg 水面贴图
 * @param extrudedHeight 水面高度
 * @returns 水面实例
 */
function useDrawRiver(
  boundary: number[],
  Cesium: any,
  waterImg: any,
  extrudedHeight = 18
) {
  let riverHeight = extrudedHeight
  const polygon = useCreatePolygonGeometry(boundary,riverHeight)
  let river = null as any
    river = new Cesium.Primitive({
      geometryInstances: new Cesium.GeometryInstance({
        geometry: polygon,
      }),
      appearance: new Cesium.EllipsoidSurfaceAppearance({
        aboveGround: true,
      }),
      show: true,
      asynchronous: false,
      releaseGeometryInstances: false,
    })
  
  const riverMaterial = new Cesium.Material({
    fabric: {
      type: 'Water',
      uniforms: {
        baseWaterColor: new Cesium.Color(64 / 255.0, 157 / 255.0, 253 / 255.0, 0.5), // 水的基本颜色
        normalMap: waterImg, // 水的法线贴图
        frequency: 500.0, // 水波纹的数量
        animationSpeed: 0.05, // 水的流速
        amplitude: 5, // 水波纹振幅
        specularIntensity: 5, // 镜面反射强度
      },
    },
  })
  const scene = window.viewer.scene
  river.appearance.material = riverMaterial
  scene.primitives.add(river) //添加到场景
  river.appearance.material = riverMaterial
   Object.defineProperty(river, 'extrudedHeight', {
    get() {
      return riverHeight
    },
    set(newVal) {
      if (typeof newVal !== 'number') {
        return
      }
      riverHeight = newVal
      river._state = 3 // 重置primitive状态触发cesium update方法
      river._appearance = undefined
      river.geometryInstances.geometry = useCreatePolygonGeometry(boundary, riverHeight)
    },
  })
  return river
}
function useCreatePolygonGeometry(boundary: number[], extrudedHeight: number) {
  const polygon = new Cesium.PolygonGeometry({
    polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(boundary)),
    extrudedHeight,
    vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
  })
  return polygon
}

调用

let river = useDrawRiver( boundary //多边形点位,Cesium,waterImg//水面纹理)
timer = setInterval(() => {
    riverHeight += 0.25
    rver.extrudedHeight = riverHeight
    if (riverHeight >= maxHeight) {
      riverHeight = maxHeight
      // 清除定时器
    }
  }, 500)

水面图片

water.jpeg