CesiumJS整合ThreeJS插件封装

6 篇文章 0 订阅
2 篇文章 0 订阅

最近做项目有一个三维需求使用CesiumJS比较难以实现,发现THREEJS中效果比较合适,于是准备将THREEJS整合到CesiumJS中

为实现效果所需我们找到官方Integrating Cesium with Three.js博客,于是根据该博客提供的思路去实现整合

一、创建ThreeJS类

为了开发时更好的扩展性把他写到了一个ThreeJS 类里面,功能直接调用即可

function ThreeJs(viewer, cesiumGlobal, defaultStatic, threeConf) {
  if (viewer && threeConf) {
    const { threeGlobal, containerId, threeContainerId } = threeConf;
    Cesium = cesiumGlobal;
    THREE = threeGlobal;
    this._viewer = viewer;
    this._containerId = containerId;
    this._threeContainerId = threeContainerId;
    this._initContainer();
    this._initThree();
  }
}
//部分省略......

项目中使用

哔哩哔哩使用介绍 >>> https://www.bilibili.com/video/BV1PKaEeeEmx/?share_source=copy_web&vd_source=fa1aa0302eb3667530ecc801e28d9687


Youtube 案例介绍 https://www.youtube.com/watch?v=2G_dA-ExPPY


import { ThreeJs } from 'cesium_dev_kit'

// 初始化map
 initMap (){
     const ThreeJsObj = new ThreeJs({
        cesiumGlobal: Cesium,
        threeGlobal: THREE,
        containerId: 'cesiumContainer',
        threeContainerId: 'threeContainer',
//部分省略......
      })
      this.c_viewer = ThreeJsObj.viewer;
      this.threeJs = ThreeJsObj.threeJs;
      this.initThree(this.threeJs);
  },
  // 初始化ThreeJs
 initThree (ThreeJs) {
      const threeDObject = this.create3DOject(ThreeJs, this.c_viewer);
      ThreeJs.addThreeObjects(threeDObject)

      this.c_viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)//解除视角锁定
    },
    // 创建三维模型
  create3DOject (threeObj, viewer) {
      let three = threeObj._three;
      let _3Dobjects = [], _3DOB;
      let entity = {
        name: 'Polygon',
        polygon: {
          hierarchy: Cesium.Cartesian3.fromDegreesArray([
            minWGS84[0], minWGS84[1],
            maxWGS84[0], minWGS84[1],
            maxWGS84[0], maxWGS84[1],
            minWGS84[0], maxWGS84[1]
          ]),
          material: Cesium.Color.RED.withAlpha(0.1)
        }
      }
      let Polypon = viewer.entities.add(entity);
      let doubleSideMaterial = new THREE.MeshNormalMaterial({
        side: THREE.DoubleSide
      });
//部分省略......
      return _3Dobjects;
    }   

根据官网的思量整合后最终实现效果如下
实现效果
效果是实现了,但是这个封装耦合性相当高,多个功能都需要使用这个插件时特别蹩脚,于是开始了下一次造…

二、插件threeJs 优化

理解官方案例的思路整合关键主要有三个方面,第一个是同步Camera,第二个是同步Scene中的物体位置,第三个是需要同步CesiumJS和THREEJS 的render重绘程序

1、创建ThressScene工具

为了扩展与管理我们抽离一个Scene 的工具js

class Scene extends THREE.Scene {}

在这个js 里面去实现插件操作的优化

1.1、同步camera

创建一个updateCameraMatrix来同步项目位置,核心代码如下

  updateCameraMatrix() {
      //同步相机
      this.camera.fov = Cesium.Math.toDegrees(
        this.cesiumViewer.camera.frustum.fovy
      ) // ThreeJS FOV is vertical
      this.camera.updateProjectionMatrix()

      this.camera.matrixAutoUpdate = false
      const cvm = this.cesiumViewer.camera.viewMatrix
      const civm = this.cesiumViewer.camera.inverseViewMatrix
      this.camera.lookAt(this.cameraCenter)
//部分省略......
      const width = this.cesiumViewer.scene.canvas.clientWidth
      const height = this.cesiumViewer.scene.canvas.clientHeight
      this.camera.aspect = width / height
      this.camera.updateProjectionMatrix()

      this.renderer.setSize(width, height)

      return this
    }
1.2、同步场景中的物体

创建一个updateGroupMatrixWorld来进行物体位置同步,核心代码如下

	 // 重写add 方法
     add(object) {
      if (arguments.length > 1) {
        for (let i = 0; i < arguments.length; i++) {
          this.childrenGroup.add(arguments[i])
        }

        return this
      }
	//部分省略......
      return this
    }
    updateGroupMatrixWorld() {
      // 得到面向模型的前向方向
      const center = this.cartesian3ToVector(
        Cesium.Cartesian3.fromDegrees(this.lngLat[0], this.lngLat[1], 0)
      )
      // 使用从左下到左上的方向作为上向量
      const topLeft = this.cartesian3ToVector(
        Cesium.Cartesian3.fromDegrees(this.lngLat[0], this.lngLat[1], 2)
      )
      const latDir = new THREE.Vector3().subVectors(center, topLeft).normalize()

      // 配置实体的位置和方向
      // this.syncGroup.position.copy(center)
      this.syncGroup.lookAt(latDir)
      this.syncGroup.up.copy(latDir)
      this.syncGroup.updateMatrix()

      this.cameraOffset.copy(center)

      this.sphere.position.set(0 - center.x, 0 - center.y, 0 - center.z)
      this.syncGroup.up.set(0, 0, -1)
      this.up.set(0, 0, -1)

      return this
    }
1.3、同步render
    renderCesium() {
      this.cesiumViewer.render()
      return this
    }

    renderThree() {
      this.renderer.render(this, this.camera)
      return this
    }
    
   loop(callback) {
    const _loop = function () {
      let time = requestAnimationFrame(_loop)
      callback && callback(time)
    }
    _loop()
  }

2、插件使用

插件改完了心里还是有点鸡冻,马上在项目中引入开始测试

2.1 引入插件初始化map
import { initCesium } from 'cesium_dev_kit'

// 初始化map
 initMap (){
      const { viewer, threeJs, base, graphics, material } = new initCesium({
        cesiumGlobal: Cesium,
        threeGlobal: THREE,
        containerId: 'cesiumContainer',
        threeContainerId: 'threeContainer',
		//部分省略......
      })
      this.c_viewer = viewer;
      this.threeJs = threeJs;
      this.base = base;
      this.graphics = graphics;
      this.material = material
      this.initThree(this.threeJs);
      // this.getClickPosition()
      this.createAEllipsoid();
      this.createAFanShape();
  },
2.1 初始化Meshes

这里我们就使用官方的extrude案例

    initMeshes (scene) {
      // 环形 extrude
      const closedSpline = new THREE.CatmullRomCurve3([
        new THREE.Vector3(-60, 30, 60), // 左下
        new THREE.Vector3(-60, 100, 60), // 左中
        new THREE.Vector3(-60, 220, 60), // 左上
        new THREE.Vector3(60, 80, -60), // 右中
        new THREE.Vector3(60, 30, -60), // 右下
      ]);
      // 2、extrude settings
      closedSpline.curveType = "catmullrom";
      closedSpline.closed = true;
      const extrudeSettings = {
        steps: 100,
        bevelEnabled: false,
        extrudePath: closedSpline,
      };
      // 3、construct shape
      const r = 20; // 截面半径
      const pts1 = [];
      const count = 3; // 截面的棱边数量
      for (let index = 0; index < count; index++) {
        // index/count 几分之几,2π为周长
        const a = (index / count) * Math.PI * 2;
        pts1.push(new THREE.Vector2(r * Math.cos(a), r * Math.sin(a)));
      }
      const shape1 = new THREE.Shape(pts1);
      // create geometry
      const geometry1 = new THREE.ExtrudeGeometry(shape1, extrudeSettings);
      // create material
      const material1 = new THREE.MeshLambertMaterial({
        color: 0xb00000,
      });
      // assembly meshes
      const mesh1 = new THREE.Mesh(geometry1, material1);
      // add mesh to scene
      scene.add(mesh1);
		//部分省略......
    },
2.2 初始化threeScene
    initThree (ThreeJs) {
      const { scene, camera } = ThreeJs.initThree({ center, axesHelper: true, threeHabit: false });
      this.initLight(scene, camera)
      this.initMeshes(scene);
      this.flyto(scene);
      ThreeJs.loop(function () {
        scene.update();
      })
    },
2.3 效果预览

光线投射
光线投射 图形挤压图形挤压烟花效果
烟花效果

奔跑的士兵
奔跑的士兵

嗯嗯测试了几个功能看了基本上问题不大了,ok先告一段落后期继续优化…

感谢您的阅读,最后附上插件下载与源码地址

  • 插件下载安装
npm install cesium_dev_kit
  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
three.js 是一款使用 JavaScript 编写的 3D 动画库,它能够帮助我们在 web 浏览器上创建交互式的 3D 场景。但是,three.js 并没有默认的地图件。如果我们想在 three.js 中创建地图,我们需要借助其他库或件来实现。 有许多第三方库与 three.js 结合使用以创建地图效果,其中最流行的就是 Mapbox.js、Leaflet.js 和 Cesium.js。这些库对地图数据的加载和渲染进行了封装,使得我们可以轻松地在 three.js 中添加地图效果。 Mapbox.js 是一个强大的地图库,它提供了丰富的地图样式和数据,可以通过 Mapbox API 进行加载和渲染。我们可以使用 Mapbox.js 将地图数据转换为 three.js 可以处理的格式,并在 three.js 场景中显示出来。 Leaflet.js 是另一个常用的地图库,它提供了基础的地图功能和用户交互。我们可以使用 Leaflet.js 来加载和渲染地图数据,并将其转换为 three.js 场景中的对象。 Cesium.js 则是一款专注于地理空间数据可视化的库,它提供了丰富的地理空间数据处理和展示功能。我们可以使用 Cesium.js 将地图数据转换为 three.js 场景中的对象,并在 three.js 中进行可视化展示。 总结来说,虽然 three.js 并没有默认的地图件,但我们可以使用一些第三方库如 Mapbox.js、Leaflet.js 或 Cesium.js 来实现在 three.js 中创建地图的效果。这些库提供了丰富的地图数据和渲染功能,有助于我们在 three.js 中实现出色的地图展示效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奔跑的痕迹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值