Three.js

技术栈
前端框架
3dwebglgraphicsanimationvisualization

概览

Three.js 技术栈概览

Three.js 是由 Ricardo Cabello (Mr.doob) 创建的 WebGL 3D 图形库,是浏览器端 3D 渲染的事实标准。它封装了 WebGL 复杂 API,提供场景、相机、灯光、材质、几何体等高层抽象,让前端开发者轻松构建 3D 交互体验。

Three.js 是什么?

  • WebGL 的上层封装(非框架,是图形库)
  • 场景(Scene) + 相机(Camera) + 渲染器(Renderer) 三要素
  • 丰富的内置几何体、材质、着色器
  • 支持 glTF/OBJ/FBX 等 3D 模型格式

解决什么问题?

  • 浏览器端 3D 可视化
  • 产品 3D 展示、数字孪生
  • 毕设中的数据可视化、虚拟展厅
  • WebXR(VR/AR)体验

关键特性:

  • BufferGeometry / ShaderMaterial
  • OrbitControls / FlyControls 相机控制
  • 光照系统:Ambient / Directional / Point / Spot
  • 后期处理(EffectComposer)
  • React Three Fiber(React 封装)

安装

环境准备

  • 操作系统:Windows / macOS / Linux 均可
  • Node.js:>= 18.x(推荐 LTS 版本)
  • 包管理器:npm / yarn / pnpm 任选
  • 浏览器:Chrome 90+ / Firefox 90+ / Safari 15+(需支持 WebGL 2.0)
  • 编辑器:VS Code(推荐安装 GLSL 语法高亮插件)

安装命令

通过 npm 安装(推荐,配合构建工具使用)

# 创建项目
mkdir my-threejs-app &;& cd my-threejs-app
npm init -y

# 安装 Three.js
npm install three

# 安装开发依赖(可选,用于开发服务器)
npm install -D vite

通过 CDN 引入(快速原型)

<script type="importmap">
{
  "imports": {
    "three": "https://unpkg.com/three@0.160.0/build/three.module.js"
  }
}
</script>

通过 CDN(传统 script 标签)

<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>

常见安装问题

1. WebGL 不支持

  • 现象:浏览器报错 "WebGL is not supported"
  • 解决:检查浏览器 WebGL 支持状态:访问 chrome://gpu(Chrome)或 about:support(Firefox),确保 WebGL 状态为 "Hardware accelerated"

2. 模块导入报错

  • 现象Cannot use import statement outside a module
  • 解决:确保 script 标签设置 type="module",或使用打包工具(Vite/Webpack)处理

3. npm 安装慢

  • 解决:使用国内镜像 npm config set registry https://registry.npmmirror.com

4. TypeScript 类型报错

  • 解决:Three.js 自带类型定义,确保 tsconfig.jsonmoduleResolution 设置为 "bundler""node"

示例

Three.js 旋转地球仪

目标

用 Three.js 创建 3D 旋转地球仪:纹理贴图 + 星空粒子 + 鼠标交互旋转缩放。

完整代码

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>3D 地球仪</title>
  <style>
    body { margin: 0; overflow: hidden; background: #000; }
    canvas { display: block; }
    .info { position: fixed; bottom: 20px; left: 20px; color: white; font-family: system-ui; opacity: 0.7; }
  </style>
</head>
<body>
  <div class="info">🌍 拖拽旋转 · 滚轮缩放</div>

  <script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
    }
  }
  </script>

  <script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

    // 场景
    const scene = new THREE.Scene();

    // 相机
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 0, 4);

    // 渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    document.body.appendChild(renderer.domElement);

    // 控件
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.minDistance = 1.5;
    controls.maxDistance = 10;
    controls.autoRotate = true;
    controls.autoRotateSpeed = 0.5;

    // 星空粒子
    const starsGeom = new THREE.BufferGeometry();
    const starsCount = 2000;
    const positions = new Float32Array(starsCount * 3);
    for (let i = 0; i < starsCount * 3; i++) {
      positions[i] = (Math.random() - 0.5) * 30;
    }
    starsGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    const starsMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.02 });
    const stars = new THREE.Points(starsGeom, starsMat);
    scene.add(stars);

    // 地球
    const geometry = new THREE.SphereGeometry(1, 64, 64);

    // 使用纹理贴图(在线纹理)
    const textureLoader = new THREE.TextureLoader();
    const earthMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
    const earthSpec = textureLoader.load('https://threejs.org/examples/textures/planets/earth_specular_2048.jpg');
    const earthBump = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');

    const material = new THREE.MeshPhongMaterial({
      map: earthMap,
      specularMap: earthSpec,
      bumpMap: earthBump,
      bumpScale: 0.05,
      specular: new THREE.Color('grey'),
      shininess: 10,
    });

    const earth = new THREE.Mesh(geometry, material);
    scene.add(earth);

    // 光照
    const ambientLight = new THREE.AmbientLight(0x333333);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
    directionalLight.position.set(5, 3, 5);
    scene.add(directionalLight);

    // 动画循环
    function animate() {
      requestAnimationFrame(animate);
      stars.rotation.y += 0.0001;
      controls.update();
      renderer.render(scene, camera);
    }
    animate();

    // 响应式
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

运行步骤

  1. 复制代码保存为 index.html
  2. 用 Live Server 打开(纹理需要 HTTP 协议加载)
  3. 或用 npx serve . 启动

预期输出

  • 3D 地球自动缓慢旋转
  • 鼠标拖拽旋转视角,滚轮缩放
  • 背景星空粒子缓慢移动
  • 光照渲染立体效果(海洋有反光)

毕设扩展方向

  • 添加标记点(城市标注)
  • 实现点击高亮某国家
  • 接入数据展示全球分布
  • 做成校园 3D 导览的基底

Three.js Hello World — 旋转立方体

目标

创建一个带光照和旋转动画的 3D 立方体场景,这是 Three.js 最经典的入门示例。

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Three.js 旋转立方体</title>
  <style>
    body { margin: 0; overflow: hidden; background: #000; }
    canvas { display: block; }
  </style>
</head>
<body>
  <script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.160.0/build/three.module.js"
    }
  }
  </script>

  <script type="module">
    import * as THREE from 'three';

    // ========== 1. 创建场景 ==========
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x1a1a2e);

    // ========== 2. 创建相机 ==========
    const camera = new THREE.PerspectiveCamera(
      75,                                    // 视野角度
      window.innerWidth / window.innerHeight, // 宽高比
      0.1,                                   // 近裁面
      1000                                   // 远裁面
    );
    camera.position.z = 5;

    // ========== 3. 创建渲染器 ==========
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    document.body.appendChild(renderer.domElement);

    // ========== 4. 创建立方体 ==========
    const geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);
    const material = new THREE.MeshStandardMaterial({
      color: 0x00ff88,
      roughness: 0.3,
      metalness: 0.1,
    });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    // ========== 5. 添加光源 ==========
    // 环境光(基础亮度)
    const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
    scene.add(ambientLight);

    // 方向光(产生阴影和立体感)
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
    directionalLight.position.set(5, 5, 5);
    scene.add(directionalLight);

    // ========== 6. 动画循环 ==========
    function animate() {
      requestAnimationFrame(animate);

      cube.rotation.x += 0.01;
      cube.rotation.y += 0.015;

      renderer.render(scene, camera);
    }

    animate();

    // ========== 7. 窗口自适应 ==========
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

运行步骤

  1. 将上述代码保存为 index.html
  2. 用浏览器直接打开(需通过 localhost 运行,或直接用 Live Server)
  3. 你将看到一个带光照的绿色立方体持续旋转

预期输出

  • 深色背景上显示一个绿色立方体
  • 立方体沿 X 和 Y 轴持续旋转
  • 有明暗面变化(光照效果)
  • 调整窗口大小时场景自适应

教程

Three.js 入门教程:从零构建 3D 场景

一、背景与概念

为什么需要 Three.js?

原生 WebGL API 极其冗长——仅画一个三角形就需要上百行代码。Three.js 对 WebGL 进行了优雅的抽象,让开发者能用面向对象的方式构建 3D 场景。它是目前 GitHub 上 Star 最多的 3D Web 库(100k+ stars),被广泛应用于产品展示、数据可视化、游戏和 AR/VR。

核心概念

Three.js 的世界观类似拍电影:

概念 类比 说明
Scene(场景) 舞台 容纳所有 3D 对象的容器
Camera(相机) 摄像机 决定观众看到什么,常用 PerspectiveCamera
Renderer(渲染器) 放映机 将场景通过相机渲染到 Canvas
Mesh(网格) 演员 由 Geometry(形状)+ Material(材质)组成
Light(光源) 灯光 没有光就看不到任何东西
Animation Loop 播放 每帧更新场景并重新渲染

二、分步操作

第一步:搭建项目骨架

使用 Vite 快速启动:

npm create vite@latest my-three-app -- --template vanilla
cd my-three-app
npm install three
npm run dev

main.js 中构建最小场景:

import * as THREE from 'three';

// 三大核心:场景 + 相机 + 渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

第二步:添加第一个物体

// Geometry(形状)+ Material(材质) = Mesh(网格物体)
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshPhongMaterial({ color: 0xff6600 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 必须有光!
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(2, 2, 5);
scene.add(light);

camera.position.z = 3;

第三步:渲染循环

function animate() {
  requestAnimationFrame(animate);  // 请求下一帧
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

第四步:丰富场景

添加多个物体和辅助工具:

// 坐标轴辅助(红=X, 绿=Y, 蓝=Z)
scene.add(new THREE.AxesHelper(3));

// 网格地面
const grid = new THREE.GridHelper(10, 10);
scene.add(grid);

// 球体
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(0.5, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0x4488ff, roughness: 0.2, metalness: 0.8 })
);
sphere.position.x = -2;
scene.add(sphere);

第五步:响应用户交互

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 开启惯性
controls.dampingFactor = 0.05;

function animate() {
  requestAnimationFrame(animate);
  controls.update(); // 必须在 render 前更新
  renderer.render(scene, camera);
}

三、常用 Geometry 速查

Geometry 用途
BoxGeometry(w, h, d) 立方体/盒子
SphereGeometry(r, segW, segH) 球体
CylinderGeometry(rT, rB, h, seg) 圆柱/圆锥
PlaneGeometry(w, h) 平面
TorusGeometry(r, tube, radSeg, tubSeg) 圆环
BufferGeometry 自定义几何体(高性能)

四、常用 Material 速查

Material 特性 需要光照
MeshBasicMaterial 不受光影响,纯色
MeshStandardMaterial PBR 物理渲染(推荐)
MeshPhongMaterial 经典 Blinn-Phong 光照
MeshNormalMaterial 法线可视化(调试用)
MeshToonMaterial 卡通风格

五、思考题

  1. 如何让立方体沿着圆形轨迹运动?(提示:用三角函数修改 position 而非 rotation)
  2. renderer.setPixelRatio 设为 devicePixelRatio 的作用是什么?何时应降低它?
  3. 如果场景中有 10000 个立方体,如何优化性能?(提示:InstancedMesh)

Three.js 3D可视化毕设入门

背景

Three.js 是浏览器端 3D 渲染的事实标准。毕设中如果能加入 3D 元素——产品 3D 展示、校园导览、数据可视化地球、虚拟展厅——会立刻让项目档次提升。Three.js 屏蔽了 WebGL 的复杂性,前端开发者无需学 OpenGL 也能做 3D。


核心概念

三要素

Scene (场景)  → 容納所有 3D 物体
Camera (相机) → 观察视角
Renderer (渲染器) → 绘制到屏幕
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, w/h, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

四大组件

组件 说明 示例
Geometry 形状 Box, Sphere, Cylinder, BufferGeometry
Material 材质 MeshBasic, MeshPhong, MeshStandard
Light 光照 Ambient, Directional, Point, Spot
Controls 交互 OrbitControls, FlyControls

分步操作

第一步:引入 Three.js

npm install three
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

第二步:创建第一个立方体

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshPhongMaterial({ color: 0x3b82f6 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 别忘了加光照
scene.add(new THREE.AmbientLight(0x404040));
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);

第三步:添加交互

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.autoRotate = true;

第四步:加载 3D 模型

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
loader.load('/models/building.glb', (gltf) => {
  scene.add(gltf.scene);
});

毕设推荐场景

校园 3D 导览

Blender 建模校园建筑 → glTF 导出 → Three.js 加载 → OrbitControls 漫游。

产品 3D 展示

商品 360 度旋转查看,支持缩放和材质切换。

数据可视化

3D 柱状图、3D 地图、3D 粒子效果。

虚拟展厅

COVID 期间流行的线上展厅,三维空间展示作品。


思考题

  1. PerspectiveCamera 和 OrthographicCamera 的区别?各自适用场景?
  2. 为什么需要光照?MeshBasicMaterial 和 MeshStandardMaterial 的区别?
  3. 加载大型 3D 模型时如何优化性能?

小结

Three.js 是毕设的"视觉杀手锏"。一个带 3D 元素的毕设项目,在答辩演示时视觉冲击力远超传统 2D 页面。

参考资料

  1. [1] Three.js Contributors. Three.js Documentation. 2024. https://threejs.org/docs
  2. [2] Lewy Blue. Discover Three.js. 2023.
  3. [3] Kouichi Matsuda, Rodger Lea. WebGL Programming Guide. 2013.
  4. [4] Patricio Gonzalez Vivo. The Book of Shaders. 2023. https://thebookofshaders.com
  5. [5] Three.js 团队. Three.js 官方文档. 2024. https://threejs.org/docs/
  6. [6] Greggman. Three.js Fundamentals. 2024. https://threejsfundamentals.org/
  7. [7] Lewy Blue. Discover Three.js. 2022. https://discoverthreejs.com/