VUE3+Cesium+Three项目源码

本文介绍了如何使用 Vue3、Cesium 和 Three.js 构建地理信息系统项目,并进行了模块化的封装,包括 Cesium 和 Three.js 的独立初始化、Vue 路由和 Vuex 的集成,以及在项目中的具体实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继上一篇Vue+Cesium+Three项目构建的详解后,为了方便使用,进一步对该项目进行模块化封装。 

VUE3+Cesium+Three项目构建_HM-hhxx!的博客-优快云博客VUE3+Cesium+Three项目创建及原理详解。https://blog.youkuaiyun.com/damadashen/article/details/126550168

目录

1.初始化Cesium:initCesium.js

2.初始化Three:initThree.js

3.HomeView.vue


该版本项目中,将cesium初始化与Three初始化剥离开,在日后使用中更为便捷,并在vue

初始化时加入router及vuex状态管理,便于后续大型项目开发使用,项目结构如下:

1.初始化Cesium:initCesium.js

import * as Cesium from "cesium";
import "../Widgets/widgets.css";
// 设置cesium的token
Cesium.Ion.defaultAccessToken =
  "your_token";
// cesium默认资源路径
window.CESIUM_BASE_URL = "/Cesium/";
// 设置默认的视角为中国
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
  // 西边经度
  89.5,
  // 南边维度
  20.4,
  // 东边经度
  110.4,
  // 北边维度
  61.2
);
// 设置全局cesium对象
let cesium = {
  viewer: null,
};
function initCesium(minWGS84, maxWGS84, cesiumContainerid) {
  var cesiumContainer = cesiumContainerid;
  // 设置cesium容器
  var cesiumContainer = document.getElementById("cesiumContainer");
  // 初始化cesium渲染器
  cesium.viewer = new Cesium.Viewer(cesiumContainer, {
    useDefaultRenderLoop: false,
    selectionIndicator: false,
    homeButton: false,
    infoBox: false,
    sceneModePicker: false,
    navigationHelpButton: false,
    animation: false,
    timeline: false,
    fullscreenButton: false,
    baseLayerPicker: false,
    clock: false,
    geocoder: false,
    //     天地图矢量路径图
    imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
      url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=30d07720fa76f07732d83c748bb84211",
      layer: "tdtBasicLayer",
      style: "default",
      format: "image/jpeg",
      tileMatrixSetID: "GoogleMapsCompatible",
    }),
    //cesium中webgl选项
    contextOptions: {
      webgl: {
        //透明度
        alpha: false,
        // 抗锯齿
        antialias: true,
        //深度检测
        depth: true,
      },
    },
  });
  //设置隐藏logo
  cesium.viewer.cesiumWidget.creditContainer.style.display = "none";
  // 设置抗锯齿
  cesium.viewer.scene.postProcessStages.fxaa.enabled = true;
  // 地图叠加
  var imageryLayers = cesium.viewer.imageryLayers;
  //console.log(imageryLayers);
  var layer = imageryLayers.addImageryProvider(
    new Cesium.WebMapTileServiceImageryProvider({
      url: "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=30d07720fa76f07732d83c748bb84211",
      layer: "tdtBasicLayer",
      style: "default",
      format: "image/jpeg",
      tileMatrixSetID: "GoogleMapsCompatible",
    })
  );
  layer.alpha = 0.5;
  // 设置前往地点
  let center = Cesium.Cartesian3.fromDegrees(
    (minWGS84[0] + maxWGS84[0]) / 2,
    (minWGS84[1] + maxWGS84[1]) / 2,
    20000
  );

  // 设置相机飞往该区域
  cesium.viewer.camera.flyTo({
    destination: center,
    duration: 2,
    orientation: {
      heading: Cesium.Math.toRadians(0),
      pitch: Cesium.Math.toRadians(-90),
      roll: 0,
    },
  });
}
function renderCesium() {
  cesium.viewer.render();
}
function exportCesium() {
    let cesiumdone = cesium;
    return cesiumdone;
}
export  { exportCesium,initCesium, renderCesium };

2.初始化Three:initThree.js

import * as THREE from "three";
import * as Cesium from "cesium";

// three全局对象
let three = {
  renderer: null,
  camera: null,
  scene: null,
};
// three.js物体
let objects3D = [];
//封装three物体(使three物体具有经纬度)
function Object3D(mesh, minWGS84, maxWGS84) {
  this.threeMesh = mesh; //物体
  this.minWGS84 = minWGS84; //范围
  this.maxWGS84 = maxWGS84; //范围
}
function initThree() {
  //初始化Three
  // 设置相机配置
  let fov = 45; //视角
  let aspect = window.innerWidth / window.innerHeight; //宽高比例
  let near = 0.1;
  let far = 10 * 1000 * 1000; //视域范围

  // 初始化场景
  three.scene = new THREE.Scene();
  three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  three.renderer = new THREE.WebGLRenderer({
    antialias: true, //抗锯齿
    alpha: true,
  });
  // 设置渲染器大小
  three.renderer.setSize(window.innerWidth, window.innerHeight);

  // 添加环境光
  let ambientLight = new THREE.AmbientLight(0xffffff, 1);
  three.scene.add(ambientLight);
  // 添加three.jscanvas元素到cesium容器
  cesiumContainer.appendChild(three.renderer.domElement);
}
// 创建three.js物体
function createMesh(minWGS84, maxWGS84) {
  let geometry = new THREE.BoxBufferGeometry(1, 1, 1);
  let material = new THREE.MeshBasicMaterial({
    color: 0x00ff00,
  });
  let mesh = new THREE.Mesh(geometry, material);

  // 放大物体
  mesh.scale.set(100, 100, 100); // 放大
  mesh.position.set(0, 0, 50); // 平移

  let meshGroup = new THREE.Group();
  meshGroup.add(mesh);
  // 添加至场景
  three.scene.add(meshGroup);
  // 创建3d物体
  let OB3d = new Object3D(
    meshGroup,
    [minWGS84[0], minWGS84[1]],
    [maxWGS84[0], maxWGS84[1]]
  );

  // 添加到3d物体数组
  objects3D.push(OB3d);
}

function renderThree(cesium) {
  // 设置相机跟cesium保持一致
  
  three.camera.fov = Cesium.Math.toDegrees(cesium.viewer.camera.frustum.fovy);
  //console.log(cesium);
  // 声明一个将cesium框架的cartesian3转换为three.js的vector3(笛卡尔坐标转换为三维向量)
  let cartToVec = function (cart) {
    return new THREE.Vector3(cart.x, cart.y, cart.z);
  };
  // 将3D的物体通过经纬度转换成对应的位置
  objects3D.forEach((item, index) => {
    // 通过经纬度获取中心点的位置
    let center = Cesium.Cartesian3.fromDegrees(
      (item.minWGS84[0] + item.maxWGS84[0]) / 2,
      (item.minWGS84[1] + item.maxWGS84[1]) / 2
    );
    item.threeMesh.position.copy(cartToVec(center));

    //计算朝向(切面方向-切线向量)
    //中心高度点
    let centerHeight = Cesium.Cartesian3.fromDegrees(
      (item.minWGS84[0] + item.maxWGS84[0]) / 2,
      (item.minWGS84[1] + item.maxWGS84[1]) / 2,
      1
    );
    //左下
    let bottomLeft = cartToVec(
      Cesium.Cartesian3.fromDegrees(item.minWGS84[0], item.minWGS84[1])
    );
    //左上
    let topLeft = cartToVec(
      Cesium.Cartesian3.fromDegrees(item.minWGS84[0], item.maxWGS84[1])
    );
    //朝向()
    let latDir = new THREE.Vector3()
      .subVectors(bottomLeft, topLeft)
      .normalize();

    // console.log(item);
    //设置查看方向
    item.threeMesh.lookAt(centerHeight.x, centerHeight.y, centerHeight.z);
    //设置朝向
    item.threeMesh.up.copy(latDir);
  });

  //设置摄像机矩阵
  // 设置相机跟cesium保持一致
  three.camera.matrixAutoUpdate = false; //自动更新
  //复制cesium相机矩阵
  let cvm = cesium.viewer.camera.viewMatrix;
  let civm = cesium.viewer.camera.inverseViewMatrix;
  // three相机默认朝向0,0,0
  three.camera.lookAt(0, 0, 0);

  // 设置threejs相机矩阵
  three.camera.matrixWorld.set(
    civm[0],
    civm[4],
    civm[8],
    civm[12],
    civm[1],
    civm[5],
    civm[9],
    civm[13],
    civm[2],
    civm[6],
    civm[10],
    civm[14],
    civm[3],
    civm[7],
    civm[11],
    civm[15]
  );

  three.camera.matrixWorldInverse.set(
    cvm[0],
    cvm[4],
    cvm[8],
    cvm[12],
    cvm[1],
    cvm[5],
    cvm[9],
    cvm[13],
    cvm[2],
    cvm[6],
    cvm[10],
    cvm[14],
    cvm[3],
    cvm[7],
    cvm[11],
    cvm[15]
  );
  //设置宽高比例
  let width = cesiumContainer.clientWidth;
  let height = cesiumContainer.clientHeight;
  three.camera.aspect = width / height;
  //更新相机矩阵
  three.camera.updateProjectionMatrix();
  //设置尺寸大小
  three.renderer.setSize(width, height);
  three.renderer.clear();
  three.renderer.render(three.scene, three.camera);
}
export {initThree,createMesh,renderThree};

3.HomeView.vue

<template>
  <div id="cesiumContainer" ref="cesiumContainer"></div>
</template>

<script setup>
import { onMounted } from "vue";
import * as Cesium from "cesium";
//import "cesium/Build/Cesium/Widgets/widgets.css";
import "../Widgets/widgets.css";
import * as THREE from "three";
import { exportCesium, initCesium, renderCesium } from "../cesium/cesium_init.js";
import { initThree, createMesh, renderThree } from "../three/three_init.js"

onMounted(() => {
  main();
});

function main() {
  // 设置北京显示模型的渲染范围(用于设置范围)
  var minWGS84 = [115.39, 38.9];
  var maxWGS84 = [117.39, 40.9];
  //初始化Cesium
  initCesium(minWGS84, maxWGS84, cesiumContainer);
  var cesium = exportCesium();
  //初始化Three
  initThree(minWGS84, maxWGS84);
  //创建物体
  createMesh(minWGS84, maxWGS84);
    //循环函数,不断请求动画帧渲染
  function loop() {
    requestAnimationFrame(loop);
    // cesium渲染
    renderCesium();
    // three.js渲染
    renderThree(cesium);
  }
  loop();
}
</script>

<style>
* {
  margin: 0;
  padding: 0;
}

#cesiumContainer {
  width: 100vw;
  height: 100vh;
  position: relative;
}

#cesiumContainer>canvas {
  position: absolute;
  top: 0;
  left: 0;
  /* 设置鼠标事件穿透 */
  pointer-events: none;
}
</style>

源码地址:

GitHub - Harsh-M1/vue_cesium_three_templateContribute to Harsh-M1/vue_cesium_three_template development by creating an account on GitHub.https://github.com/Harsh-M1/vue_cesium_three_template


vue_cesium_three_template: 使用VUE3+cesium+three.js构建的基础想木模板!https://gitee.com/lei-aimiao/vue_cesium_three_template

在智慧城市数字孪生相关的 Vue.js 开发中,可以结合 Web3D 技术(如 Three.jsCesium、Mapbox GL JS 等)构建可视化系统。以下是一些源码示例和实现思路: ### 组件结构设计 Vue 的组件化特性非常适合用于构建模块化的数字孪生前端应用。例如,一个基础的三维场景组件可以如下定义: ```vue <template> <div class="scene-container"> <canvas ref="webglCanvas"></canvas> </div> </template> <script> import * as THREE from &#39;three&#39;; export default { name: &#39;ThreeScene&#39;, mounted() { this.initThree(); }, methods: { initThree() { const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ canvas: this.$refs.webglCanvas }); renderer.setSize(window.innerWidth, window.innerHeight); const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); camera.position.z = 5; const animate = () => { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); }; animate(); } } }; </script> <style scoped> .scene-container { width: 100%; height: 100vh; } </style> ``` 该组件封装了 Three.js 的基本初始化流程,并可在任意 Vue 页面中复用。 ### 数据接入与状态管理 对于智慧城市平台而言,通常需要接入多种实时数据,如传感器信息、交通流量等。可以使用 Vuex 进行全局状态管理,并通过 WebSocket 或 HTTP 接口获取数据流: ```javascript // store/index.js import Vue from &#39;vue&#39;; import Vuex from &#39;vuex&#39;; Vue.use(Vuex); export default new Vuex.Store({ state: { sensorData: {} }, mutations: { updateSensorData(state, payload) { state.sensorData = { ...state.sensorData, ...payload }; } }, actions: { fetchSensorData({ commit }) { // 模拟从后端获取数据 setInterval(() => { const mockData = { temperature: Math.random() * 40 }; commit(&#39;updateSensorData&#39;, mockData); }, 2000); } }, modules: {} }); ``` 然后在组件中监听这些数据变化并更新 3D 场景中的对应元素[^2]。 ### 数字孪生平台集成 为了更贴近实际应用,可参考类似“杨浦滨江智慧大脑”项目中的多源数据融合方式[^4],将 GIS 数据、三维模型、设备运行数据整合进 Vue 应用中。例如使用 Mapbox GL JS 展示地图底图,叠加 Cesium 显示建筑模型和动态设备状态: ```javascript // 在 Vue 组件中初始化 Cesium Viewer mounted() { const viewer = new Cesium.Viewer(&#39;cesiumContainer&#39;, { terrainProvider: new Cesium.CesiumTerrainProvider({ url: Cesium.IonResource.fromAssetId(1) }) }); // 加载城市建筑模型 const buildingEntity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-115.0, 37.0, 0), model: { uri: &#39;/models/city_building.glb&#39; } }); viewer.zoomTo(viewer.entities); } ``` 此外,还可以利用低代码编辑器框架提升开发效率,尤其是在结合 AI 功能时,使开发者专注于业务逻辑而非底层渲染细节[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HM-hhxx!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值