3D地球可视化教程 - 第1篇:基础地球渲染系统
最终效果:
本节完成后的效果:
难度: ⭐⭐☆☆☆ 初级
预计时间: 30分钟
技术栈: Vue3 + Vite + Three.js
📖 教程简介
欢迎来到3D地球可视化的完整教程系列!在这个系列中,我们将从零开始,一步步构建一个专业级的3D地球项目。本篇是系列的第一篇,我们将学习如何创建一个基础但完整的3D地球渲染系统。
🎯 本篇学习目标
- 理解Three.js的核心概念和渲染管道
- 掌握3D场景的基础搭建方法
- 学会创建真实感地球渲染效果
- 实现基础的相机控制和交互
🏆 最终效果预览
完成本篇教程后,你将获得:
- ✅ 一个可交互的3D地球
- ✅ 真实的地球纹理效果
- ✅ 专业的光照系统
- ✅ 流畅的鼠标控制
🧠 理论基础
Three.js核心概念
在开始编码之前,我们需要理解Three.js的几个核心概念:
1. 渲染三要素
// Three.js的渲染三要素
const scene = new THREE.Scene(); // 场景 - 3D世界的容器
const camera = new THREE.Camera(); // 相机 - 观察3D世界的视角
const renderer = new THREE.Renderer(); // 渲染器 - 将3D场景绘制到屏幕
2. 物体构成
// 3D物体 = 几何体 + 材质
const geometry = new THREE.SphereGeometry(); // 几何体 - 物体的形状
const material = new THREE.Material(); // 材质 - 物体的外观
const mesh = new THREE.Mesh(geometry, material); // 网格 - 最终的3D物体
3. 地球渲染原理
- 使用
SphereGeometry
创建球体几何 - 通过
MeshPhongMaterial
实现光照效果 - 加载真实的地球纹理贴图
- 配置光源系统营造真实感
🛠️ 项目架构设计
目录结构规划
src/
├── components/
│ └── three/
│ ├── models/
│ │ ├── EarthDay/ # 地球白天渲染
│ │ ├── Lights/ # 光照系统
│ │ └── Scene/ # 场景管理
│ └── utils/
│ └── EarthController/ # 地球控制器
├── constants/
│ └── index.js # 常量配置
└── assets/└── textures/ # 纹理资源
核心类设计
- Scene - 场景管理器(单例模式)
- EarthDay - 地球渲染器
- Lights - 光照系统
- EarthController - 交互控制器
🎨 Step 1: 地球几何体创建
1.1 球体几何体
地球的形状使用Three.js的球体几何体:
// src/components/three/models/EarthDay/EarthDay.js
createGeometry() {// 创建球体几何体this.geometry = new THREE.SphereGeometry(EARTH_RADIUS, // 半径: 10EARTH_FRAGMENTS, // 宽度分段: 64 EARTH_FRAGMENTS // 高度分段: 64);
}
参数解释:
- radius: 球体半径,决定地球大小
- widthSegments: 水平方向分段数,影响球体圆滑度
- heightSegments: 垂直方向分段数,影响球体圆滑度
💡 技巧: 分段数越高球体越圆滑,但性能消耗也越大。64是一个平衡点。
1.2 材质系统
使用Phong材质实现真实的光照效果:
createMaterial() {this.material = new THREE.MeshPhongMaterial({// 🎨 纹理贴图map: this.textures.day, // 地球表面颜色贴图bumpMap: this.textures.bump, // 凹凸贴图(山脉、海沟)specularMap: this.textures.specular, // 镜面反射贴图(海洋反光)// 🎭 基础属性 color: new THREE.Color("#ffffff"),opacity: 1.0,transparent: true,// ✨ Phong光照属性emissive: new THREE.Color("#000000"), // 自发光颜色emissiveIntensity: 0.0, // 自发光强度specular: new THREE.Color("#111111"), // 镜面反射颜色shininess: 30, // 光泽度bumpScale: 12.4, // 凹凸强度});
}
材质属性详解:
- map: 主纹理,决定地球表面的颜色
- bumpMap: 凹凸贴图,模拟地形高低起伏
- specularMap: 镜面贴图,控制海洋的反光效果
- shininess: 光泽度,数值越高反光越强
💡 Step 2: 光照系统设计
2.1 光源类型分析
我们的地球使用了多种光源组合:
// src/components/three/models/Lights/Lights.js
class Lights {constructor(parentContainer, camera, controls, options) {// 🌞 方向光 - 模拟太阳光this.directionalLight = new THREE.DirectionalLight("#ffffff", // 白色光5.1 // 强度);// 🌙 环境光 - 模拟天空散射光this.ambientLight = new THREE.AmbientLight("#ffffff", // 白色光2.45 // 强度);// 🔆 点光源 - 模拟城市灯光this.pointLight = new THREE.PointLight("#ff6600", // 橙色光2.0, // 强度500, // 照射距离0 // 衰减系数);}
}
2.2 光照效果原理
方向光 (DirectionalLight):
- 模拟太阳光,平行光线
- 产生明确的明暗对比
- 支持阴影投射
环境光 (AmbientLight):
- 模拟天空散射光
- 均匀照亮所有物体
- 避免过暗的阴影区域
点光源 (PointLight):
- 模拟城市灯光效果
- 从一个点向四周发散
- 可设置衰减距离
🎬 Step 3: 场景管理系统
3.1 单例模式设计
场景管理器使用单例模式,确保全局唯一:
// src/components/three/models/Scene/Scene.js
class Scene {static instance = null;constructor(container, options) {// 防止多实例if (Scene.instance) {return Scene.instance;}Scene.instance = this;this.init();}static getInstance() {return Scene.instance;}
}
3.2 组件组织结构
使用分组管理不同类型的组件:
init() {// 🌍 地球主组this.earthGroup = new THREE.Group();// 💡 灯光子组 (固定位置,不随地球旋转)this.lightsGroup = new THREE.Group();this.earthGroup.add(this.lightsGroup);// 🌐 元素子组 (跟随地球旋转)this.elementsGroup = new THREE.Group();this.earthGroup.add(this.elementsGroup);this.scene.add(this.earthGroup);
}
🎮 Step 4: 交互控制系统
4.1 自定义控制器
项目使用自定义的地球控制器替代标准的OrbitControls:
// src/components/three/utils/EarthMouseController.js
class EarthMouseController {constructor(camera, renderer, earthGroup, elementsGroup, scene) {this.camera = camera;this.renderer = renderer;this.earthGroup = earthGroup; // 整个地球组this.elementsGroup = elementsGroup; // 只旋转元素组this.setupEventListeners();}setupEventListeners() {// 鼠标事件监听this.renderer.domElement.addEventListener('mousedown', this.onMouseDown);this.renderer.domElement.addEventListener('mousemove', this.onMouseMove);this.renderer.domElement.addEventListener('mouseup', this.onMouseUp);this.renderer.domElement.addEventListener('wheel', this.onWheel);}
}
4.2 旋转逻辑分离
设计亮点: 灯光固定,只旋转地球元素
onMouseMove(event) {if (this.isMouseDown) {const deltaX = event.clientX - this.mouse.x;const deltaY = event.clientY - this.mouse.y;// 🌍 只旋转元素组,灯光保持固定this.elementsGroup.rotation.y += deltaX * 0.005;this.elementsGroup.rotation.x += deltaY * 0.005;// 💡 灯光组不旋转,保持照射方向}
}
🖼️ Step 5: 纹理系统实现
5.1 纹理加载策略
async loadTextures() {const textureLoader = new THREE.TextureLoader();// 并行加载多张纹理const [dayTexture, bumpTexture, specularTexture] = await Promise.all([this.loadTexture(textureLoader, './textures/earth-day.jpg'),this.loadTexture(textureLoader, './textures/earth-bump.jpg'),this.loadTexture(textureLoader, './textures/earth-specular.jpg'),]);// 设置纹理属性dayTexture.colorSpace = THREE.SRGBColorSpace; // 颜色空间dayTexture.anisotropy = renderer.capabilities.getMaxAnisotropy(); // 各向异性过滤
}
5.2 纹理类型说明
- Day Texture: 地球表面的彩色贴图
- Bump Map: 黑白高度图,模拟地形起伏
- Specular Map: 控制反光强度,海洋更亮,陆地更暗
🎯 Step 6: 完整实现代码
6.1 主要的实现要点
让我们看看当前的核心实现:
- 地球几何体创建 ✅
- Phong材质配置 ✅
- 多光源照明 ✅
- 纹理系统 ✅
- 交互控制 ✅
🎯 关键参数配置
// src/constants/index.js
export const EARTH_RADIUS = 20; // 地球半径
export const EARTH_FRAGMENTS = 64; // 球体分段数
export const AUTO_ROTATE_SPEED = 0.03; // 自动旋转速度// 纹理路径配置
export const PATHS = {earthMap: "./img/earth-day.jpg", // 地球白天贴图bumpMap: "./img/bump-map.webp", // 凹凸贴图specularMap: "./img/specular-map.webp", // 镜面贴图
};
🚀 运行和测试
启动项目
npm run dev
测试功能
在浏览器中你应该看到:
- ✅ 一个完整的3D地球
- ✅ 真实的地球纹理
- ✅ 鼠标拖拽旋转功能
- ✅ 滚轮缩放功能
📊 性能优化要点
1. 纹理优化
- 使用WebP格式减少文件大小
- 设置合适的anisotropy值
- 启用纹理预加载
2. 几何体优化
- 64分段是性能和质量的平衡点
- 避免过高的分段数
- 复用几何体实例
✅ 已掌握的技能:
- Three.js基础概念
- 地球几何体创建
- Phong材质系统
- 多光源照明
- 纹理贴图系统
- 交互控制系统
🎯 下一篇预告
第2篇:夜晚纹理与昼夜过渡效果