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)