我是靠谱客的博主 文静仙人掌,最近开发中收集的这篇文章主要介绍three + cesium 深度融合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
        });
	}
	// 创建three
    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; // needs to be far to support Cesium's world-scale rendering
	   	three.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,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]
		);
		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.look
		    viewer.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.offsetLeft
    const offsety = three.renderer.domElement.offsetTop
    const 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 深度融合three + cesium 深度融合的全部内容,希望文章能够帮你解决three + cesium 深度融合three + cesium 深度融合所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部