Three.js一键构建Google Earth级3D地图,探秘Geo-Three核心特性与实战指南
Geo-Three 是一个基于 Three.js 的 JavaScript 库,专门用于在浏览器中展示 3D 地图。它采用瓦片(Tile)分块机制,能够实现全球尺度的地理数据可视化,并支持地形高度的 3D 几何体生成。
简单来说,Geo-Three 让你能够用 Three.js 轻松构建出类似 Google Earth 的 3D 地图应用。
常用地址
开源项目:https://github.com/tentone/geo-three/
项目文档:https://tentone.github.io/geo-three/docs/
在线示例:https://geo-three.github.io/project/
项目Demo
三维地球:https://tentone.github.io/geo-three/examples/transition.html


核心特性
1. 多地图服务商支持
Geo-Three 内置了对多个主流地图服务商的支持:
- Bing Maps
- Google Maps
- Here Maps
- MapBox
- MapTiler
- OpenMapTiles
- OpenStreetMaps
每个服务商都有对应的 Provider 对象,只需简单配置即可使用。
2. 灵活的地形生成
库支持两种地形生成方式:
- CPU 生成:软件生成地形瓦片,可访问几何体数据,适合需要射线交互的场景
- GPU 置换贴图:使用着色器直接处理高度数据,性能更高、细节更丰富,但不支持射线检测
3. 智能的 LOD 控制
LOD(Level of Detail,细节层次)是 3D 地图性能优化的关键。Geo-Three 提供了多种 LOD 控制策略:
| 模式 | 原理 | 适用场景 |
|---|---|---|
| 射线投射 | 通过射线检测视锥体内的瓦片距离 | 整体性能较快 |
| 径向模式 | 计算所有瓦片到相机的距离 | 效果更平滑一致 |
| 视锥体模式 | 只考虑视锥体内的瓦片 | 性能优化最佳 |
快速上手
安装
npm install three go-three
基础示例
import * as THREE from 'three';
import { MapView, OpenStreetMapsProvider } from 'go-three';
// 创建场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地图瓦片提供器
const provider = new OpenStreetMapsProvider();
// 创建平面地图视图
const map = new MapView(MapView.PLANAR, provider);
scene.add(map);
// 调整缩放(将米转换为千米)
map.scale.set(0.001, 0.001, 0.001);
// 设置相机位置
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 动画循环
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
坐标转换
geo-three 内部使用 EPSG:900913(XY 坐标)格式,与 three.js 的 XYZ 坐标体系兼容。以下是将经纬度转换为 three.js 坐标的方法:
import { Geo } from 'go-three';
// 将 WGS84 经纬度转换为 XY 坐标
const coords = Geo.UnitsUtils.datumsToSpherical(40.940119, -8.535589);
controls.target.set(coords.x, 0, -coords.y);
进阶用法
自定义 LOD 控制
你可以通过扩展 LODControl 类来实现自己的 LOD 逻辑:
import { LODControl, MapNode } from 'go-three';
import { Vector3 } from 'three';
export class DistanceLOD extends LODControl {
updateLOD(view, camera, renderer, scene) {
const pov = new Vector3();
camera.getWorldPosition(pov);
view.traverse(node => {
if (node instanceof MapNode) {
const position = new Vector3();
node.getWorldPosition(position);
let distance = pov.distanceTo(position);
distance /= Math.pow(2, 20 - node.level);
if (distance < 50) {
node.subdivide(); // 近距离细分
} else if (distance > 200 && node.parentNode) {
node.parentNode.simplify(); // 远距离简化
}
}
});
}
}
自定义数据提供器
如果你想接入自己的瓦片数据源,只需扩展 MapProvider 类:
import { MapProvider } from 'go-three';
export class CustomProvider extends MapProvider {
fetchTile(zoom, x, y) {
return new Promise((resolve, reject) => {
const image = document.createElement('img');
image.onload = () => resolve(image);
image.onerror = reject;
image.crossOrigin = 'Anonymous';
image.src = `https://your-tile-server.com/${zoom}/${x}/${y}.png`;
});
}
}
甚至可以用 Canvas 动态生成瓦片:
export class GradientProvider extends MapProvider {
fetchTile(zoom, x, y) {
const canvas = new OffscreenCanvas(256, 256);
const context = canvas.getContext('2d');
const hue = (zoom * 36) % 360;
context.fillStyle = `hsl(${hue}, 100%, 50%)`;
context.fillRect(0, 0, 256, 256);
return Promise.resolve(canvas);
}
}
自定义地图节点
你可以创建自定义的 MapNode 来改变每个瓦片的外观和行为:
import { MapNode, MapNodeGeometry } from 'go-three';
import { SphereGeometry, MeshBasicMaterial, Vector3 } from 'three';
export class CustomMapNode extends MapNode {
static GEOMETRY = new SphereGeometry(0.5, 32, 32);
static MATERIAL = new MeshBasicMaterial();
static BASE_GEOMETRY = new MapNodeGeometry(1, 1, 1, 1);
static BASE_SCALE = new Vector3(40075000, 1, 40075000); // 地球周长
constructor(parentNode, mapView, location, level, x, y) {
super(
CustomMapNode.GEOMETRY,
CustomMapNode.MATERIAL,
parentNode, mapView, location, level, x, y
);
}
initialize() {
// 初始化节点数据
}
createChildNodes() {
// 细分时创建子节点
}
}
平面模式 vs 球面模式
geo-three 支持两种地图投影模式:
| 模式 | 特点 | 注意事项 |
|---|---|---|
| 平面模式 | 适合局部地图、城市规划 | 瓦片为平面矩形 |
| 球面模式 | 适合全球视图、地球仪 | 需要预先调整瓦片,避免极地区域拉伸 |
性能优化建议
- 合理设置 subdivisionRays:每帧用于射线检测的数量,影响 LOD 响应速度
- 调整 thresholdUp/thresholdDown:控制瓦片细分和简化的阈值
- 复用几何体和材质:减少内存占用
- 根据场景选择合适的 LOD 模式:径向模式效果好,视锥体模式性能优
应用场景
- 三维地图导航:结合 GPS 数据,构建沉浸式导航体验
- 地形可视化:展示山脉、峡谷等地理特征
- 数据大屏:在地图上叠加热力图、标记点等
- 游戏地图:为开放世界游戏提供真实世界地图
- 城市规划:展示建筑模型和城市布局
总结
geo-three 是一个功能完善、扩展性强的 3D 地图库。它将 three.js 强大的 3D 渲染能力与成熟的地图瓦片体系相结合,为开发者提供了一个构建 3D 地理应用的坚实基础。
无论你是想快速搭建一个地球仪展示,还是构建复杂的地理数据可视化平台,geo-three 都值得一试。项目采用 MIT 许可证,可免费用于商业项目。