three.js and cesium

本文介绍了将Cesium的行星级渲染和GIS功能与Three.js通用3D API相结合的方法。两者都是用于3D可视化的JavaScript库,有相似之处。文中给出了整合步骤,包括初始化渲染器、3D对象和循环渲染器,并提供了详细的代码示例。

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

Three.js是一个轻量级的跨浏览器JavaScript库,用于在浏览器中创建和显示动画3D计算机图形。将Cesium的行星级渲染和GIS功能与Three.js广泛而易用的通用3D API相结合,为新的WebGL体验开启了许多可能性。3D JavaScript库现在已经完全成熟并且广为人知,使得开发人员可以避免在浏览器中使用3D的麻烦。开发人员可以轻松创建相机,对象,灯光,材质和图形,并选择渲染器,使用HTML 5的画布,WebGL或SVG绘制场景。

因为Cesium和Three.js都是用于3D可视化的,并且是从头开始用JavaScript构建的,所以它们有相似之处,可以将这些惊人的库集成在一起。我对这两个框架进行整合的方法比看起来简单:我将这两个框架分离到了不同的视图中,并参考了HTML Canvas元素,并将它们的控制器组合在同一个坐标系中。由于两者都是开源的,我可以分享这个演示,这将涵盖一些基础知识。

上:Cesium场景。中:Three.js场景。下:组合的场景。

Cesiumjs是一个为了创建数字地球而开发的三维图书馆,其渲染对于真实的地球来说是非常精确的。借助3D Tiles,开发人员可以将几乎所有内容都重新渲染到浏览器中的数字画布上。

指导Cesium的基本渲染原理与Three.js没有太大区别。Three.js是用于渲染3D对象的强大3D库。通过在两个场景中复制铯的球面坐标系和匹配的数字地球,很容易将两个单独的渲染引擎层整合到一个主场景中。我将给出一个关于其整合方法的简单说明,如下所示:

  • 初始化Cesium渲染器,
  • 初始化Three.js渲染器,
  • 初始化这两个库的3D对象,和
  • 循环渲染器。

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Use correct character set. -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>Tools-12CesiumThreejs</title>
    <link href="Tools-12CesiumThreejs.css" rel="stylesheet" type="text/css" media="all">
    <script src="../Cesium/Cesium.js"></script>
    <script src="Libs/Three/three.js"></script>
</head>
<body onload="pageload()">
    <div id="cesiumContainer"></div>
    <div id="ThreeContainer"></div>
    <div id="cover">
        <div id="loadingIndicator" class="loadingIndicator"></div>
    </div>
    <script>
      function pageload() {
          var loadingIndicator = document.getElementById('loadingIndicator');
          loadingIndicator.style.display = 'none';
          // boundaries in WGS84 around the object
          var minWGS84 = [115.23, 39.55];
          var maxWGS84 = [116.23, 41.55];
          var cesiumContainer = document.getElementById("cesiumContainer");
          var ThreeContainer = document.getElementById("ThreeContainer");
          var _3Dobjects = []; //Could be any Three.js object mesh
          var three = {
              renderer: null,
              camera: null,
              scene: null
          };
          var cesium = {
              viewer: null
          };
          function _3DObject() {
              //THREEJS 3DObject.mesh
              this.threeMesh = null;
              //location bounding box
              this.minWGS84 = null;
              this.maxWGS84 = null;
          }
          function initCesium() {
              cesium.viewer = new Cesium.Viewer(cesiumContainer, {
                  useDefaultRenderLoop: false,
                  selectionIndicator: false,
                  homeButton: false,
                  sceneModePicker: false,
                  navigationHelpButton: false,
                  infoBox: false,
                  navigationHelpButton: false,
                  navigationInstructionsInitiallyVisible: false,
                  animation: false,
                  timeline: false,
                  fullscreenButton: false,
                  allowTextureFilterAnisotropic: false,
                  contextOptions: {
                      webgl: {
                          alpha: false,
                          antialias: true,
                          preserveDrawingBuffer: true,
                          failIfMajorPerformanceCaveat: false,
                          depth: true,
                          stencil: false,
                          anialias: false
                      },
                  },
                  targetFrameRate: 60,
                  resolutionScale: 0.1,
                  orderIndependentTranslucency: true,
                  //imageryProvider: undefined,
                  baseLayerPicker: true,
                  geocoder: false,
                  automaticallyTrackDataSourceClocks: false,
                  dataSources: null,
                  clock: null,
                  terrainShadows: Cesium.ShadowMode.DISABLED
              });
              var center = Cesium.Cartesian3.fromDegrees(
                (minWGS84[0] + maxWGS84[0]) / 2,
                ((minWGS84[1] + maxWGS84[1]) / 2) - 1,
                200000
              );
              cesium.viewer.camera.flyTo({
                  destination: center,
                  orientation: {
                      heading: Cesium.Math.toRadians(0),
                      pitch: Cesium.Math.toRadians(-60),
                      roll: Cesium.Math.toRadians(0)
                  },
                  duration: 3
              });
          }
          function initThree() {
              var fov = 45;
              var width = window.innerWidth;
              var height = window.innerHeight;
              var aspect = width / height;
              var near = 1;
              var far = 10 * 1000 * 1000;
              three.scene = new THREE.Scene();
              three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
              three.renderer = new THREE.WebGLRenderer({ alpha: true });
              ThreeContainer.appendChild(three.renderer.domElement);
          }
          function init3DObject() {
              //Cesium entity
              var 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.2)
                  }
              };
              var Polygon = cesium.viewer.entities.add(entity);
              //Three.js Objects
              // Lathe geometry
              var doubleSideMaterial = new THREE.MeshNormalMaterial({
                  side: THREE.DoubleSide
              });
              var segments = 10;
              var points = [];
              for (var i = 0; i < segments; i++) {
                  points.push(new THREE.Vector2(Math.sin(i * 0.2) * segments + 5, (i - 5) * 2));
              }
              var geometry = new THREE.LatheGeometry(points);
              var latheMesh = new THREE.Mesh(geometry, doubleSideMaterial);
              latheMesh.scale.set(1500, 1500, 1500); //scale object to be visible at planet scale
              latheMesh.position.z += 15000.0; // translate "up" in Three.js space so the "bottom" of the mesh is the handle
              latheMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
              var latheMeshYup = new THREE.Group();
              latheMeshYup.add(latheMesh)
              three.scene.add(latheMeshYup); // don’t forget to add it to the Three.js scene manually
              //Assign Three.js object mesh to our object array
              var _3DOB = new _3DObject();
              _3DOB.threeMesh = latheMeshYup;
              _3DOB.minWGS84 = minWGS84;
              _3DOB.maxWGS84 = maxWGS84;
              _3Dobjects.push(_3DOB);
              // dodecahedron
              geometry = new THREE.DodecahedronGeometry();
              var dodecahedronMesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
              dodecahedronMesh.scale.set(5000, 5000, 5000); //scale object to be visible at planet scale
              dodecahedronMesh.position.z += 15000.0; // translate "up" in Three.js space so the "bottom" of the mesh is the handle
              dodecahedronMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
              var dodecahedronMeshYup = new THREE.Group();
              dodecahedronMeshYup.add(dodecahedronMesh)
              three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
              //Assign Three.js object mesh to our object array
              _3DOB = new _3DObject();
              _3DOB.threeMesh = dodecahedronMeshYup;
              _3DOB.minWGS84 = minWGS84;
              _3DOB.maxWGS84 = maxWGS84;
              _3Dobjects.push(_3DOB);
          }
          // Looping Renderer
          function renderCesium() {
              cesium.viewer.render();
          }
          function renderThreeObj() {
              // register Three.js scene with Cesium
              three.camera.fov = Cesium.Math.toDegrees(cesium.viewer.camera.frustum.fovy) // ThreeJS FOV is vertical
              three.camera.updateProjectionMatrix();
              var cartToVec = function (cart) {
                  return new THREE.Vector3(cart.x, cart.y, cart.z);
              };
              // Configure Three.js meshes to stand against globe center position up direction
              for (var id in _3Dobjects) {
                  minWGS84 = _3Dobjects[id].minWGS84;
                  maxWGS84 = _3Dobjects[id].maxWGS84;
                  // convert lat/long center position to Cartesian3
                  var center = Cesium.Cartesian3.fromDegrees((minWGS84[0] + maxWGS84[0]) / 2, (minWGS84[1] + maxWGS84[1]) / 2);
                  // get forward direction for orienting model
                  var centerHigh = Cesium.Cartesian3.fromDegrees((minWGS84[0] + maxWGS84[0]) / 2, (minWGS84[1] + maxWGS84[1]) / 2, 1);
                  // use direction from bottom left to top left as up-vector
                  var bottomLeft = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], minWGS84[1]));
                  var topLeft = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1]));
                  var latDir = new THREE.Vector3().subVectors(bottomLeft, topLeft).normalize();
                  // configure entity position and orientation
                  _3Dobjects[id].threeMesh.position.copy(center);
                  _3Dobjects[id].threeMesh.lookAt(centerHigh);
                  _3Dobjects[id].threeMesh.up.copy(latDir);
              }
              // Clone Cesium Camera projection position so the
              // Three.js Object will appear to be at the same place as above the Cesium Globe
              three.camera.matrixAutoUpdate = false;
              var cvm = cesium.viewer.camera.viewMatrix;
              var civm = cesium.viewer.camera.inverseViewMatrix;
              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]
              );
              three.camera.lookAt(new THREE.Vector3(0, 0, 0));
              var width = ThreeContainer.clientWidth;
              var height = ThreeContainer.clientHeight;
              var aspect = width / height;
              three.camera.aspect = aspect;
              three.camera.updateProjectionMatrix();
              three.renderer.setSize(width, height);
              three.renderer.render(three.scene, three.camera);
          }
          function loop() {
              requestAnimationFrame(loop);
              renderCesium();
              renderThreeObj();
          }
          initCesium(); // Initialize Cesium renderer
          initThree(); // Initialize Three.js renderer
          init3DObject(); // Initialize Three.js object mesh with Cesium Cartesian coordinate system
          loop(); // Looping renderer
      }
    </script>
</body>
</html>

感兴趣的可以留言或发邮件1985692469@qq.com,欢迎一起探讨!

### 集成 Three.js Cesium 进行 WebGL 渲染 为了使 Three.jsCesium 能够协同工作,在同一页面上创建复杂的三维场景,可以采取以下方法: #### 设置环境 确保两个库都已加载并初始化。通常情况下,先启动 Cesium Viewer 或 Scene,再在其之上叠加 Three.js 场景。 #### 同步摄像机视角 通过克隆 Cesium 的相机参数至 Three.js 中对应的 Camera 对象属性上来维持两者之间的同步[^1]。此过程涉及定期更新位置、方向以及视场角等重要参数,从而保证无论哪个平台发生改变都能反映到另一个平台上。 #### 处理用户输入冲突 为了避免鼠标操作干扰到位于顶层的 Three.js Canvas,可通过应用 `pointer-events:none` 样式规则于该元素之上,使得所有的指针事件能够穿透它直达下层组件即 Cesium viewer。 ```css /* 应用于 Three.js canvas */ #threeCanvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; /* 关键样式 */ } ``` #### 示例代码片段展示如何实现上述功能 下面是一个简单的例子说明怎样在一个 HTML 文件里同时运行这两个框架,并让它们共享相同的视觉空间而不互相妨碍。 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>Integrating Three.js and Cesium</title> <!-- 加载必要的资源 --> <script src="https://cesium.com/downloads/cesiumjs/releases/1.87/Build/Cesium/Cesium.js"></script> <link href="https://cesium.com/downloads/cesiumjs/releases/1.87/Build/Cesium/Widgets/widgets.css" rel="stylesheet"/> <script type="module" src="https://unpkg.com/three@0.140.0/build/three.module.js"></script> <style> body, html { margin: 0; padding: 0; overflow: hidden } #appContainer { position:relative; width:100vw; height:100vh; } #cesiumContainer{ width:100%; height:100%; } #threeCanvas { position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; } </style> </head> <body> <div id="appContainer"> <!-- 容纳 Cesium 地图 --> <div id="cesiumContainer"></div> <!-- Three.js 使用同一个容器绘制额外图形 --> <canvas id="threeCanvas"></canvas> </div> <script> // 初始化 Cesium 并获取其相机实例... const cesiumViewer = new Cesium.Viewer('cesiumContainer'); let cesiumCamera = cesiumViewer.scene.camera; // 创建 Three.js scene/renderer/camera ... var threeScene = new THREE.Scene(); var threeRenderer = new THREE.WebGLRenderer({ antialias:true }); document.getElementById('threeCanvas').appendChild(threeRenderer.domElement); var threeCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); function syncCameras() { // 更新 Three.js camera 参数以匹配 Cesium's current state. let pos = cesiumCamera.positionCartesian; threeCamera.position.set(pos.x,pos.y,pos.z); threeCamera.lookAt(new THREE.Vector3(cesiumCamera.directionWC.x, cesiumCamera.directionWC.y, cesiumCamera.directionWC.z)); } // 动态调整大小时重新计算宽高比 window.addEventListener('resize', () => { const aspectRatio = window.innerWidth / window.innerHeight; cesiumViewer.container.style.width = `${window.innerWidth}px`; cesiumViewer.container.style.height = `${window.innerHeight}px`; threeRenderer.setSize(window.innerWidth, window.innerHeight); threeCamera.aspect = aspectRatio; threeCamera.updateProjectionMatrix(); }, false); // 每帧调用一次来保持两者的同步状态 function animate() { requestAnimationFrame(animate); syncCameras(); // Keep cameras synchronized // Render both scenes here... cesiumViewer.render(); threeRenderer.render(threeScene, threeCamera); } animate(); </script> </body> </html> ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值