Cesium開發三維地圖入門


需求:要求將GLTF三維模型放到地圖上展示,並且添加各種圖標和線進行標注。

 用CesiumJS地圖庫實現代碼如下:

引入CesiumJS庫

1、直接clone源碼包,在index.html中引入,如下:

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
  <meta name="description" content="Create 3D models using glTF.">
  <title>Chemical plant</title>
  <script type="text/javascript" src="../../Cesium-1.77/Build/Cesium/Cesium.js"></script>
  <link href="../../Cesium-1.77/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>

<body>
  <div id="cesiumContainer"></div>

2、參考官網說明(https://www.cesium.com/docs/tutorials/cesium-and-webpack/)用npm安裝

 貼下package.json和webpack.config.js:

package.json

{
  "name": "cesium-webpack-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "node_modules/.bin/webpack --config webpack.config.js",
    "start": "node_modules/.bin/webpack serve --config webpack.config.js --open"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cesium": "^1.78.0",
    "copy-webpack-plugin": "^7.0.0",
    "css-loader": "^5.0.2",
    "html-webpack-plugin": "^5.2.0",
    "style-loader": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.23.0",
    "webpack-cli": "^4.5.0",
    "webpack-dev-server": "^3.11.2"
  }
}

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';



module.exports = {
    context: __dirname,
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist'),
        sourcePrefix: ''
    },
    amd: {
        toUrlUndefined: true
    },
    module: {
        rules: [{
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        }, {
            test: /\.(png|gif|jpg|jpeg|svg|xml|json)$/,
            use: ['url-loader']
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }),
        new CopyWebpackPlugin({
            patterns: [
                { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' },
                { from: path.join(cesiumSource, 'Assets'), to: 'Assets' },
                { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' }
            ]
        }),
        new webpack.DefinePlugin({
            CESIUM_BASE_URL: JSON.stringify('')
        })
    ],
    devServer: {
        contentBase: path.join(__dirname, "dist")
    },
    resolve: {
        alias: {
            cesium: path.resolve(__dirname, cesiumSource)
        },
        fallback: {
            fs: false
        }
    }
};

以上2種方式經測試都不需要在官網申請token,直接使用api即可。

 

初始化地圖:

    const imageryProvider = new Cesium.UrlTemplateImageryProvider({
      url: "http://webst01.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x={x}&y={y}&z={z}",
      tilingScheme: new Cesium.WebMercatorTilingScheme(),
      fileExtension: 'png',
      minimumLevel: 0,
      maximumLevel: 20,
    });

    const viewer = new Cesium.Viewer("cesiumContainer", {
      imageryProvider: imageryProvider,
      animation: false,        //是否顯示動畫控件
      homeButton: false,       //是否顯示home鍵
      geocoder: false,         //是否顯示地名查找控件,如果設置為true,則無法查詢
      baseLayerPicker: false,  //是否顯示圖層選擇控件
      timeline: false,         //是否顯示時間線控件
      fullscreenButton: false,  //是否全屏顯示
      scene3DOnly: true,       //如果設置為true,則所有幾何圖形以3D模式繪制以節約GPU資源
      infoBox: false,           //是否顯示點擊要素之后顯示的信息
      sceneModePicker: false,  //是否顯示投影方式控件  三維/二維
      navigationInstructionsInitiallyVisible: false,
      navigationHelpButton: false,     //是否顯示幫助信息控件
      selectionIndicator: false,       //是否顯示指示器組件
    });

    viewer._cesiumWidget._creditContainer.style.display = "none";

    //添加文字標注
    viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
      url: "http://t0.tianditu.com/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=TOKEN",
      layer: "tdtAnnoLayer",
      style: "default",
      format: "image/jpeg",
      tileMatrixSetID: "GoogleMapsCompatible",
      show: false,
    }));

    viewer.scene.primitives.add(Cesium.createOsmBuildings());
    viewer.scene.highDynamicRange = false;
    viewer.shadows = false;

    { //修改鼠標控制地圖視圖的默認行為:左鍵拖動,右鍵旋轉
      viewer.scene.screenSpaceCameraController.zoomEventTypes = [
        Cesium.CameraEventType.WHEEL,
        Cesium.CameraEventType.MIDDLE_DRAG,
        Cesium.CameraEventType.PINCH,
      ];
      viewer.scene.screenSpaceCameraController.tiltEventTypes = [
        Cesium.CameraEventType.RIGHT_DRAG,
        Cesium.CameraEventType.PINCH,

        {
          eventType: Cesium.CameraEventType.RIGHT_DRAG,
          modifier: Cesium.KeyboardEventModifier.CTRL,
        },

        {
          eventType: Cesium.CameraEventType.MIDDLE_DRAG,
          modifier: Cesium.KeyboardEventModifier.CTRL,
        },
      ];
    }


    createGltfModel("../../data/gltf/NewFile.gltf", 117.628293, 23.798717, 0.0, {
      modelScale: 1, //模型放大倍數
      lightColor: new Cesium.Cartesian3(20.0, 20.0, 20.0), //模型的材質亮度
      position: {
        //地圖初始化位置,坐標是3維笛卡爾坐標
        x: -2707823.1735314624,
        y: 5173260.303294086,
        z: 2558159.506208664,
      },
      orientation: {
        heading: 4.735189003200103,
        pitch: -0.4113143959917751,
        roll: 6.2804863005660785,
      },
    });

    function createGltfModel(url, lng, lat, height, {
      modelScale,
      lightColor,
      position,
      orientation
    } = {
        modelScale: 1,
        lightColor: new Cesium.Cartesian3(0, 0, 0),
        position: { x: 0, y: 0, z: 0 },
        orientation: { heading: 0, pitch: 0, roll: 0 }
      }) {
      viewer.entities.removeAll();
      let ellipsoid = viewer.scene.globe.ellipsoid;
      let cart3 = ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(lng, lat, height));
      let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(cart3);
      let model = viewer.scene.primitives.add(Cesium.Model.fromGltf({
        url,
        modelMatrix,
        scale: 1,     //放大倍數
        lightColor,//gltf模型加載后比較暗,這個起到增大模型材質亮度的作用
      }));

      let initialPosition = new Cesium.Cartesian3(position.x, position.y, position.z); // 相機的位置
      let homeCameraView = {
        destination: initialPosition, // 相機的位置
        orientation,
      };

      viewer.scene.camera.setView(homeCameraView);

      
      /**
       * 這個時間是我調試的結果,模型不至於很暗
       * 主要是時間要調到太陽照射到整個模型區域,日期沒有多大影響
       */
      let utc = Cesium.JulianDate.fromDate(new Date("2021/02/20 03:40:00"));//UTC
      viewer.clock.currentTime = Cesium.JulianDate.addHours(utc, 8, new Cesium.JulianDate());
    }

 抗鋸齒處理:

 //抗鋸齒處理
    {
      viewer.scene.fxaa = true
      viewer.scene.postProcessStages.fxaa.enabled = true;
      let supportsImageRenderingPixelated = viewer.cesiumWidget._supportsImageRenderingPixelated;
      if (supportsImageRenderingPixelated) {
        let vtxf_dpr = window.devicePixelRatio;
        while (vtxf_dpr >= 2.0) { vtxf_dpr /= 2.0; }
        viewer.resolutionScale = vtxf_dpr;
      }
    }

添加圖片:

 //添加圖片
    {
      const iconMarks = [
        {
          id: 'factory1',
          position: [117.62514171688602, 23.800514411219126, 40],
          image: '../../data/icons/廢氣-C.png',
        },
        {
          id: 'factory2',
          position: [117.62441672316956, 23.801488899527932, 40],
          image: '../../data/icons/廢氣-C.png',
        },
        {
          id: 'camera1',
          position: [117.62438331048037, 23.80172986514075, 20],
          image: '../../data/icons/攝像頭-C.png',
          width: 13,
          height: 18
        },
        {
          id: 'camera2',
          position: [117.6251283858732, 23.801983468675637, 10],
          image: '../../data/icons/攝像頭-C.png',
          width: 13,
          height: 18
        }
      ];

      for (const mark of iconMarks) {
        let width = mark.width || 30;
        let height = mark.height || 30;
        viewer.entities.add({
          id: mark.id,
          name: 'mark',
          position: Cesium.Cartesian3.fromDegrees(...mark.position),
          billboard: {
            // 圖像地址,URI或Canvas的屬性
            image: mark.image,
            // 設置顏色和透明度
            // color: Cesium.Color.WHITE.withAlpha(1),
            // 高度(以像素為單位)
            height,
            // 寬度(以像素為單位)
            width,
            // 逆時針旋轉
            rotation: 0,
            // 大小是否以米為單位
            sizeInMeters: false,
            // 相對於坐標的垂直位置
            verticalOrigin: Cesium.VerticalOrigin.CENTER,
            // 相對於坐標的水平位置
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
            // 該屬性指定標簽在屏幕空間中距此標簽原點的像素偏移量
            pixelOffset: new Cesium.Cartesian2(-width / 2, -height / 2),
            // 應用於圖像的統一比例。比例大於會1.0放大標簽,而比例小於會1.0縮小標簽。
            scale: 1.0,
            // 是否顯示
            show: true
          }
        });
      }
    }

添加線:

 //添加線
    {
      const markLines = [
        {
          id: 'line1',
          positions: [[117.62514171688602, 23.800514411219126, 0], [117.62514171688602, 23.800514411219126, 40]],
        },
        {
          id: 'line2',
          positions: [[117.62441672316956, 23.801488899527932, 0], [117.62441672316956, 23.801488899527932, 40]],
        },
        {
          id: 'line3',
          positions: [[117.62441672316956, 23.801488899527932, 20],
          [117.62438331048037, 23.80172986514075, 20],
          [117.6251283858732, 23.801983468675637, 10],
          [117.62516689671625, 23.802117335288763, 10]]
        }
      ];

      for (const line of markLines) {
        let polyline = new Cesium.PolylineGraphics();
        polyline.material = new Cesium.ColorMaterialProperty(new Cesium.Color(0.18, 0.67, 1, 1));
        polyline.width = new Cesium.ConstantProperty(2);
        polyline.arcType = new Cesium.ConstantProperty(
          Cesium.ArcType.NONE
        );
        let coordArr = line.positions.map(e => Cesium.Cartesian3.fromDegrees(...e));
        console.log('coordArr', coordArr);
        polyline.positions = new Cesium.ConstantProperty(coordArr);
        let entity = new Cesium.Entity({
          id: line.id,
          show: true,
          polyline,
          name: 'line',
        });
        viewer.entities.add(entity);
      }
    }

添加事件:

//事件
    {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction(function (evt) {
        let pick = viewer.scene.pick(evt.position);
        // //選中某模型
        if (pick && pick.id) {
          alert(pick.id._id)
        }
        let cartesian = viewer.camera.pickEllipsoid(evt.position, viewer.scene.globe.ellipsoid);
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        let lng = Cesium.Math.toDegrees(cartographic.longitude);//經度值
        let lat = Cesium.Math.toDegrees(cartographic.latitude);//緯度值
        let mapPosition = { x: lng, y: lat, z: cartographic.height };//cartographic.height的值始終為零。
        // console.log('mapPosition: ', mapPosition);
        console.log('lng: ', lng, 'lat: ', lat);//拾取坐標

      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      handler.setInputAction(evt => {
        let pick = viewer.scene.pick(evt.endPosition);
        //選中某模型
        if (pick && pick.id && pick.id._name === 'mark') {
          // console.log('pick', pick.id._id);
// 修改鼠標指針樣式
viewer._container.style.cursor = 'pointer'; } else { viewer._container.style.cursor = ''; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) }

 

 

效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM