Cesium实现动态立体墙

912 阅读3分钟

效果

GIF 2024-09-05 21-48-35.gif

技术栈

cesium 1.103 vue3

实现

// 动态墙材质
import * as Cesium from 'cesium'

// 定义动态墙材质属性构造函数
export default function DynamicWallMaterialProperty(options) {
  // 默认参数设置
  this._definitionChanged = new Cesium.Event() // 材质定义变更事件
  this._color = undefined // 颜色属性
  this._colorSubscription = undefined // 颜色变化订阅
  this.color = options.color // 从选项中获取颜色
  this.duration = options.duration // 持续时间
  this.trailImage = options.trailImage // 路径图像
  this._time = new Date().getTime() // 当前时间戳
  this._viewer = options.viewer // Cesium 视图对象
}

// 定义属性
Object.defineProperties(DynamicWallMaterialProperty.prototype, {
  isConstant: {
    get: function () {
      return false // 返回材质是否是常量(动态材质返回 false)
    },
  },
  definitionChanged: {
    get: function () {
      return this._definitionChanged // 返回定义变更事件
    },
  },
  color: Cesium.createPropertyDescriptor('color'), // 创建颜色属性描述符
})

// 返回材质类型
DynamicWallMaterialProperty.prototype.getType = function (time) {
  return 'DynamicWall' // 返回材质类型名称
}

// 获取材质的值
DynamicWallMaterialProperty.prototype.getValue = function (time, result) {
  if (!Cesium.defined(result)) {
    result = {} // 如果结果未定义,则初始化为空对象
  }
  result.color = Cesium.Property.getValueOrClonedDefault(
    this._color, // 获取颜色值
    time, // 当前时间
    Cesium.Color.WHITE, // 默认颜色为白色
    result.color // 结果对象中的颜色属性
  )
  if (this.trailImage) {
    result.image = this.trailImage // 使用自定义的路径图像
  } else {
    result.image = Cesium.Material.DynamicWallImage // 使用默认路径图像
  }
  if (this.duration) {
    result.time =
      ((new Date().getTime() - this._time) % this.duration) / this.duration // 计算时间进度
  }
  this._viewer.scene.requestRender() // 请求重新渲染场景
  return result // 返回结果对象
}

// 比较两个 DynamicWallMaterialProperty 对象是否相等
DynamicWallMaterialProperty.prototype.equals = function (other) {
  return (
    this === other || // 判断是否为同一对象
    (other instanceof DynamicWallMaterialProperty && // 判断是否为 DynamicWallMaterialProperty 的实例
      Cesium.Property.equals(this._color, other._color)) // 比较颜色属性
  )
}

// 定义动态墙材质类型
Cesium.Material.DynamicWallType = 'DynamicWall'

// 定义默认图像路径
Cesium.Material.DynamicWallImage = '/src/assets/col.png'

// 定义材质源代码
Cesium.Material.DynamicWallSource =
// 定义了一个函数 czm_getMaterial,输入参数为 materialInput,返回值为 czm_material 类型的材质。
  'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
                                            {\n\
                                            // 调用 czm_getDefaultMaterial 函数获取一个默认的材质实例,并将其存储在 material 变量中\n\
                                            czm_material material = czm_getDefaultMaterial(materialInput);\n\
                                            // // 获取纹理坐标(st)的二维向量\n\
                                            vec2 st = materialInput.st;\n\
                                            // 纹理采样,依据时间动态变化,fract 函数用于计算余数,使纹理坐标在[0, 1)范围内循环。\n\
                                            vec4 colorImage = texture(image, vec2(fract(st.t - time), st.t));\n\
                                            // 创建一个 vec4 类型的变量用于存储片段颜色\n\
                                            vec4 fragColor;\n\
                                            // 将颜色的 RGB 分量除以 1.0(即保持不变),并赋值给 fragColor 的 RGB\n\
                                            fragColor.rgb = color.rgb / 1.0;\n\
                                            // 对 fragColor 进行 gamma 校正。czm_gammaCorrect 是一个函数,用于调整颜色的亮度,以便在不同的显示设备上显示一致。\n\
                                            fragColor = czm_gammaCorrect(fragColor);\n\
                                            //设置材质的 alpha 值,通常是纹理的 alpha 分量乘以颜色的 alpha 值。\n\
                                            material.alpha = colorImage.a * color.a;\n\
                                            // 设置材质的漫反射颜色(diffuse)为 color.rgb,漫反射颜色决定了材质在受到光照时的反射效果。\n\
                                            material.diffuse = color.rgb;\n\
                                            // 设置材质的发光颜色(emission)为 fragColor.rgb,发光颜色决定了材质在没有外部光源时的自发光效果。\n\
                                            material.emission = fragColor.rgb;\n\
                                            // 返回修改后的材质。\n\
                                            return material;\n\
                                            }'

// 将材质添加到缓存中
Cesium.Material._materialCache.addMaterial(Cesium.Material.DynamicWallType, {
  fabric: {
    type: Cesium.Material.DynamicWallType, // 设置材质类型
    uniforms: {
      color: new Cesium.Color(1.0, 1.0, 1.0, 1), // 设置颜色属性
      image: Cesium.Material.DynamicWallImage, // 设置图像路径
      time: 0, // 设置时间属性
    },
    source: Cesium.Material.DynamicWallSource, 
  },
  translucent: function (material) {
    return true // 确定材质是否是半透明的
  },
})

调用方法

let positions = Cesium.Cartesian3.fromDegreesArray([
    113.8236839, 22.528061, 113.9236839, 22.628061, 114.0236839, 22.528061,
    113.9236839, 22.428061, 113.8236839, 22.528061,
  ])
  // 绘制墙体
  const wall = viewer.entities.add({
    name: '立体墙效果',
    wall: {
      positions: positions,
      // 设置高度
      maximumHeights: new Array(positions.length).fill(400),
      minimumHeights: new Array(positions.length).fill(0),
      material: new DynamicWallMaterialProperty({
        viewer,
        color : Cesium.Color.RED,
        duration: 1500,
      }),
    },
  })
  viewer.zoomTo(wall)

材质图片

c705508c3156f73e84b95f02f4ef22df.png

遇到的错误

image.png

Fragment shader compile log: ERROR: 0:9: 'texture2D' : no matching overloaded function found ERROR: 0:9: '=' : dimension mismatch ERROR: 0:9: '=' : cannot convert from 'const mediump float' to 'highp 4-component vector of float'

参考:cesium1.102和以上的版本,自定义材质报‘texture2D‘ : no matching overloaded function found错误_texture2d' : no matching overloaded function found-CSDN博客

我这里直接把texture2D改为texture即可。

参考文章

cesium实现动态立体墙效果_cesium特效wall-CSDN博客

前端3D引擎-Cesium自定义动态材质 - 夜尽丶 - 博客园 (cnblogs.com)

cesium1.102和以上的版本,自定义材质报‘texture2D‘ : no matching overloaded function found错误_texture2d' : no matching overloaded function found-CSDN博客