Threejs实现绘制地球,地理位置标注、经纬度转换世界坐标threejs坐标

1,介绍

该示例使用的是 r95版本Three.js库。

主要实现功能:绘制地球和地理位置进行标注 

效果图如下: 

2,主要说明 

准备一张地图,创建一个球体并进行贴图,把地理位置经纬度转换成threejs的世界坐标,并进行标注。

创建地球,部分代码如下:

// 创建地球 半径100
function createEarth() {
	var earthGeo = new THREE.SphereGeometry(radius, 50, 50);
	var earthMater = new THREE.MeshPhongMaterial({
		map: new THREE.TextureLoader().load('assets/earth/earth3.jpg'),
		transparent: true,
		depthWrite: false,
		side: THREE.DoubleSide,
		blending: THREE.AdditiveBlending,
		opacity: 0.8,
		color: 0x03d98e
	});
	var earthMesh = new THREE.Mesh(earthGeo, earthMater);
	scene.add(earthMesh)
}

经纬度转换成threejs坐标(也叫右手坐标系) 

图片描述

 phi是方位面(水平面)内的角度,范围0~360度,theta是俯仰面(竖直面)内的角度,范围0~180度、就是空间极坐标系中的两个参数,和类比直角坐标系里的xyz

threejs实现转换,代码如下:

// 坐标转换,
function createPosition(lnglat) {
	let spherical = new THREE.Spherical
	spherical.radius = radius;
	const lng = lnglat[0]
	const lat = lnglat[1]
	const theta = (lng + 90) * (Math.PI / 180)
	const phi = (90 - lat) * (Math.PI / 180)
	spherical.phi = phi; // phi是方位面(水平面)内的角度,范围0~360度
	spherical.theta = theta; // theta是俯仰面(竖直面)内的角度,范围0~180度
	let position = new THREE.Vector3()
	position.setFromSpherical(spherical)
	return position
}

 3,源码

<!DOCTYPE html>
<html>
	<head>
		<title>Threejs实现绘制地球,地理位置标注-经纬度转换世界坐标</title>
		<script type="text/javascript" src="libs/three.js"></script>
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<div id="dom"></div>
		<script type="text/javascript">
			var camera;
			var renderer;
			var radius = 100; // 地球半径
			var areas = [{
				name: "中国",
				position: [116.20, 39.55]
			}, {
				name: "中非共和国",
				position: [18.35, 4.23]
			}, {
				name: "智利",
				position: [-70.40, -33.24]
			}, {
				name: "乍得",
				position: [14.59, 12.10]
			}, {
				name: "赞比亚",
				position: [28.16, -15.28]
			}, {
				name: "越南",
				position: [105.55, 21.05]
			}, {
				name: "约旦",
				position: [35.52, 31.57]
			}, {
				name: "英属维尔京群岛",
				position: [-64.37, 18.27]
			}, {
				name: "英国",
				position: [-0.05, 51.36]
			}];

			function init() {
				// 创建一个场景,它将包含我们所有的元素,如物体,相机和灯光。
				var scene = new THREE.Scene();

				var urls = [
					'assets/textures/cubemap/flowers/posx.jpg',
					'assets/textures/cubemap/flowers/negx.jpg',
					'assets/textures/cubemap/flowers/posy.jpg',
					'assets/textures/cubemap/flowers/negy.jpg',
					'assets/textures/cubemap/flowers/posz.jpg',
					'assets/textures/cubemap/flowers/negz.jpg'
				];

				var cubeLoader = new THREE.CubeTextureLoader();
				// scene.background = cubeLoader.load(urls);

				// 创建一个摄像机,它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
				// 将摄像机对准场景的中心
				camera.position.z = 500;
				camera.lookAt(scene.position);
				var orbit = new THREE.OrbitControls(camera);

				// 创建一个渲染器并设置大小,WebGLRenderer将会使用电脑显卡来渲染场景
				renderer = new THREE.WebGLRenderer({
					antialias: true,
					logarithmicDepthBuffer: true,
				});
				renderer.setSize(window.innerWidth, window.innerHeight);
				// scene.add(new THREE.AmbientLight(0x666666));

				var ambientLight = new THREE.AmbientLight("#ffffff", 1);
				scene.add(ambientLight);

				// 在屏幕上显示坐标轴
				var axes = new THREE.AxisHelper(radius);
				scene.add(axes);

				// 将平面添加到场景中
				var plane = createPlaneGeometryBasicMaterial();
				// scene.add(plane);

				// initSphere(10, 0, 10);
				createEarth();
				createAreaPoint();

				var rs = coordinateWorldTurnScreen(10, 0, 10);
				var div = document.createElement('div');
				div.innerHTML = '立';
				div.style.padding = '5px';
				div.style.position = 'absolute';
				div.style.backgroundColor = 'rgba(155,0,155,0.8)';
				document.body.appendChild(div);
				div.style.left = rs.x + "px";
				div.style.top = rs.y + "px";
				console.log(rs)

				// 将呈现器的输出添加到HTML元素
				document.getElementById("dom").appendChild(renderer.domElement);

				// 启动动画
				renderScene();

				/**
				 * 创建地面并添加材质
				 * wrapS属性定义的是纹理沿x轴方向的行为,而warpT属性定义的是纹理沿y轴方向的行为。
				 * Three.js为这些属性提供了如下两个选项:
				 * ·THREE.RepeatWrapping允许纹理重复自己。
				 * ·THREE.ClampToEdgeWrapping是属性的默认值。
				 * 属性值为THREE.ClampToEdgeWrapping时,那么纹理的整体不会重复,只会重复纹理边缘的像素来填满剩下的空间。
				 */
				function createPlaneGeometryBasicMaterial() {
					var textureLoader = new THREE.TextureLoader();
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/stone/cd.jpg"),
					});
					cubeMaterial.map.wrapS = THREE.RepeatWrapping;
					cubeMaterial.map.wrapT = THREE.RepeatWrapping;
					cubeMaterial.map.repeat.set(8, 8)
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(100, 100);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);

					// 设置平面位置并旋转
					plane.rotation.x = -0.5 * Math.PI;
					plane.position.x = 0;
					plane.position.z = 0;
					return plane;
				}

				// 世界坐标转屏幕坐标
				function coordinateWorldTurnScreen(x, y, z) {
					let world_vector = new THREE.Vector3(x, y, z);
					let vector = world_vector.project(camera);
					let halfWidth = window.innerWidth / 2,
						halfHeight = window.innerHeight / 2;
					return {
						x: Math.round(vector.x * halfWidth + halfWidth),
						y: Math.round(-vector.y * halfHeight + halfHeight)
					}
				}

				// 创建地球 半径100
				function createEarth() {
					var earthGeo = new THREE.SphereGeometry(radius, 50, 50);
					var earthMater = new THREE.MeshPhongMaterial({
						map: new THREE.TextureLoader().load('assets/earth/earth3.jpg'),
						transparent: true,
						depthWrite: false,
						side: THREE.DoubleSide,
						blending: THREE.AdditiveBlending,
						opacity: 0.8,
						color: 0x03d98e
					});
					var earthMesh = new THREE.Mesh(earthGeo, earthMater);
					scene.add(earthMesh)
				}

				function createAreaPoint() {
					// 球面
					let sphereGeom = new THREE.SphereGeometry(1, 20, 20),
						sphereMat = new THREE.MeshBasicMaterial({
							color: 0x03d98e,
							wireframe: true
						})
					let sphere = new THREE.Mesh(sphereGeom, sphereMat)
					scene.add(sphere)
					// 地标及光锥
					for (let i = 0, length = areas.length; i < length; i++) {
						const position = createPosition(this.areas[i].position)
						createHexagon(position); // 地标
					}
				}

				// 坐标转换,
				function createPosition(lnglat) {
					let spherical = new THREE.Spherical
					spherical.radius = radius;
					const lng = lnglat[0]
					const lat = lnglat[1]
					const theta = (lng + 90) * (Math.PI / 180)
					const phi = (90 - lat) * (Math.PI / 180)
					spherical.phi = phi; // phi是方位面(水平面)内的角度,范围0~360度
					spherical.theta = theta; // theta是俯仰面(竖直面)内的角度,范围0~180度
					let position = new THREE.Vector3()
					position.setFromSpherical(spherical)
					return position
				}

				// 创建地标标记
				function createHexagon(position) {
					var hexagon = new THREE.Object3D()
					let hexagonLine = new THREE.CircleGeometry(4, 6)
					let hexagonPlane = new THREE.CircleGeometry(3, 6)
					let vertices = hexagonLine.vertices
					vertices.shift() // 第一个节点是中心点
					let material = new THREE.MeshBasicMaterial({
						color: 0xffff00,
						side: THREE.DoubleSide,
						opacity: 0.5
					})
					let circleLine = new THREE.LineLoop(hexagonLine, material)
					let circlePlane = new THREE.Mesh(hexagonPlane, material)
					circleLine.position.copy(position)
					circlePlane.position.copy(position)
					circlePlane.lookAt(new THREE.Vector3(0, 0, 0))
					circleLine.lookAt(new THREE.Vector3(0, 0, 0))

					hexagon.add(circleLine)
					hexagon.add(circlePlane)
					scene.add(hexagon);
				}

				// 初始球体
				function initSphere(x, y, z) {
					var geometry = new THREE.SphereGeometry(1, 100, 100); //球体几何
					var material = new THREE.MeshBasicMaterial({
						color: 0xffff00
					}); //网格基础材料

					var sphere = new THREE.Mesh(geometry, material);
					sphere.position.x = x;
					sphere.position.y = y;
					sphere.position.z = z;
					scene.add(sphere);
				}

				function renderScene() {
					orbit.update();
					// 使用requestAnimationFrame函数进行渲染
					requestAnimationFrame(renderScene);
					renderer.render(scene, camera);
				}

				// 渲染的场景
				renderer.render(scene, camera);
			}
			window.onload = init;

			// 随着窗体的变化修改场景
			function onResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听窗体调整大小事件
			window.addEventListener('resize', onResize, false);
		</script>
	</body>
</html>

在线预览:左本的博客 (zuoben.top)

  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Mapbox 经纬度转换是指将一个地点的经纬度坐标转换为地图坐标,或者将地图坐标转换经纬度坐标。Mapbox 是一家提供地图数据、地图开发和地图相关服务的公司,它的经纬度转换功能可以帮助开发者在地图上准确定位和标注地点。 要实现经纬度转换,可以使用 Mapbox 提供的 API 或者 SDK 进行调用。首先需要获取一个 Mapbox Access Token,以便进行 API 调用。接下来可以使用 API 的转换接口,将经纬度坐标转换为地图坐标或者将地图坐标转换经纬度坐标。 在经纬度转换方面,有几个常见的用途: 1. 在地图上标注和定位地点:通过将获取到的经纬度坐标转换为地图坐标,可以在地图上标注和定位具体的地点。例如,可以将一个地址的经纬度转换为地图坐标,并在地图上显示出来。 2. 路径规划和导航:通过将一系列地点的经纬度坐标转换为地图坐标,可以在地图上绘制路径并进行导航。例如,将起点和终点的经纬度转换为地图坐标,然后使用地图导航功能指导用户沿着最佳路径到达目的地。 3. 地理数据分析和可视化:通过将经纬度坐标转换为地图坐标,可以将地理数据与地图进行关联和可视化。例如,将不同地区的经纬度坐标转换为地图坐标,并在地图上使用不同的颜色或标记来表示不同地区的特征或属性。 总之,Mapbox 经纬度转换是一个方便实用的功能,可以帮助开发者在地图开发和应用中更好地处理和展示地理位置信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

左本Web3D

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

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

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

打赏作者

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

抵扣说明:

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

余额充值