基于 Three.js 的 3D 地球可视化项目
基于 Three.js 的 3D 地球可视化项目 项目说明这是一个使用 Three.js 创建的交互式 3D 地球模型支持鼠标拖动旋转、自动旋转动画和响应式布局。 更新时间2026 年 3 月 24 日 技术栈HTML5 CSS3 JavaScript Three.js⏱️ 预计阅读时间20-30 分钟✍️ 作者书到用时方恨少! 完整目录┌─────────────────────────────────────────────────────────────┐ │ 本篇博客内容导航 │ ├─────────────────────────────────────────────────────────────┤ │ 第一部分项目介绍 │ │ ├── 1. 项目背景 │ │ ├── 2. 效果预览 │ │ └── 3. 功能特性 │ ├─────────────────────────────────────────────────────────────┤ │ 第二部分技术架构 │ │ ├── 4. 技术栈说明 │ │ ├── 5. 项目结构 │ │ └── 6. 核心原理 │ ├─────────────────────────────────────────────────────────────┤ │ 第三部分代码详解 │ │ ├── 7. HTML 结构 │ │ ├── 8. CSS 样式 │ │ └── 9. JavaScript 核心代码 │ ├─────────────────────────────────────────────────────────────┤ │ 第四部分核心功能讲解 │ │ ├── 10. Three.js 场景搭建 │ │ ├── 11. 地球材质与纹理 │ │ ├── 12. 灯光系统 │ │ ├── 13. 鼠标交互控制 │ │ └── 14. 动画循环 │ ├─────────────────────────────────────────────────────────────┤ │ 第五部分扩展与优化 │ │ ├── 15. 功能扩展建议 │ │ ├── 16. 性能优化 │ │ └── 17. 常见问题 │ └─────────────────────────────────────────────────────────────┘第一部分项目介绍1. 项目背景在 Web 3D 可视化日益普及的今天Three.js 成为了前端开发者创建 3D 内容的首选库。本项目通过创建一个交互式 3D 地球模型帮助开发者快速掌握 Three.js 的核心概念包括场景搭建、几何体、材质、纹理、灯光、交互控制和动画循环。┌─────────────────────────────────────────────────────────────┐ │ 项目应用场景 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 数据可视化 │ │ • 全球业务分布展示 │ │ • 用户地理位置可视化 │ │ • 网络流量监控 │ │ │ │ 教育演示 │ │ • 地理教学辅助 │ │ • 天文科普展示 │ │ • 互动学习平台 │ │ │ │ 创意展示 │ │ • 企业官网首页 │ │ • 产品介绍页面 │ │ • 个人作品集 │ │ │ └─────────────────────────────────────────────────────────────┘2. 效果预览️ 项目效果 交互特性交互方式效果鼠标拖动地球跟随鼠标旋转鼠标释放恢复自动旋转窗口缩放自适应调整大小右键菜单禁用防止干扰3. 功能特性┌─────────────────────────────────────────────────────────────┐ │ 核心功能清单 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ✅ 3D 地球渲染 │ │ • 高精度球体几何体64×64 分段 │ │ • 多层纹理贴图颜色/法线/高光 │ │ • Phong 材质光照效果 │ │ │ │ ✅ 交互控制 │ │ • 鼠标拖动旋转 │ │ • 平滑旋转动画 │ │ • 禁用右键菜单 │ │ │ │ ✅ 自适应布局 │ │ • 响应式窗口大小 │ │ • 设备像素比适配 │ │ • 全屏显示 │ │ │ │ ✅ 灯光系统 │ │ • 环境光基础照明 │ │ • 方向光模拟太阳 │ │ │ └─────────────────────────────────────────────────────────────┘第二部分技术架构4. 技术栈说明️ 核心技术技术版本用途HTML5-页面结构CSS3-样式布局JavaScriptES6交互逻辑Three.jsr1283D 渲染引擎 Three.js 核心模块┌─────────────────────────────────────────────────────────────┐ │ Three.js 模块使用 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ THREE.Scene → 3D 场景容器 │ │ THREE.PerspectiveCamera → 透视相机 │ │ THREE.WebGLRenderer → WebGL 渲染器 │ │ THREE.SphereGeometry → 球体几何体 │ │ THREE.TextureLoader → 纹理加载器 │ │ THREE.MeshPhongMaterial → Phong 材质 │ │ THREE.Mesh → 网格对象 │ │ THREE.AmbientLight → 环境光 │ │ THREE.DirectionalLight → 方向光 │ │ │ └─────────────────────────────────────────────────────────────┘5. 项目结构project/ │ ├── index.html # 主页面包含所有代码 │ ├── 纹理资源CDN 加载 │ ├── earth_atmos_2048.jpg # 地球颜色纹理 │ ├── earth_normal_2048.jpg # 法线贴图 │ └── earth_specular_2048.jpg # 高光贴图 │ └── 依赖库CDN 加载 └── three.min.js (r128) # Three.js 核心库 说明本项目采用单文件结构所有代码集成在index.html中便于快速部署和测试。纹理和库文件通过 CDN 加载。6. 核心原理 渲染流程┌─────────────────────────────────────────────────────────────┐ │ Three.js 渲染流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. 创建场景 (Scene) │ │ ↓ │ │ 2. 创建相机 (Camera) │ │ ↓ │ │ 3. 创建渲染器 (Renderer) │ │ ↓ │ │ 4. 添加几何体 材质 网格 (Mesh) │ │ ↓ │ │ 5. 添加灯光 (Light) │ │ ↓ │ │ 6. 动画循环 (requestAnimationFrame) │ │ ↓ │ │ 7. 渲染场景 (renderer.render) │ │ │ └─────────────────────────────────────────────────────────────┘ 交互原理┌─────────────────────────────────────────────────────────────┐ │ 鼠标交互原理 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ mousedown → 记录起始位置 → isDragging true │ │ ↓ │ │ mousemove → 计算位移差 → 更新旋转角度 │ │ ↓ │ │ mouseup → isDragging false → 恢复自动旋转 │ │ │ └─────────────────────────────────────────────────────────────┘第三部分代码详解7. HTML 结构!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title3D 地球模型/title !-- CSS 样式 -- /head body div idinstructions拖动地球旋转 | Drag to rotate the Earth/div div idcontainer/div !-- 引入 Three.js -- script srchttps://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js/script !-- JavaScript 代码 -- /body /html 关键元素说明元素作用meta viewport移动端适配#instructions操作提示文字#containerThree.js 渲染容器script引入 Three.js 库8. CSS 样式body { margin: 0; overflow: hidden; background-color: #000000; font-family: Arial, sans-serif; } #container { width: 100%; height: 100vh; display: block; } #instructions { position: absolute; top: 20px; left: 0; width: 100%; text-align: center; color: white; font-size: 14px; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8); pointer-events: none; /* 不阻挡鼠标事件 */ z-index: 10; } 样式要点┌─────────────────────────────────────────────────────────────┐ │ CSS 样式要点 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ✅ margin: 0 │ │ 移除默认边距实现全屏效果 │ │ │ │ ✅ overflow: hidden │ │ 隐藏滚动条防止拖动时页面滚动 │ │ │ │ ✅ pointer-events: none │ │ 提示文字不阻挡鼠标事件确保能拖动地球 │ │ │ │ ✅ text-shadow │ │ 文字阴影增强在黑色背景上的可读性 │ │ │ └─────────────────────────────────────────────────────────────┘9. JavaScript 核心代码 代码结构概览// 1. 场景设置 const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(...); const renderer new THREE.WebGLRenderer(...); // 2. 地球创建 const geometry new THREE.SphereGeometry(...); const material new THREE.MeshPhongMaterial({...}); const earth new THREE.Mesh(geometry, material); // 3. 灯光系统 const ambientLight new THREE.AmbientLight(...); const directionalLight new THREE.DirectionalLight(...); // 4. 交互控制 // 鼠标事件监听函数... // 5. 动画循环 function animate() { ... }第四部分核心功能讲解10. Three.js 场景搭建 场景、相机、渲染器// 场景设置 const scene new THREE.Scene(); // 相机透视相机 const camera new THREE.PerspectiveCamera( 75, // 视野角度 (FOV) window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近截面 1000 // 远截面 ); camera.position.z 2; // 相机位置 // 渲染器 const renderer new THREE.WebGLRenderer({ antialias: true // 开启抗锯齿 }); renderer.setPixelRatio(window.devicePixelRatio); // 设备像素比 renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById(container).appendChild(renderer.domElement); 参数详解参数值说明FOV75视野角度值越大视野越广宽高比innerWidth/innerHeight保持画面不变形近截面0.1小于该距离的物体不渲染远截面1000大于该距离的物体不渲染相机 Z 轴2相机距离原点的距离 相机位置示意图┌─────────────────────────────────────────────────────────────┐ │ 相机位置示意 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 相机 (z2) │ │ │ │ │ │ 看向 │ │ ↓ │ │ 地球 (0,0,0) │ │ │ │ X 轴 → 左右旋转 │ │ Y 轴 → 上下旋转 │ │ Z 轴 → 前后移动 │ │ │ └─────────────────────────────────────────────────────────────┘11. 地球材质与纹理 几何体创建const geometry new THREE.SphereGeometry(1, 64, 64);参数值说明半径1球体半径水平分段64经线方向分段数垂直分段64纬线方向分段数 提示分段数越高球体越圆滑但性能消耗越大。64×64 是质量和性能的平衡点。 纹理加载const textureLoader new THREE.TextureLoader(); // 三种纹理 const map textureLoader.load(earth_atmos_2048.jpg); // 颜色纹理 const bumpMap textureLoader.load(earth_normal_2048.jpg); // 法线贴图 const specularMap textureLoader.load(earth_specular_2048.jpg); // 高光贴图 三种纹理对比┌─────────────────────────────────────────────────────────────┐ │ 纹理类型对比 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ️ 颜色纹理 (map) │ │ ═══════════ │ │ • 显示地球表面颜色 │ │ • 包含陆地、海洋、云层 │ │ • 基础视觉效果 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ ️ 法线贴图 (bumpMap) │ │ ═══════════ │ │ • 模拟表面凹凸效果 │ │ • 增强山脉、地形的立体感 │ │ • bumpScale 控制凹凸强度 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ ✨ 高光贴图 (specularMap) │ │ ═══════════ │ │ • 控制反光强度 │ │ • 海洋反光强陆地反光弱 │ │ • 增强真实感 │ │ │ └─────────────────────────────────────────────────────────────┘ 材质配置const material new THREE.MeshPhongMaterial({ map: map, // 颜色纹理 bumpMap: bumpMap, // 法线贴图 bumpScale: 0.05, // 凹凸强度 specularMap: specularMap, // 高光贴图 specular: new THREE.Color(0x333333), // 高光颜色 shininess: 5 // 光泽度 }); const earth new THREE.Mesh(geometry, material); scene.add(earth); 材质参数说明参数值效果bumpScale0.05凹凸强度值越大越明显specular0x333333高光颜色深灰色shininess5光泽度值越大越亮12. 灯光系统 灯光配置// 环境光 - 基础照明 const ambientLight new THREE.AmbientLight(0x404040, 1); scene.add(ambientLight); // 方向光 - 模拟太阳 const directionalLight new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(2, 1, 3).normalize(); scene.add(directionalLight); 灯光类型对比┌─────────────────────────────────────────────────────────────┐ │ 灯光类型对比 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 环境光 (AmbientLight) │ │ ═════════════ │ │ • 均匀照亮整个场景 │ │ • 无方向性 │ │ • 防止背光面全黑 │ │ • 颜色0x404040深灰色 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ ☀️ 方向光 (DirectionalLight) │ │ ═════════════ │ │ • 模拟平行光源如太阳 │ │ • 有方向性 │ │ • 产生明暗对比 │ │ • 位置(2, 1, 3) 归一化 │ │ │ └─────────────────────────────────────────────────────────────┘ 灯光效果示意┌─────────────────────────────────────────────────────────────┐ │ 灯光效果示意 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ☀️ 方向光 │ │ ╱ │ │ ╱ │ │ ╱ │ │ 地球 │ │ ╱│ │ │ ╱ │ 环境光整体 │ │ │ │ 亮面 ← 方向光照射 │ │ 暗面 ← 背光面 │ │ │ └─────────────────────────────────────────────────────────────┘13. 鼠标交互控制 变量定义let isDragging false; let previousMousePosition { x: 0, y: 0 }; 事件处理函数// 鼠标按下 function onMouseDown(event) { isDragging true; previousMousePosition { x: event.clientX, y: event.clientY }; } // 鼠标移动 function onMouseMove(event) { if (isDragging) { const deltaX event.clientX - previousMousePosition.x; const deltaY event.clientY - previousMousePosition.y; // 根据鼠标移动调整地球旋转 earth.rotation.y deltaX * 0.01; earth.rotation.x deltaY * 0.01; previousMousePosition { x: event.clientX, y: event.clientY }; } } // 鼠标释放 function onMouseUp() { isDragging false; } // 鼠标离开 function onMouseLeave() { isDragging false; } // 禁用右键菜单 function onContextMenu(event) { event.preventDefault(); } 事件监听器绑定renderer.domElement.addEventListener(mousedown, onMouseDown, false); window.addEventListener(mousemove, onMouseMove, false); window.addEventListener(mouseup, onMouseUp, false); renderer.domElement.addEventListener(mouseleave, onMouseLeave, false); renderer.domElement.addEventListener(contextmenu, onContextMenu, false); 交互流程图┌─────────────────────────────────────────────────────────────┐ │ 交互控制流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ │ │ │ 鼠标按下 │ ──→ isDragging true │ │ │ mousedown │ 记录起始位置 │ │ └─────────────┘ │ │ ↓ │ │ ┌─────────────┐ │ │ │ 鼠标移动 │ ──→ 计算位移差 │ │ │ mousemove │ 更新旋转角度 │ │ │ (isDragging)│ 更新上次位置 │ │ └─────────────┘ │ │ ↓ │ │ ┌─────────────┐ │ │ │ 鼠标释放 │ ──→ isDragging false │ │ │ mouseup │ 恢复自动旋转 │ │ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ 旋转参数说明参数值说明deltaX * 0.01Y 轴旋转水平拖动控制左右旋转deltaY * 0.01X 轴旋转垂直拖动控制上下旋转0.01灵敏度值越大旋转越快14. 动画循环 核心代码function animate() { requestAnimationFrame(animate); // 非拖动状态下自动旋转 if (!isDragging) { earth.rotation.y 0.001; } renderer.render(scene, camera); } animate(); 动画原理┌─────────────────────────────────────────────────────────────┐ │ 动画循环原理 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ requestAnimationFrame(animate) │ │ ↓ │ │ 浏览器准备下一帧渲染 │ │ ↓ │ │ 检查是否拖动 │ │ ↓ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ 拖动中 │ │ 未拖动 │ │ │ │ 不自动旋转 │ │ 自动旋转 │ │ │ └─────────────┘ └─────────────┘ │ │ ↓ ↓ │ │ renderer.render() ←───┘ │ │ ↓ │ │ 重复循环约 60fps │ │ │ └─────────────────────────────────────────────────────────────┘ 响应式适配function onWindowResize() { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } window.addEventListener(resize, onWindowResize, false);操作说明更新宽高比保持画面不变形更新投影矩阵应用新的宽高比更新渲染器尺寸适配新窗口大小第五部分扩展与优化15. 功能扩展建议 可扩展功能┌─────────────────────────────────────────────────────────────┐ │ 功能扩展建议 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 基础扩展 │ │ ├── 添加月球绕地球旋转 │ │ ├── 添加大气层效果 │ │ ├── 添加星空背景 │ │ └── 添加云层动画 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ 交互扩展 │ │ ├── 鼠标滚轮缩放 │ │ ├── 点击显示地点信息 │ │ ├── 添加标记点城市/景点 │ │ └── OrbitControls 专业控制 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ 数据可视化 │ │ ├── 显示飞行航线 │ │ ├── 显示人口密度 │ │ ├── 显示天气数据 │ │ └── 显示实时地震 │ │ │ └─────────────────────────────────────────────────────────────┘ 扩展代码示例添加星空背景// 创建星空 function createStars() { const starGeometry new THREE.BufferGeometry(); const starMaterial new THREE.PointsMaterial({color: 0xffffff}); const starVertices []; for(let i 0; i 10000; i) { const x (Math.random() - 0.5) * 2000; const y (Math.random() - 0.5) * 2000; const z (Math.random() - 0.5) * 2000; starVertices.push(x, y, z); } starGeometry.setAttribute(position, new THREE.Float32BufferAttribute(starVertices, 3)); const stars new THREE.Points(starGeometry, starMaterial); scene.add(stars); } createStars();添加鼠标滚轮缩放camera.position.z 2; renderer.domElement.addEventListener(wheel, (event) { camera.position.z event.deltaY * 0.001; camera.position.z Math.max(1.5, Math.min(5, camera.position.z)); });使用 OrbitControls推荐!-- 引入 OrbitControls -- script srchttps://cdn.jsdelivr.net/npm/three0.128.0/examples/js/controls/OrbitControls.js/script script // 添加控制器 const controls new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping true; controls.dampingFactor 0.05; controls.autoRotate true; controls.autoRotateSpeed 1.0; // 在 animate 中更新 function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } /script16. 性能优化⚡ 优化建议┌─────────────────────────────────────────────────────────────┐ │ 性能优化建议 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ✅ 几何体优化 │ │ • 适当降低分段数32×32 足够 │ │ • 使用 LOD多细节层次 │ │ │ │ ✅ 纹理优化 │ │ • 使用压缩纹理KTX/DDS │ │ • 根据设备选择纹理大小 │ │ • 使用纹理压缩格式 │ │ │ │ ✅ 渲染优化 │ │ • 限制最大帧率 │ │ • 离屏时暂停渲染 │ │ • 使用请求动画帧 │ │ │ │ ✅ 资源管理 │ │ • 及时释放不用的资源 │ │ • 使用纹理缓存 │ │ • 延迟加载资源 │ │ │ └─────────────────────────────────────────────────────────────┘ 代码优化示例// 优化 1降低几何体分段数 const geometry new THREE.SphereGeometry(1, 32, 32); // 64→32 // 优化 2离屏时暂停渲染 let isVisible true; document.addEventListener(visibilitychange, () { isVisible !document.hidden; }); function animate() { if (isVisible) { requestAnimationFrame(animate); // ... 渲染代码 } else { requestAnimationFrame(animate); } } // 优化 3使用纹理压缩 // 在生产环境中使用 .ktx 或 .dds 格式17. 常见问题❓ FAQ问题原因解决方案地球不显示纹理加载失败检查 CDN 链接使用本地纹理画面模糊像素比未设置添加setPixelRatio拖动卡顿性能问题降低几何体分段数移动端无法拖动缺少触摸事件添加 touch 事件监听窗口缩放变形未更新相机添加 resize 事件处理 移动端适配// 添加触摸事件支持 let touchStartX 0; let touchStartY 0; renderer.domElement.addEventListener(touchstart, (event) { isDragging true; touchStartX event.touches[0].clientX; touchStartY event.touches[0].clientY; }); renderer.domElement.addEventListener(touchmove, (event) { if (isDragging) { const deltaX event.touches[0].clientX - touchStartX; const deltaY event.touches[0].clientY - touchStartY; earth.rotation.y deltaX * 0.01; earth.rotation.x deltaY * 0.01; touchStartX event.touches[0].clientX; touchStartY event.touches[0].clientY; } }); renderer.domElement.addEventListener(touchend, () { isDragging false; }); 总结核心知识点回顾┌─────────────────────────────────────────────────────────────┐ │ 知识点总览 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Three.js 基础 │ │ ├── Scene场景 │ │ ├── Camera相机 │ │ ├── Renderer渲染器 │ │ └── Geometry Material Mesh │ │ │ │ 材质与纹理 │ │ ├── 颜色纹理map │ │ ├── 法线贴图bumpMap │ │ └── 高光贴图specularMap │ │ │ │ 灯光系统 │ │ ├── AmbientLight环境光 │ │ └── DirectionalLight方向光 │ │ │ │ 交互控制 │ │ ├── 鼠标事件监听 │ │ ├── 旋转角度计算 │ │ └── 动画循环 │ │ │ │ 响应式适配 │ │ ├── 窗口 resize 处理 │ │ ├── 设备像素比适配 │ │ └── 移动端触摸支持 │ │ │ └─────────────────────────────────────────────────────────────┘ 学习路线建议┌─────────────────────────────────────────────────────────────┐ │ Three.js 学习路线 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 第一阶段基础 │ │ ├── 场景搭建 │ │ ├── 几何体与材质 │ │ └── 本项目的地球模型 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ 第二阶段交互 │ │ ├── 鼠标/触摸控制 │ │ ├── OrbitControls │ │ └── 点击检测 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ 第三阶段进阶 │ │ ├── 粒子系统 │ │ ├── 着色器编程 │ │ └── 物理引擎 │ │ │ │ ───────────────────────────────────────────────────────── │ │ │ │ 第四阶段实战 │ │ ├── 数据可视化 │ │ ├── 游戏开发 │ │ └── VR/AR 应用 │ │ │ └─────────────────────────────────────────────────────────────┘ 推荐资源类型名称链接官网Three.js 官方网站https://threejs.org文档Three.js 文档https://threejs.org/docs示例Three.js 示例https://threejs.org/examples教程Three.js 入门教程https://threejs-journey.com社区GitHubhttps://github.com/mrdoob/three.js中文Three.js 中文网http://www.webgl3d.cn 结语3D 可视化是前端开发的重要方向掌握 Three.js让你的网页更加生动通过本项目你已经✅ 掌握了 Three.js 的基本使用流程✅ 理解了 3D 场景、相机、渲染器的关系✅ 学会了材质与纹理的应用✅ 实现了鼠标交互控制✅ 完成了响应式适配下一步建议尝试添加更多功能月球、星空、标记点学习 OrbitControls 专业控制器探索粒子系统和着色器将地球模型应用到实际项目中记住3D 世界的大门已经打开尽情发挥你的创造力 更新时间2026 年 3 月 24 日✍️ 作者书到用时方恨少! 如有疑问欢迎在评论区留言讨论如果这篇博客对你有帮助请点赞、收藏⭐、转发让更多的小伙伴一起探索 3D 世界