three + cesium 深度融合

编程入门 行业动态 更新时间:2024-10-18 02:36:32

three + cesium <a href=https://www.elefans.com/category/jswz/34/1769690.html style=深度融合"/>

three + cesium 深度融合

three + cesium 深度融合

思路是 使用两个dom叠加,three的dom在cesium的dom上, 将three的dom的鼠标事件禁用 pointer-events:none;, three的原点设置为cesium显示的坐标区域的中心点,three的相机同步到cesium的相机位置,操作由cesium反馈到three

html

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

css

#cesiumContainer,
#threeContainer {width: 100%;height: 100%;margin: 0;padding: 0;position: absolute;top: 0;left: 0;
}
#threeContainer {pointer-events: none;
}

javascript

	import * as Cesium from 'cesium';import * as THREE from 'three';const minWGS84 = [115.39, 38.9];const maxWGS84 = [117.39, 40.9];const _3Dobjects = [];let viewer;let three = {scene: null,camera: null,renderer: null,}// 创建cesium 地球function initCesium(){viewer = new Cesium.Viewer('cesiumContainer',{infoBox: false,})// 得到中心点const center = Cesium.Cartesian3.fromDegrees(this.centerWGS84.length > 0 ? this.centerWGS84[0] : (this.minWGS84[0] + this.maxWGS84[0]) / 2,this.centerWGS84.length > 0 ? this.centerWGS84[1] : ((this.minWGS84[1] + this.maxWGS84[1]) / 2) - 1,this.centerHigh);// 相机移动到中心点并设置朝向viewer.camera.flyTo({destination: center,orientation: {heading: Cesium.Math.toRadians(0),pitch: Cesium.Math.toRadians(-60),roll: Cesium.Math.toRadians(0)},duration: 3});}// 创建threefunction initThree(){var fov = 45;var width = window.innerWidth;var height = window.innerHeight;var aspect = width / height;var near = 1;var far = 10 * 1000 * 1000; // needs to be far to support Cesium's world-scale renderingthree.sence = new THREE.Sence();three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);three.renderer = new THREE.WebGLRenderer({alpha: true});document.getElementById('threeContainer').appendChild(three.renderer.domElement)}// 创建three 3d物体function initObject3d(){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(1000, 1000, 1000); // 放大mesh.position.set(0, 0, 500); // 平移let meshGroup = new THREE.Group();meshGroup.add(mesh);// 添加至场景three.scene.add(meshGroup);_3Dobjects.push({threeMesh: meshGroup,minWGS84,maxWGS84})}function loop() {requestAnimationFrame(loop);// cesium渲染renderCesium();// three.js渲染renderThree();}function renderCesium() {cesium.viewer.render();}function renderThree() {// 设置相机跟cesium保持一致three.camera.fov = Cesium.Math.toDegrees(cesium.viewer.camera.frustum.fovy);// 声明一个将cesium框架的cartesian3转换为three.js的vector3(笛卡尔坐标转换为三维向量)let cartToVec = function (cart) {return new THREE.Vector3(cart.x, cart.y, cart.z);};// 将3D的物体通过经纬度转换成对应的位置_3Dobjects.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();//设置查看方向item.threeMesh.lookAt(cartToVec(centerHeight));//设置朝向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,0three.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]);const cesiumContainer = document.getElementById('cesiumContainer');//设置宽高比例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);}

绑定点击事件

// 绑定点击事件
bindClick(viewer,three)
function bindClick(viewer,three){viewer.scene.globe.depthTestAgainstTerrain = true;new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas).setInputAction(function (pick: any) {// 获取cesium中点击的经纬度const res = getCartographic(viewer, pick.position);console.log(res)// 获取cesium中点击的物体const pickObj = viewer.scene.pick(pick.position);console.log(pickObj);// 获取three中点击的坐标和物体const threeRes = getThreeClick(viewer,three,pick.position)console.log(threeRes);if (Cesium.defined(pickObj) && Cesium.defined(pickObj.id)) {if (pickObj.id === selected) return;Cesium.defined(selected) && (selected = void 0);}// 相机移动到cesium点击的图元位置if (Cesium.defined(pickObj) && Cesium.defined(pickObj.primitive) && Cesium.defined(pickObj.id)&& Cesium.defined(pickObj.primitive.getGeometryInstanceAttributes)) {selected = pickObj.id;look = selected.lookviewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(look.center[0], look.center[1], Number(res.split(',')[2]) + 200),orientation: {heading: look.orientation.heading, //旋转角 正东为90°pitch: Cesium.Math.toRadians(look.orientation.pitch), //俯仰角,水平为0°roll: look.orientation.roll     //翻滚角},})const name = typeof (selected) == 'string' ? selected : selected.name;console.log('用于demo的建筑,' + name)} else {Cesium.defined(selected) && (selected = void 0)}},Cesium.ScreenSpaceEventType.LEFT_CLICK)
}// 坐标转换(鼠标坐标转换为经纬度)
function getCartographic(viewer: any, position: any) {const ray: any = viewer.scene.camera.getPickRay(position);let cartesian: any = null;let pickPostion: any = {};const feature = viewer.scene.pick(position);if (viewer.scene.pickPositionSupported && Cesium.defined(feature) && feature.content) {cartesian = viewer.scene.pickPosition(position);} else if (feature instanceof Cesium.Cesium3DTileFeature) {cartesian = viewer.scene.pickPosition(position);} else {// cartesian = viewer.scene.globe.pick(ray, viewer.scene);cartesian = viewer.scene.pickPosition(position);}if (cartesian) {const cartographic = Cesium.Cartographic.fromCartesian(cartesian); // 结果对象中的值将以弧度表示。const longitude = Number(Cesium.Math.toDegrees(cartographic.longitude));const latitude = Number(Cesium.Math.toDegrees(cartographic.latitude));const height = Number(cartographic.height);pickPostion = [longitude.toFixed(6), latitude.toFixed(6), height.toFixed(2)].join(',');}return pickPostion;
}
function getThreeClick(Viewer,three,position) {const raycaster: any = new THREE.Raycaster();const pointer: any = new THREE.Vector2();const cesiumP = Viewer.scene.canvas.getBoundingClientRect()const { width, height, top, left } = three.renderer.domElement.getBoundingClientRect()const offsetx = three.renderer.domElement.offsetLeftconst offsety = three.renderer.domElement.offsetTopconst x = position.x + cesiumP.x - left + offsetx;const y = position.y + cesiumP.y - top + offsety;pointer.x = (x / width) * 2 - 1;pointer.y = - (y / height) * 2 + 1;const clickObjects = three.sence.children;// 通过摄像机和鼠标位置更新射线raycaster.setFromCamera(pointer, three.camera);// 计算物体和射线的焦点const intersects = raycaster.intersectObjects(clickObjects);return intersects[0]
}

更多推荐

three + cesium 深度融合

本文发布于:2024-02-26 21:46:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1704050.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:深度   cesium

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!