文档
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 |
卡通风格 | 是 |
五、思考题
- 如何让立方体沿着圆形轨迹运动?(提示:用三角函数修改 position 而非 rotation)
renderer.setPixelRatio设为devicePixelRatio的作用是什么?何时应降低它?- 如果场景中有 10000 个立方体,如何优化性能?(提示:InstancedMesh)