【Three.js】使用Three.js开发一个太阳系 3D 可视化模拟器完整技术
项目概述
基于 Three.js 构建的交互式 3D 太阳系模拟,运行于现代浏览器中。支持行星公转、自转、土星光环、地球云层与大气、太阳辉光与日冕特效,以及相机聚焦与自由视角控制。
技术栈: Three.js r170 (ES Module)、原生 JavaScript (ES Module)、WebGL、Canvas 2D
入口文件: earth.html(单页应用,无构建工具依赖)
效果展示


项目结构
game engine/
├── earth.html # 主入口,包含全部 HTML/CSS/JS
├── img/ # 行星纹理图片(外网下载的 JPG)
│ ├── sun.jpg
│ ├── earth.jpg
│ ├── mercury.jpg
│ ├── venus.jpg
│ ├── mars.jpg
│ ├── jupiter.jpg
│ ├── saturn.jpg
│ ├── uranus.jpg
│ ├── neptune.jpg
│ └── moon.jpg
架构设计
加载与初始化
通过 <script type="importmap"> 映射 three 及 three/addons/ 到 unpkg CDN,以 ES Module 方式导入 Three.js 核心库和 OrbitControls。
js
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
场景、相机、渲染器
| 组件 | 参数 |
|---|---|
| 场景 | 黑色背景 (0x000000) |
| 相机 | PerspectiveCamera(45, aspect, 0.1, 1000),初始位置 (0, 10, 18) |
| 渲染器 | WebGLRenderer,开启抗锯齿,像素比限制 ≤2,ACES Filmic ToneMapping |
轨道控制器
使用 OrbitControls 实现:
- 阻尼惯性:
dampingFactor = 0.05 - 距离限制:
minDistance = 0.8,maxDistance = 60 - 自动旋转:默认开启,速度
0.3
模块详解
1. 星空背景 (createStars)
使用 THREE.Points 生成 15000 颗星星。

- 位置:球面均匀分布,半径 100~400
- 大小:
0.3~1.1随机 - 颜色:10% 偏橙红,10% 偏蓝,80% 纯白
- 材质:
PointsMaterial,AdditiveBlending,sizeAttenuation: true
2. 太阳系统
纹理
- 程序化回退纹理:橙黄渐变 + 大量随机噪点圆
- 外载纹理:
img/sun.jpg(加载完成后替换)

网格
| 层级 | 半径 | 材质 | 作用 |
|---|---|---|---|
| 太阳球体 | 1.5 | MeshBasicMaterial |
基础表面 |
| 内层辉光 | 1.6 | ShaderMaterial |
边缘泛光 |
| 日冕 | 2.0 | ShaderMaterial |
动态闪烁冕流 |
| 外层光晕 | 2.6 | ShaderMaterial |
微弱外发光 |
着色器特效
三个 ShaderMaterial 共享相同的顶点着色器(计算法线和世界坐标),区别在片元着色器:
- 辉光 :基于视角与法线点积的边缘发光,叠加时间脉冲
sin(time * 2.0 + y * 3.0) - 日冕 :更强的边缘衰减
pow(rim, 3),叠加 flicker 噪声(sin(time * 1.5 + x * 5 + z * 4)) - 光晕 :最外层大半径
pow(rim, 4),低强度 0.12
所有发光层均使用 AdditiveBlending 和 BackSide,保证从任何角度可见。
3. 行星系统
数据定义 (planetData)
| 行星 | 半径 | 轨道半径 | 相对速度 | 轴倾角 | 特殊标记 |
|---|---|---|---|---|---|
| 水星 | 0.08 | 2.5 | 4.15 | 0.03 | - |
| 金星 | 0.18 | 3.8 | 1.62 | 2.64 | - |
| 地球 | 0.20 | 5.2 | 1.00 | 0.41 | earth: true |
| 火星 | 0.13 | 6.8 | 0.53 | 0.44 | - |
| 木星 | 0.55 | 9.5 | 0.084 | 0.05 | - |
| 土星 | 0.45 | 12.5 | 0.034 | 0.47 | saturn: true |
| 天王星 | 0.30 | 15.5 | 0.012 | 1.71 | - |
| 海王星 | 0.28 | 18.5 | 0.006 | 0.49 | - |
纹理加载机制
采用 fallback 回退 + 异步替换 策略:
js
const planetMatConfig = {
mercury: { fallback: createMercuryTexture(), props: { roughness: 0.9, metalness: 0.1 } },
// ...
};
const texUrls = {
mercury: 'img/mercury.jpg',
// ...
};
- 初始化时创建 Canvas 程序化纹理作为 fallback
- 用
TextureLoader异步加载外部 JPG 图片 - 加载完成后替换材质的
map属性并标记更新
地球特殊处理:使用 MeshPhysicalMaterial 并设置 clearcoat 等 PBR 参数。
八大行星月球地球和太阳都下载号纹理图片


程序化纹理生成
各行星的 createXxxTexture() 函数均使用 Canvas 2D API:
| 行星 | 方法 | 风格 |
|---|---|---|
| 水星 | createMercuryTexture |
灰度渐变 + 大量深色陨石坑 |
| 金星 | createVenusTexture |
暖黄渐变 + 大范围模糊云层 |
| 地球 | 内联在 fallbackEarthTex |
蓝绿渐变为大陆 + 白斑为云(示意) |
| 火星 | createMarsTexture |
红橙渐变 + 深色地表斑点 + 浅色极冠 |
| 木星 | createJupiterTexture |
水平色带 + 白色湍流噪点 |
| 土星 | createSaturnTexture |
水平淡黄带 + 微弱高光 |
| 天王星 | createUranusTexture |
青蓝渐变 + 微弱云纹 |
| 海王星 | createNeptuneTexture |
深蓝渐变 + 淡色涡旋 |
LOD(多级细节)
createPlanetLOD(radius, material, baseSeg) 创建三个精度的球体:
| 级别 | 分段数 | 显示距离 |
|---|---|---|
| 精细 | min(256, baseSeg*2) |
radius * 5 以内 |
| 中等 | baseSeg |
radius * 15 以内 |
| 粗略 | max(12, seg*0.4) |
radius * 40 以内 |
4. 土星环系统
纹理生成
Canvas 2048×64,绘制 23 层同心色带(start → end 映射到径向位置),每层独立颜色和透明度。从内到外模拟:
- 稠密的 B 环(明亮)
- 卡西尼缝(低透明度间隙)
- 较暗的 C 环
- 外层逐渐稀薄
叠加 200 个随机噪点模拟冰粒尘埃。
UV 映射
RingGeometry 默认 UV 基于投影坐标,直接贴图会导致纹理扭曲。核心处理:
js
for (let i = 0; i < uvs.count; i++) {
const x = pos.getX(i);
const y = pos.getY(i);
const dist = Math.sqrt(x * x + y * y);
const u = (dist - ringInner) / (ringOuter - ringInner);
uvs.setXY(i, u, 0.5);
}
- U 坐标重映射为径向距离归一化值,使纹理的 X 轴映射为同心环
- V 坐标固定为 0.5(取纹理中间一行,因为所有行相同)
几何参数
| 参数 | 值 |
|---|---|
| 内径 | planet.radius * 1.15 |
| 外径 | planet.radius * 2.4 |
| 分段 | 320 |
| 倾斜角 | Math.PI * 0.4 |
| 透明度 | 0.75 |
| 渲染面 | DoubleSide |
5. 地球云层与大气
- 云层 :
MeshPhysicalMaterial,半径偏移 0.8%,AdditiveBlending,以不同速度自转(rotation.y += dt * 0.1) - 大气辉光 :
ShaderMaterial,pow(rim, 3)边缘发光,颜色#4d8aff,AdditiveBlending - 月球 :
SphereGeometry(radius * 0.27),以地球为中心半径 0.5 公转
6. 运动系统
公转
js
p.angle += dt * p.data.speed * 0.2;
p.lod.position.x = Math.cos(p.angle) * p.data.orbit;
p.lod.position.z = Math.sin(p.angle) * p.data.orbit;
相对速度基准:地球 = 1.0。
自转
所有行星自转:rotation.y += dt * 0.3(云层更慢 *0.1)
月球公转
角速度 dt * 3,半径 0.5,绕地球旋转。
7. 相机聚焦系统
点击右侧标签触发 focusPlanet(name):
- 获取行星/月球世界坐标
- 计算目标相机位置:
pos + (0, r*2, r*4) - 使用 cubic bezier 缓动 插值
camera.position和controls.target
js
const t = focusProgress < 0.5
? 4 * focusProgress * focusProgress * focusProgress
: 1 - Math.pow(-2 * focusProgress + 2, 3) / 2;
聚焦期间暂停自动旋转。双击空白重置视角。
8. 轨道线
使用 LineBasicMaterial(透明度 0.1)绘制 128 段圆环,每条轨道在行星创建时添加。
9. UI 面板
固定于右侧垂直居中,包含所有行星和月球的圆形标签按钮。点击切换 active 高亮状态。
光照体系
| 光源 | 参数 | 说明 |
|---|---|---|
PointLight |
0xffeedd, intensity 4 |
太阳模拟 |
AmbientLight |
0xffffff, intensity 1 |
环境补光 |
HemisphereLight |
天 0xffffff / 地 0x444466, 0.6 |
环境色 |
着色器一览
| 使用位置 | 着色器 | 核心公式 |
|---|---|---|
| 太阳辉光 | ShaderMaterial (BackSide, Additive) |
rim = pow(1-dot(view,normal), 2) * pulse |
| 太阳日冕 | ShaderMaterial (BackSide, Additive) |
rim = pow(1-dot(view,normal), 3) * flicker |
| 太阳光晕 | ShaderMaterial (BackSide, Additive) |
rim = pow(1-dot(view,normal), 4) |
| 地球大气 | ShaderMaterial (FrontSide, Additive) |
rim = pow(1-dot(view,normal), 3) |
关键渲染参数
| 参数 | 值 |
|---|---|
| Pixel Ratio | min(devicePixelRatio, 2) |
| Tone Mapping | ACES Filmic |
| Tone Mapping Exposure | 1.5 |
| 抗锯齿 | antialias: true |
响应式
窗口 resize 事件更新相机 aspect ratio 和渲染器尺寸。
性能优化
- Pixel ratio 限制 :
Math.min(devicePixelRatio, 2)避免高 DPI 设备渲染压力 - LOD 多级细节:远距离行星使用低面数网格
- Canvas 回退纹理:不依赖外部图片加载,首次渲染即显示
- 纹理尺寸控制:内行星 512×256,外行星(天王/海王)256×128