Skip to content

学习Cesiumjs

案列网站 官方文档 案例资源

cesium在vite项目中使用

bash
npm i vite-plugin-cesium cesium -D

微信截图_20250429133801

离线使用cesium

js

const viewer = new Viewer(document.querySelector("#root"), {
  imageryProvider: false,//在cesium1.128版本中已经移出了这个配置项,默认施加在cesium自己的底图,我们现在要使用离线的cesium,为来控制台不报错,设置false
  baseLayerPicker: false,
});
js
 Cesium.Ion.defaultAccessToken = undefined;

      let viewer;
      async function initCesium() {
        viewer = new Cesium.Viewer('cesiumContainer', {
          animation: false,
          baseLayerPicker: false,
          fullscreenButton: false,
          vrButton: false,
          geocoder: false,
          homeButton: false,
          infoBox: false,
          sceneModePicker: false,
          selectionIndicator: false,
          timeline: false,
          navigationHelpButton: false,
          skyBox: false,
          skyAtmosphere: false,
          contextOptions: {
            webgl: {
              alpha: true,
              failIfMajorPerformanceCaveat: false,
            },
          },
          imageryProvider: false, //让控制台不报错 默认状态会加载cesium的底图
        });

        viewer.cesiumWidget.creditContainer.style.display = 'none';
        // 添加底图
        const provider = await Cesium.SingleTileImageryProvider.fromUrl(
          'http://127.0.0.1:8004/blue.jpg'
        );
        viewer.scene.imageryLayers.addImageryProvider(provider);
        viewer.scene.imageryLayers.addImageryProvider(
          new Cesium.TileMapServiceImageryProvider({
            url: 'http://127.0.0.1:8004/map/{z}/{x}/{reverseY}.jpg',
            fileExtension: 'jpg',
            tilingScheme: new Cesium.GeographicTilingScheme(),
          })
          // new Cesium.UrlTemplateImageryProvider({
          //   url: 'http://192.168.5.228:8004/map/{z}/{x}/{reverseY}.jpg',
          //   fileExtension: 'jpg',
          //   tilingScheme: new Cesium.GeographicTilingScheme(),
          // })
        );
      }
      initCesium();

在 Cesium 1.128 版本中,主要有以下几种 TilingScheme:

  1. GeographicTilingScheme (地理坐标切片方案):

    • 基于地理坐标系(经纬度)
    • 适用于全球范围的数据展示
    • 经度范围:-180° 到 180°
    • 纬度范围:-90° 到 90°
    • 在高纬度地区变形较小
  2. WebMercatorTilingScheme (墨卡托投影切片方案):

    • 基于墨卡托投影
    • 是最常用的网络地图切片方案
    • 适用于 Google Maps、OpenStreetMap 等常见地图服务
    • 在高纬度地区会产生较大变形
    • 不能完全显示极地区域 这两种切片方案的主要区别:
  3. 投影方式:

    • GeographicTilingScheme 使用等经纬度投影
    • WebMercatorTilingScheme 使用墨卡托投影
  4. 使用场景:

    • GeographicTilingScheme 适合:

      • 全球范围数据展示
      • 需要精确经纬度的场景
      • 极地区域的显示
    • WebMercatorTilingScheme 适合:

      • 常见的网络地图服务
      • 中低纬度地区的显示
      • 与主流地图服务对接

创建视口容器

Viewer配置项详情

js
 const viewer = new Cesium.Viewer('cesiumContainer', {
      terrain: Cesium.Terrain.fromWorldTerrain(), //地形
      baseLayerPicker: false, //右上角底图选择
      fullscreenButton: false,
      homeButton: false, //右上角小房子按钮
      infoBox: false, //右上角信息框
      sceneModePicker: false, //右上角地图3d/2d切换
      navigationHelpButton: false, //右上角帮助按钮
      navigationInstructionsInitiallyVisible: false, //右上角指南
      selectionIndicator: false, //选中指示器
      shadows: true, //阴影
      timeline: false, //时间轴
      animation: false,
      geocoder: false, //搜索框
    })

更新渲染器和场景视图

js
//建议配合防抖一起使用  
import _ from 'lodash';
window.addEventListener('resize',debounceResize);
const debounceResize = _.debounce(function(){
    viewer.resize();//viewer.resize()方法会更新 Cesium 渲染器以适应新的窗口尺寸。它会重新分配 WebGL 资源,确保场景能够正确地渲染在新的尺寸下。
       // viewer.scene对象也可以进行其他必要的更新操作,比如更新相机视角等
       // 例如,根据新的窗口尺寸调整相机的纵横比
       var canvas = viewer.scene.canvas;
       var width = canvas.clientWidth;
       var height = canvas.clientHeight;
       viewer.camera.aspectRatio = width / height;
       viewer.camera.updateProjectionMatrix();
})

创建地形

方式1(异步):

js
const viewer = new Cesium.Viewer('cesiumContainer')
viewer.terrainProvider = await Cesium.createWorldTerrainAsync()//添加地形-解决加载3dtiles悬浮的问题

方式2:

js
const viewer = new Cesium.Viewer("cesiumContainer", {
  terrain: Cesium.Terrain.fromWorldTerrain(),
});

隐藏cesiun的logo(隐藏版权)

js
  viewer.cesiumWidget.creditContainer.style.display = 'none'// 隐藏版权

Cesium 中用于创建边缘检测

Cesium.PostProcessStageLibrary.createEdgeDetectionStage() 是 Cesium 中用于创建边缘检测后处理阶段的方法。边缘检测是一种图像处理技术,旨在识别图像中的边界或边缘,使得图像的结构更加清晰,通常用于增强图像的视觉效果。

主要作用和参数:

  1. 目的

    • 增强场景的视觉效果,突出显示对象的边缘,以便于观察和分析。
    • 边缘检测可以帮助用户更好地理解场景中的几何形状和结构。
  2. 使用

    • 在 Cesium 中,可以将边缘检测作为后处理效果添加到渲染管道中。通过这种方式,您可以在渲染场景时应用边缘检测效果。
  3. 基本参数

    • createEdgeDetectionStage()

      方法可以接受一些可选的参数来定制效果,例如:

      • edgeColor: 边缘的颜色。
      • edgeWidth: 边缘的宽度。
      • backgroundColor: 背景颜色。
  4. 使用示例

    js
    const viewer = new Cesium.Viewer('cesiumContainer');
    
    // 创建边缘检测后处理阶段
    const edgeDetectionStage = Cesium.PostProcessStageLibrary.createEdgeDetectionStage({
        edgeColor: Cesium.Color.RED, // 设置边缘颜色
        edgeWidth: 2.0 // 设置边缘宽度
    });
    
    // 将边缘检测后处理阶段添加到渲染管道中
    viewer.scene.postProcessStages.add(edgeDetectionStage);

注意事项:

  • 边缘检测效果可能会对性能产生影响,特别是在处理大型场景时。因此,建议根据实际需求谨慎使用。
  • 可以与其他后处理效果结合使用,如模糊、亮度调整等,以达到更好的视觉效果。

通过使用 createEdgeDetectionStage(),您可以显著增强场景中对象的可见性和可理解性,特别是在复杂的环境中。

将世界坐标转换为地图上的经纬度高度

js
 let cartographic = Cesium.Cartographic.fromCartesian(cartesianPosition)// 将世界坐标转换为地图上的经纬度高度
 let longitude = Cesium.Math.toDegrees(cartographic.longitude)
 let latitude = Cesium.Math.toDegrees(cartographic.latitude)
 let height = cartographic.height

使用Cesium的``或Label来创建动态信息框

ts
  function createInfoBox(longitude: any, latitude: any, height: any) {
    // 创建新的信息标签
    currentInfoLabel = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height + 50), // 提高一点高度避免遮挡
      label: {
        text: `
                        Longitude: ${longitude.toFixed(6)}<br>
                        Latitude: ${latitude.toFixed(6)}<br>
                        Height: ${height.toFixed(2)} m<br>
                    `,
        font: '14px sans-serif',
        fillColor: Cesium.Color.BLACK,
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 2,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -20), // 调整垂直偏移量
      },
    })

    // 刷新视图
    viewer.scene.requestRender()
  }

viewer.entities介绍

viewer.entities 是 Cesium 中用于管理和操作场景中各种实体(如点、线、多边形、标签、图标等)的一个集合。通过 viewer.entities,你可以轻松地添加、删除和修改这些实体,从而在 Cesium 场景中展示各种地理信息和标注。

主要功能

  1. 添加实体

    js
    var entity = viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
        point: {
            color: Cesium.Color.RED,
            pixelSize: 10
        },
        label: {
            text: 'Hello, World!',
            font: '14px sans-serif',
            fillColor: Cesium.Color.BLACK,
            outlineColor: Cesium.Color.WHITE,
            outlineWidth: 2,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM
        }
    });
  2. 获取实体

    var entity = viewer.entities.getById('entityId');
  3. 删除实体

    viewer.entities.remove(entity);
  4. 清空所有实体

    viewer.entities.removeAll();
  5. 遍历所有实体

    viewer.entities.values.forEach(function(entity) {
        console.log(entity);
    });

示例:添加一个带有标签的点

js
var viewer = new Cesium.Viewer('cesiumContainer');

// 添加一个带有标签的点
var entity = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03925, 100.0),
    point: {
        color: Cesium.Color.RED,
        pixelSize: 10
    },
    label: {
        text: 'Philadelphia',
        font: '14px sans-serif',
        fillColor: Cesium.Color.BLACK,
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 2,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM
    }
});

// 刷新视图
viewer.scene.requestRender();

cesium 改写默认鼠标事件 平移 缩放 旋转

1、修改鼠标中键为缩放

js
viewer.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH];

2、修改鼠标右键旋转

js
viewer.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.PINCH, Cesium.CameraEventType.RIGHT_DRAG];

相机控制

1.飞到某个地点

js
    const destination = Cesium.Cartesian3.fromDegrees(config.center[0], config.center[1], config.height);
     viewer.camera.flyTo({
          destination: destination,
          duration: 3.0, // 动画持续时间,单位为秒
          orientation: {
            heading: 0.0,
            pitch: -Cesium.Math.PI_OVER_TWO,
            roll: 0.0,
          },
        })
js
  /**
   * ## 加载舟山边界
   */
  function loadBoundary() {
    // 加载GeoJSON数据并设置边界样式
    Cesium.GeoJsonDataSource.load(zhoushan, {
      stroke: Cesium.Color.RED, // 边界线颜色
      strokeWidth: 3, // 边界线宽度
      fill: Cesium.Color.fromAlpha(Cesium.Color.BLUE, 0), // 填充颜色和透明度
    })
      .then((dataSource) => {
        // 将GeoJSON数据添加到地图中
        viewer.dataSources.add(dataSource);
        GeoJsonDataSource = dataSource;
        // 让视图聚焦到GeoJSON区域

        if (!isint) {
          viewer.flyTo(dataSource, {
            duration: 2, // 飞行持续时间(秒)
            offset: new Cesium.HeadingPitchRange(
              0, // heading(航向角):0 表示朝北
              Cesium.Math.toRadians(-70), // pitch(俯仰角):负值表示向下看,-45度
              500000 // range(距离):米
            ),
          });
          isint = true;
        } else {
          viewer.zoomTo(dataSource);
        }
      })
      .catch((error) => {
        console.error('加载GeoJSON失败:', error);
      });
  }

2.移动到某一个点

js
 viewer.zoomTo(dataSource);

限制相机的俯仰角度

js
const viewer = new Cesium.Viewer('cesiumContainer');
// 获取 ScreenSpaceCameraController
const cameraController = viewer.scene.screenSpaceCameraController;

// 设置俯仰角度限制(例如限制为 45 度)
cameraController.maximumTiltAngle = Cesium.Math.toRadians(45);

关于Cesium.GeoJsonDataSource.load()加载geojson,设置边界的宽度不生效的问题

js
 Cesium.GeoJsonDataSource.load(zhoushan, {
      stroke: Cesium.Color.fromCssColorString('#00203f'), // 边界线颜色
      strokeWidth: 2, // 边界线宽度
      fill: Cesium.Color.fromAlpha(Cesium.Color.BLUE, 0), // 填充颜色和透明度
    })
      .then((dataSource) => {
     	 viewer.dataSources.add(dataSource);
 	}

使用上述的方法加载geojson,绘制边界线发现设置strokeWidth边界线的粗细不生效的。

原因是你的geojson文件

微信截图_20241127153929

如果你加载的是MultiPolygon类型的话 代表是个多边形的 所以strokeWidth无效,将MultiPolygon转换成MultiLineString即可

微信截图_20241127154004

转换脚本

如果不想转换的话也可以实现,通过给entity.polygon添加材质实现边界线的线条粗细

js
 function loadBoundary() {
    // 加载GeoJSON数据并设置边界样式
    Cesium.GeoJsonDataSource.load(zhoushan, {
      stroke: Cesium.Color.fromCssColorString('#00203f'), // 边界线颜色
      strokeWidth: 2, // 边界线宽度
      fill: Cesium.Color.fromAlpha(Cesium.Color.BLUE, 0), // 填充颜色和透明度
    })
      .then((dataSource) => {
        // 将GeoJSON数据添加到地图中
        dataSource.entities.values.forEach(function (entity) {
          if (entity.polygon) {
            entity.polygon.outline = false;

           var positions = entity.polygon.hierarchy._value.positions;
            entity.polyline = {
              positions: positions,
              width: 2,
              material: Cesium.Color.fromCssColorString('#00203f'),
            };
          } 
         });
        viewer.dataSources.add(dataSource);
      })
      .catch((error) => {
        console.error('加载GeoJSON失败:', error);
      });
  }

材质

电子围墙

js
/*
      动态墙材质
      color 颜色
      duration 持续时间 毫秒
      trailImage 贴图地址
  */
import * as Cesium from 'cesium'

export default class DynamicWallMaterialProperty {
  constructor(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 视图对象
  }
  // 返回材质类型
  getType(time) {
    return MaterialType // 返回材质类型名称
  }
  getValue(time, result) {
    if (!Cesium.defined(result)) {
      result = {} // 如果结果未定义,则初始化为空对象
    }
    result.color = Cesium.Property.getValueOrClonedDefault(
      this._color, // 获取颜色值
      time, // 当前时间
      Cesium.Color.WHITE, // 默认颜色为白色
      result.color // 结果对象中的颜色属性
    )
    // 使用自定义的路径图像
    result.image = this.trailImage
    // 计算时间进度
    if (this.duration) {
      result.time =
        ((new Date().getTime() - this._time) % this.duration) / this.duration
    }
    this._viewer.scene.requestRender() // 请求重新渲染场景
    return result
  }
  // 比较两个 DynamicWallMaterialProperty 对象是否相等
  equals(other) {
    return (
      this === other || // 判断是否为同一对象
      (other instanceof DynamicWallMaterialProperty && // 判断是否为 DynamicWallMaterialProperty 的实例
        Cesium.Property.equals(this._color, other._color)) // 比较颜色属性
    )
  }
}

/**
 * 带方向的墙体
 * @param {*} options.get:true/false
 * @param {*} options.count:数量
 * @param {*} options.freely:vertical/standard
 * @param {*} options.direction:+/-
 */
function _getDirectionWallShader(options) {
  if (options && options.get) {
    // 定义了一个函数 czm_getMaterial,输入参数为 materialInput,返回值为 czm_material 类型的材质。
    var materail = `czm_material czm_getMaterial(czm_materialInput materialInput)
      {
      // 调用 czm_getDefaultMaterial 函数获取一个默认的材质实例,并将其存储在 material 变量中
          czm_material material = czm_getDefaultMaterial(materialInput);
          // 获取纹理坐标(st)的二维向量
          vec2 st = materialInput.st;`
    // 垂直方向动态效果
    if (options.freely == 'vertical') {
      //(由下到上)
      // texture(image, vec2(u,v)),st.s 是水平方向上的纹理坐标,st.t 是垂直方向上的纹理坐标。
      // 如果要实现上下垂直滚动的效果,就要设置st.t随时间的动态,而st.s值不变。
      // 如果要实现左右水平滚动的效果,就要设置st.s随时间的动态,而st.t值不变。
      materail +=
        // 纹理采样,依据时间动态变化,fract 函数用于计算余数,使纹理坐标在[0, 1)范围内循环。
        'vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(' +
        options.count +
        ')*st.t' +
        options.direction +
        ' time)));\n '
    } else {
      // 水平方向的动态效果
      //(逆时针)
      materail +=
        'vec4 colorImage = texture(image, vec2(fract(float(' +
        options.count +
        ')*st.s ' +
        options.direction +
        ' time), fract(st.t)));\n '
      console.log('materail2: ', materail)
    }
    //泛光
    materail += `vec4 fragColor;
          fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;
          fragColor = czm_gammaCorrect(fragColor);
          material.diffuse = colorImage.rgb;
          material.alpha = colorImage.a;
          material.emission = fragColor.rgb;
          return material;
      }`
    return materail
  }
}

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

// 定义一个变量MaterialType,其值为字符串'wallType'加上一个随机数
var MaterialType = 'wallType' + parseInt(Math.random() * 1000)
// 定义默认图像路径
let DynamicWallImage = '/src/assets/col.png'

// 将材质添加到缓存中
Cesium.Material._materialCache.addMaterial(MaterialType, {
  fabric: {
    type: MaterialType, // 设置材质类型
    uniforms: {
      color: new Cesium.Color(1.0, 0.0, 0.0, 0.5), // 设置颜色属性
      image: DynamicWallImage, // 设置图像路径
      time: -20, // 设置时间属性
    },
    source: _getDirectionWallShader({
      get: true,
      count: 3.0,
      freely: 'vertical', //或者standard
      direction: '+',
    }),
  },
  translucent: function (material) {
    return true // 确定材质是否是半透明的
  },
})

调用:

js
import DynamicWallMaterialProperty from '../../utils/cesium/WallDiffuseDymaticMaterial.js'


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(600),
      minimumHeights: new Array(positions.length).fill(0),
      material: new DynamicWallMaterialProperty({
        viewer,
        // trailImage: '/src/assets/vertical.png',
        trailImage: '/src/assets/standard.png',
        color: Cesium.Color.RED,
        duration: 1500,
      }),
    },
  })
  viewer.zoomTo(wall)

1.垂直方向

  • 往下滚动
js
vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(3)*st.t + time)));

source: _getDirectionWallShader({
      get: true,
      count: 3.0,
      freely: 'vertical', //或者standard
      direction: '+',
    }),
  • 往上滚动
js
vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(3)*st.t - time)));

source: _getDirectionWallShader({
      get: true,
      count: 3.0,
      freely: 'vertical', //或者standard
      direction: '-',
    }),

2.水平方向

  • 顺时针
php
php 代码解读复制代码vec4 colorImage = texture(image, vec2(fract(float(8)*st.s - time), fract(st.t)));

source: _getDirectionWallShader({
      get: true,
      count: 20.0,
      freely: 'standard', //或者standard
      direction: '-',
    }),
  • 逆时针
php
php 代码解读复制代码vec4 colorImage = texture(image, vec2(fract(float(8)*st.s + time), fract(st.t)));

source: _getDirectionWallShader({
      get: true,
      count: 20.0,
      freely: 'standard', //或者standard
      direction: '+',
    }),