资讯动态

Three.js旋转地球源码:从贴图到动画的完整实现

发布时间:2026/9/2 10:46:22 来源:尧图企业网站定制
简介HTMLThree.js旋转地球源码是一份面向Web前端开发者和Three.js初学者的可直接运行示例用于在网页中快速构建并展示三维旋转地球模型帮助开发者免去从零搭建3D场景的繁琐步骤。压缩包采用RAR格式共5个文件2个JavaScript脚本负责页面中的核心3D渲染逻辑包含Three.js库与主程序1个HTML页面承载页面结构1个CSS文件控制页面布局与样式1张JPG图片作为地球表面材质贴图整体仅957KB体积小巧、结构清晰。目前已有1351人学习下载。代码将三维场景、摄像机、球体模型、材质贴图与旋转动画完整串联适合初学者对照理解Three.js的基础流程包括场景搭建、几何体创建、纹理映射以及动画循环等关键环节同时具备良好的复用性可方便地移植到需要地球模型的前端项目中节省开发调试时间。配套的地球贴图材质更能帮助理解贴图坐标与球面渲染的对应关系对正在研究Three.js或需要快速集成地球效果的开发者来说是一份不错的参考。 做 Web 可视化的时候想在页面上放一个能转的地球第一个反应就是 Three.js。这个“HTMLThreejs旋转地球源码含地球材质贴图”的项目其实就是把那套 3D 地球最核心的玩法抽出来一个 HTML 文件、一个 Three.js 的库、一张地球贴图拼出一个自带光照、能自动旋转、还能适配屏幕的地球。源码拿到手之后不用装环境、不用跑构建双击就能看到效果。这篇博文我就拿自己的实操过程来讲讲这个项目怎么玩踩过哪些坑怎么改出自己想要的效果。适合刚开始接触 Three.js 的网页前端也适合项目里要快速加一个“地球”做视觉元素的开发者。1. 先把旋转地球的骨架想清楚1.1 为什么选 Three.js 而不是 CSS 或原生 Canvas做旋转地球这件事我见过有人用 CSS 的transform: rotateY()配合平面图硬转成品看起来就像一张图片在翻面没有球面的立体感也有人用原生 Canvas 配合数学计算把经纬度投影成球面能把轮廓画出来但一旦要加光照、阴影、纹理畸变矫正代码量就压不住了。Three.js 的优势在于它把 WebGL 底层逻辑封装成了“场景、相机、网格、材质”这一套面向对象模型思考方式更接近美术做三维建模先搭台子再放物体再打光。回到这个项目本身核心就三件事一个Scene场景用来装所有 3D 对象一个PerspectiveCamera透视相机决定用户从哪个角度观察一个WebGLRenderer渲染器把三维场景画到canvas上。再往场景里放地球模型也就是一个SphereGeometry球体外表面贴一张世界地图纹理补一个方向光模拟太阳照射最后用一个requestAnimationFrame循环让地球绕 Y 轴旋转。这个架构可以扩展到任何 Three.js 3D 项目不只是地球做产品展示、数据可视化、3D 模型预览套路都是这一套。1.2 项目目录与运行方式这个项目不需要 Node.js也不需要 webpack解法就是把 Three.js 通过script标签引入。我用的是 CDN 方式加载three.min.js的 UMD 版本挂到全局的THREE对象上。这样最省事复制源码就能跑。运行方式就两种本地双击 HTML 文件大多数情况下能跑但注意浏览器对file://协议下加载本地资源有限制详见后面常见问题部分。起一个本地静态服务推荐用 VS Code 的 Live Server或者 Python 的python -m http.server 8080把页面放在服务根目录下访问localhost:8080即可。文件结构上我习惯把贴图单独放在assets/目录里HTML 放根目录这样后面想换纹理、加天空盒子、加云层贴图时不用改动目录结构。2. 核心细节贴图、材质与光照的配合2.1 地球贴图从哪里来“含地球材质贴图”是这个项目最实在的价值点。地球贴图本质上是一张**等距圆柱投影Equirectangular Projection**的平面图就是你在平面世界地图上看到的那种方方正正的样式。Three.js 的SphereGeometry会把这纹理按 UV 坐标包到球体上很像把一张长方形纸包在一个球外面。贴图选择建议分辨率市面上常见的成品地球贴图有 1K、2K、4K 之分。网页项目里 2K 足够4K 只有在拍特写镜头、拉近看岛屿轮廓的时候才有意义但纹理显存占用和整体性能压力也会上去一个级别。格式JPG 够用体积小如果追求大陆边缘文字清晰度、或者需要透明通道的图层用 PNG。来源NASA 官网有不少公开的地球卫星影像Three.js 官方仓库的examples/textures/planets/目录下面也有现成的贴图资源。商用项目用之前先确认授权。这里有个坑要专门说一下贴图的 UV 接缝问题。如果你的贴图是从左到右的一个连续世界平面图那么当它包到球体上左边缘和右边缘会形成一条拼接缝。Three.js 里可以通过设置texture.wrapS THREE.RepeatWrapping减少接缝痕迹但如果你是在预览一个贴图品质很高、边缘又非常明显的素材最好的办法是换一张左右无缝的贴图。2.2 材质的取舍Phong 还是 StandardThree.js 里最常用的球体材质有两个MeshPhongMaterial和MeshStandardMaterial。项目源码里我用的是MeshPhongMaterial原因很直接场景就一个球不需要 PBR 那套粗糙度、金属度参数Phong 材质光照计算快对手机端 GPU 压力小要模拟的地球表面陆地、海洋本质是漫反射为主Phong 的表现力已经足够。如果你想要更加“真实”的地球比如海洋有明显的镜面反射像卫星照片里阳光打在海上那一块白亮的区域可以换成MeshStandardMaterial然后把roughness调低到 0.3 左右metalness设为 0。这样海水会有一层光泽感代价是渲染变慢。对照页面上有没有其他特效再决定要不要换。2.3 光源怎么布置才自然一个纯贴图的地球如果没有光照看起来就是你贴了一张“图”在球面上扁平的没有立体感。光源决定了明暗交界线看起来才像个球。实际测试下来一组光源的搭配效果最好光源类型颜色/强度作用AmbientLight0x333333弱一点保证背光面不至于全黑DirectionalLight0xffffff强度 1.0模拟太阳平行光方向产生明暗过渡这里有个反直觉的点环境光不要加太亮。很多人为了让球体更清晰把环境光加到0xffffff结果整个球被“洗”得很平立体感立刻消失。环境光加暗色比如0x404040都行方向光负责制造对比才是一个“球”。方向光的位置也很讲究。我习惯放在(5, 3, 5)附近这样光从右前上方打过来地球的左上部分会有阴影右下部分更亮看起来最有立体感。如果放在正前方(0,0,5)整个球没有明暗面又变回一张贴图了。3. 实操手写一个完整的旋转地球3.1 页面基础结构与样式先看 HTML 结构。body里不需要放任何 DOM 元素Three.js 的渲染器会帮我们生成一个canvas直接塞到页面里。页面的样式做两件事全屏展示去掉滚动条。!DOCTYPE html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1 titleThree.js 旋转地球/title style * { margin: 0; padding: 0; } html, body { width: 100%; height: 100%; overflow: hidden; background: #000; } canvas { display: block; } /style /head body script srchttps://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js/script script src./main.js/script /body /html版本这里我说一下为什么用r128而不是最新的r16xr128 是 UMD 版本用 script 标签引入最简单代码写法和一些 API 名称也足够稳定全项目 demo 完全够用。新版本的 Three.js 走向 ES Module 化引入方式更复杂还要借助 import map对只是想快速做一个旋转地球的朋友来说没必要。3.2 创建场景、相机与渲染器这部分是 Three.js 项目的“铁三角”顺序不能乱场景负责装东西相机负责看东西渲染器负责画出来。// 场景 const scene new THREE.Scene(); // 相机 const camera new THREE.PerspectiveCamera( 45, // 视角越大看到的东西越多透视越夸张 window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近裁剪面 1000 // 远裁剪面 ); camera.position.z 4; // 相机往后拉让地球完整落在视野里 // 渲染器 const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement);视角45是模拟人眼的常规数值z轴距离4是在半径1的球体下比较合适的观看距离。如果你把球体缩放成2那相机距离要拉到6以上否则球会溢出画面。3.3 添加地球球体与纹理这一步就是项目标题里的重点创建球体几何体加载贴图套上材质生成网格加入场景。const geometry new THREE.SphereGeometry(1, 64, 64); const textureLoader new THREE.TextureLoader(); const texture textureLoader.load(./assets/earth.jpg); const material new THREE.MeshPhongMaterial({ map: texture, shininess: 25 // 高光强度适中模拟海面轻微反光 }); const earth new THREE.Mesh(geometry, material); scene.add(earth);这里有两个参数值得写清楚SphereGeometry(1, 64, 64)半径 1宽度分段 64高度分段 64。分段数越多球面越平滑三角形数量越多。默认的 32 段在较新设备上边缘已经会有轻微的多边形感64 段是性能和视觉的平衡点。改到 128 段会在球体快速的边缘线条上显得更圆滑但没必要。textureLoader.load的第二个参数可以传一个回调函数在纹理加载完成后执行比如给页面加一点淡入效果。贴图本身也会影响观感。光源、材质参数这种影响是全局的但如果你拿到的贴图是“黑底星空图”、“带大气层的透明图”那效果就完全不同了。所以我建议拿到一张新贴图之后先用最简单的方式加载出来看一眼再做其他特效叠加。3.4 让地球转起来旋转动画用的是requestAnimationFrame。一个容易被忽略的问题每一帧地球转动的角度应该是固定的吗如果固定写成earth.rotation.y 0.005那么 60Hz 的显示器上地球转速是0.3弧度/秒而在 144Hz 的显示器上转速会变成0.72弧度/秒转得明显快很多。这就是“帧率挂勾”问题。解决办法是引入时间增量deltaThree.js 给我们提供了现成的THREE.Clockconst clock new THREE.Clock(); function animate() { requestAnimationFrame(animate); const delta clock.getDelta(); earth.rotation.y 0.4 * delta; // 每秒 0.4 弧度转一圈约 15.7 秒 renderer.render(scene, camera); } animate();每秒0.4弧度的转动速度视觉效果是比较舒服的不会慢到像静止也不会快到像陀螺仪。想要慢节奏一点的展示可以改成0.15。3.5 完整的快速可跑源码把上面的片段拼起来再加个自适应窗口的resize监听就是一份完整可运行的旋转地球源码。这份代码我建议你就当作一个基础模板后面所有升级都在这上面改const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z 4; const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); const ambient new THREE.AmbientLight(0x404040); scene.add(ambient); const sun new THREE.DirectionalLight(0xffffff, 1.0); sun.position.set(5, 3, 5); scene.add(sun); const geometry new THREE.SphereGeometry(1, 64, 64); const texture new THREE.TextureLoader().load(./assets/earth.jpg); const material new THREE.MeshPhongMaterial({ map: texture, shininess: 25 }); const earth new THREE.Mesh(geometry, material); scene.add(earth); const clock new THREE.Clock(); function animate() { requestAnimationFrame(animate); const delta clock.getDelta(); earth.rotation.y 0.4 * delta; renderer.render(scene, camera); } animate(); window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });到这里一个旋转地球已经跑起来了。但如果你想把这种“旋转展示”加到现有页面上或者希望地球有一个初始角度、可以看到亚洲或者美洲的正面那还需要做点小调整。比如把地球的经纬度旋转拆开rotation.x控制南北倾角rotation.z控制轴线倾角rotation.y控制自转。我最常用的初始画面是让中国在正面这样演示的时候更亲切。4. 常见问题与排查技巧实录实操过程中你一定会遇到各种问题。我把自己在跑这个项目时踩过的、以及帮别人排查过的典型问题整理了一下按出现频率排序。4.1 页面黑屏或只显示背景色黑屏是最高频的问题。无非三种原因现象原因处理方式页面全黑看不到地球相机看不到球检查camera.position.z距离球体太近时被裁剪掉检查球体是否加入了场景地球在但很暗淡缺少光源或光源设置不对加上AmbientLight和DirectionalLight只有黑背景贴图路径 404打开控制台看 Network 面板确认earth.jpg路径是否正确贴图加载失败其实不是最明显的报错因为图片请求失败不会让页面崩掉只会在控制台留下一条资源请求日志。这时候地球会呈现出默认的白色材质如果你没注意看会以为“球没渲染出来”。4.2 地球边缘有锯齿Three.js 里所谓的“锯齿问题”在 r185 版本附近讨论热度很高其实根源一致WebGL 默认的抗锯齿机制是 MSAA开启方式是在创建渲染器时传{ antialias: true }。如果你创建时没开后面改renderer.antialias是没有用的只能重新初始化渲染器。另外还有一个影响清晰度的重点是setPixelRatio。不设置的话Mac 的 Retina 屏上 1 个 CSS 像素对应 2 个物理像素画面会发糊但直接设置为设备像素比也可能导致 GPU 负载过高。我惯用Math.min(window.devicePixelRatio, 2)把上限压住兼顾清晰度和性能。如果你用了后处理脚本或者自定义着色器MSAA 通常会失效锯齿又会冒出来。这时候可以考虑叠加渲染分辨率比如renderer.setPixelRatio(2)强制超采样能有效缓解。4.3 贴图“接缝”或者“贴反了”贴图包到球体上之后如果看到有明显的左右接缝线说明贴图左右边缘在球面上是断开的两条线可以通过texture.wrapS THREE.ClampToEdgeWrapping配合重复采样的方式规避但根治方法还是换一张做好的无缝贴图。上下颠倒经纬度投影贴图通常是北在上、南在下如果颠倒了说明贴图本身是“南极在上”的图可以用texture.rotation Math.PI配合texture.center设置来解决。地图位置不对正面不是你想要的大陆在场景初始化时直接设置earth.rotation.y为对应的弧度值。比如想让本初子午线在正前方把rotation.y设为-Math.PI / 2附近。4.4 在低端设备上发烫、掉帧旋转地球是一个持续的动画循环即使你不操作它也在不间断渲染GPU 一直在干活。低配手机上如果转起来比较吃力优先做三件事把球体分段从64降到48三角形数量减少将近一半把renderer.setPixelRatio上限从2降到1.5把贴图从 4K 压缩到 2K纹理加载和显存占用都会明显下降。掉帧还有一种情况是页面里同时开了很多动画比如背景粒子、云层、星空贴图等多个 Canvas 叠加会让帧率雪崩。两个选择把所有动画放到同一个渲染器里或者用 CSS 动画去做纯平面的背景不要让多个 WebGL 渲染器同时跑。4.5 用一个技巧直达“源码能跑”上面的问题排查完你应该已经拿到一个能跑、画质可调的基础项目了。最后再分享一个小技巧我自己常用它来快速区分是代码问题还是资源问题把textureLoader.load的 URL 换成一张网络图片比如一个公开的静态图地址只要跨域允许如果页面能正常显示“另一颗星星”说明代码没问题问题在你的本地贴图资源上如果还是黑的那问题在场景、相机这一层先别折腾贴图了。5. 你还可以这样扩展旋转地球做出来之后我通常给它加三个小部件按投入产出比排序第一是星空背景。不用复杂的粒子系统直接给场景的背景设置成一张深空星星贴图或者用THREE.Points摆几千个随机点效果立刻不一样。最简单的方式就是设一个scene.background textureLoader.load(./assets/stars.jpg)。第二是云层。找一张带透明通道的云层贴图做第二个SphereGeometry半径比地球大一点点比如 1.01材质用MeshPhongMaterial的alphaMap透明度设为 0.4然后让它以比地球略慢的速度旋转。这样一个“活”的地球就出来了。第三是鼠标交互。给earth加上THREE.OrbitControls在 r128 里要单独引入就能实现鼠标拖拽旋转、滚轮缩放适合产品展示场景。注意引入方式在 r128 里是script srchttps://cdnjs.cloudflare.com/ajax/libs/three.js/r128/examples/js/controls/OrbitControls.js/script挂载在THREE.OrbitControls下新版本里则是从three/examples/jsm/controls/OrbitControls.js导入 ES Module用法略有差别。我个人做这个旋转地球项目最大的体会是Three.js 的 API 又多又杂但它最常用的套路就是那几步千万不要一开始就陷入“把所有示例学一遍”的焦虑里。先把场景、相机、渲染器、网格、材质、光照、动画循环这七个关键词吃透你已经能覆盖绝大多数 3D 展示场景了。旋转地球只是一个起点把这份源码留在手边下次要做地球数据可视化、3D 落地页、大屏数字地球时直接在这个骨架上填充比从零起步要快得多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价