最新版cesium集成threejs

2023年4月19日更新—搞了一个 Cesium 镜像,欢迎使用:沙盒示例API

简介

之前三维加载模型都是加载 glb 或者 gltf,模型不好找,一般需要定制,因此领导想加载 threejs的模型。

按照官方示例(吐槽:2017年的示例 ,代码存在诸多问题,而且版本太老)。

官方地址Integrating Cesium with Three.js

githup地址cesium-threejs-experiment

尝试了很多遍,无法加载模型;githup项目无法运行。

后来在搜索到一篇博客,修改之后可以显示模型,但是模型没有添加到cesium地球中,是分离的,经过修改,完成地球加载three模型,并且同步。

完整代码

基本上是参照官方示例,和大神博客来完成的。自己修改部分主要是:

cesium初始化增加底图、three初始化修改容器
同步cesium画布和three画布位置,画布叠加在一起
解决cesium初始化找不到容器的问题
增加立方体模型

使用版本

cesium 1.88 (目前最新版)
thee.js r135(目前最新版)
在这里插入图片描述
---------------------------------------------------------------------------------------------------------------------------
在这里插入图片描述

html 代码

<!DOCTYPE html>
<html lang="en">
<head>
	<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>Cesium integrate Threejs</title>
	<!--cesium样式-->
	<link rel="stylesheet" href="./Widgets/widgets.css">
	<!--cesium-->
	<script src="./Cesium.js"></script>
	<!--three-->
	<script src="./threejs/three.js"></script>
    <style>
		/*设置cesium和three的画布位置*/
        .container-integrate canvas {
            position: absolute;
            top: 0;
        }
		/*three画布禁止鼠标操作*/
        .container-integrate canvas:nth-child(3) {
            pointer-events: none;

        }
    </style>
</head>

<body onload="pageload()">

<div class="container-integrate" style="">
	<!--cesium容器-->
    <div id="cesiumContainer" style="height: 800px;width: 100%;"></div>
</div>

JavaScript代码


// three对象
let three = {
    renderer: null,
    camera: null,
    scene: null
};

//cesium对象
let cesium = {
    viewer: null
};

function pageload() {

    // 模型定位范围
    let minWGS84 = [115.56936458615716, 39.284100766866445];
    let maxWGS84 = [117.10745052365716, 41.107831235616445];

    // cesium 容器
    let cesiumContainer = document.getElementById("cesiumContainer");
    let _3Dobjects = []; //Could be any Three.js object mesh

    // three对象
    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,
            infoBox: false,
            navigationHelpButton: false,
            navigationInstructionsInitiallyVisible: false,
            animation: false,
            timeline: false,
            fullscreenButton: false,
            allowTextureFilterAnisotropic: false,
            baseLayerPicker: 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: new Cesium.ArcGisMapServerImageryProvider({
                url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
            }),
            geocoder: false,
            automaticallyTrackDataSourceClocks: false,
            // creditContainer : "hidecredit", //注意:这里需要注释掉,否则会报找不到容器的问题
            dataSources: null,
            clock: null,
            terrainShadows: Cesium.ShadowMode.DISABLED
        });
        let 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
        });
    }

    //初始化three
    function initThree() {
        let fov = 45;
        let width = window.innerWidth;
        let height = window.innerHeight;
        let aspect = width / height;
        let near = 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({alpha: true});
        let Amlight = new THREE.AmbientLight(0xffffff, 2);
        three.scene.add(Amlight);
        // 注意这里,直接把three容器(canvas 添加到 cesium中,在cesium的canvas之下),
        // 这样的话,两个canvas才会重叠起来。
        cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(three.renderer.domElement);
        // ThreeContainer.appendChild(three.renderer.domElement);
    }

    //创建 cesium 图形,跟three无关
    function createPolygon() {
        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.BLUE.withAlpha(0.4)
            }
        };
        let Polygon = cesium.viewer.entities.add(entity);
    }

    // 加载three模型
    function getModel(geometry) {
        geometry = new THREE.DodecahedronGeometry();
        const material = new THREE.MeshBasicMaterial({color: 0x0000ff});
        let dodecahedronMesh = new THREE.Mesh(geometry, material);
        // let 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 += 25000.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
        let 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
        let _3DOB = new _3DObject();
        _3DOB.threeMesh = dodecahedronMeshYup;
        _3DOB.minWGS84 = minWGS84;
        _3DOB.maxWGS84 = maxWGS84;
        _3Dobjects.push(_3DOB);
    }

    // 加载three立方体模型
    function cube() {
        const geometry = new THREE.BoxGeometry();
        const material = new THREE.MeshBasicMaterial({color: 0x00ff00});
        const dodecahedronMesh = new THREE.Mesh(geometry, material);
        dodecahedronMesh.scale.set(15000, 15000, 15000); //scale object to be visible at planet scale
        dodecahedronMesh.position.z += 7000.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
        let 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
        let _3DOB = new _3DObject();
        _3DOB.threeMesh = dodecahedronMeshYup;
        _3DOB.minWGS84 = minWGS84;
        _3DOB.maxWGS84 = maxWGS84;
        _3Dobjects.push(_3DOB);
    }

    // 创建three 对象
    function createThreeObject() {
        getModel();
        cube();
    }

    // 初始化模型
    function init3DObject() {
        //Cesium entity
        createPolygon()
        //Three.js Objects
        createThreeObject()
    }

    // cesium 渲染
    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();
        let 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 (let id in _3Dobjects) {
            minWGS84 = _3Dobjects[id].minWGS84;
            maxWGS84 = _3Dobjects[id].maxWGS84;
            // convert lat/long center position to Cartesian3
            let center = Cesium.Cartesian3.fromDegrees((minWGS84[0] + maxWGS84[0]) / 2, (minWGS84[1] + maxWGS84[1]) / 2);
            // get forward direction for orienting model
            let 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
            let bottomLeft = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], minWGS84[1]));
            let topLeft = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1]));
            let latDir = new THREE.Vector3().subVectors(bottomLeft, topLeft).normalize();
            // configure entity position and orientation
            _3Dobjects[id].threeMesh.position.copy(center);
            _3Dobjects[id].threeMesh.lookAt(centerHigh.x, centerHigh.y, centerHigh.z);
            _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;
        let cvm = cesium.viewer.camera.viewMatrix;
        let civm = cesium.viewer.camera.inverseViewMatrix;

        // 注意这里,经大神博客得知,three高版本这行代码需要放在 three.camera.matrixWorld 之前
        three.camera.lookAt(0, 0, 0);

        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宽高
        let width = cesiumContainer.clientWidth;
        let height = cesiumContainer.clientHeight;

        let aspect = width / height;
        three.camera.aspect = aspect;
        three.camera.updateProjectionMatrix();
        three.renderer.setSize(width, height);
        three.renderer.clear();
        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
}

实现效果

在这里插入图片描述

项目在线示例

在线示例,可以直接扒代码在本地运行

嫌麻烦可以直接下载源码: 项目源码

参考博客:

cesium与three.js 结合的栗子,结合了一下网友们的栗子,解决了three.js 高版本模型出不来的问题
cesium+threejs结合实现GIS+BIM大场景-2

  • 18
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
CesiumThree.js是两种流行的3D图形库,它们可以结合使用来加载和渲染3D Tile数据。 首先,我们需要了解3D Tile是什么。3D Tile是一种开放标准的3D地理空间数据格式,它使用了网格化的数据结构,可以将大规模的地理空间数据以图块(Tiles)的形式进行存储、传输和渲染。它支持以地理坐标系为基础的渲染和空间分析,可以用于展示城市模型、地形数据、空间环境等。 要在Cesium中加载和渲染3D Tile数据,我们可以使用Cesium的Tileset类。Tileset类能够处理3D Tile数据集,并根据视口和细节级别动态加载和渲染图块。我们可以使用Cesium的Viewer类创建一个窗口,然后使用Tileset类加载3D Tile数据集,调用其show方法将其显示在场景中。 而要结合Three.js来进行渲染,我们可以通过Cesium提供的API将3D Tile数据转换为Three.js可识别的模型格式,如glTF或Collada。然后,我们可以使用Three.js的Loader类加载这些模型,并通过设置材质、光照等参数来实现渲染效果。最后,我们可以将加载后的模型添加到Three.js的场景中,与其他Three.js的元素一起进行渲染和交互操作。 总而言之,结合CesiumThree.js来加载和渲染3D Tile数据,可以借助Cesium的Tileset类加载和管理3D Tile数据集,然后将其转换为Three.js可识别的模型格式,使用Three.js的Loader类加载并进行渲染,最后将加载后的模型添加到Three.js的场景中进行展示。这样,我们可以充分利用CesiumThree.js的优势,实现更加丰富和高效的3D地理空间数据的加载和渲染。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

非科班Java出身GISer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值