Three.js 是一个基于 WebGL 的 JavaScript 3D 图形库。它把复杂的底层 GPU 编程封装成简洁的 API,让前端开发者也能轻松创建 3D 场景,而不需要掌握晦涩的图形学知识。
一、Three.js 能做什么?
- 数字孪生:工厂、城市、机房的三维可视化
- 产品展示:360° 旋转查看商品
- 数据大屏:三维地图、粒子效果
- Web 游戏:轻量级 3D 游戏
- 建筑可视化:BIM 模型在线浏览
- 科学仿真:卫星轨道、导航轨迹展示
二、核心概念:3D 场景的组成
在写代码之前,先理解 Three.js 的三个核心概念:
场景(Scene)
相当于摄影棚,所有东西都放在这里
场景是一个容器,3D 物体、光源等都需要被添加到场景中才能被渲染。
相机(Camera)
相当于摄像机,决定你从哪个角度看场景
最常用的是透视相机(PerspectiveCamera),模拟人眼的透视效果(近大远小)。参数包括视角(FOV)、宽高比、近裁剪面、远裁剪面。
渲染器(Renderer)
相当于后期制作,把场景和相机的信息输出成画面
WebGLRenderer 负责把 3D 场景渲染到 HTML 的 <canvas> 元素上,最终显示在页面中。
三、搭建第一个 3D 场景
我们来渲染一个旋转的绿色立方体,这是 Three.js 的 Hello World。
第一步:引入 Three.js
可以通过 CDN 引入:
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; }
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';
// 后续代码写在这里
</script>
</body>
</html>
第二步:创建场景、相机、渲染器
// 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; // 相机往后退 5 个单位,才能看到原点处的物体
// 3. 创建渲染器,挂载到页面
const renderer = new THREE.WebGLRenderer({ antialias: true }); // antialias: 抗锯齿
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); // 把 canvas 添加到页面
第三步:创建几何体
Three.js 中一个可见的物体由两部分组成:
- Geometry(几何体):定义形状(顶点、面)
- Material(材质):定义外观(颜色、贴图、光照反应)
两者结合,创建 Mesh(网格体) 并添加到场景:
// 创建一个 1x1x1 的立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建材质:MeshBasicMaterial 不受光照影响,颜色始终可见
const material = new THREE.MeshBasicMaterial({ color: 0x00ff88 });
// 合并为网格体
const cube = new THREE.Mesh(geometry, material);
// 添加到场景
scene.add(cube);
第四步:动画循环
Three.js 的动画原理是利用浏览器的 requestAnimationFrame,每帧更新物体状态并重新渲染:
function animate() {
requestAnimationFrame(animate); // 告诉浏览器下一帧继续调用 animate
// 每帧让立方体旋转一点
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染这一帧
renderer.render(scene, camera);
}
animate(); // 启动动画循环
到这里,你应该能看到一个旋转的绿色立方体了。
四、让场景更真实:加入光照
MeshBasicMaterial 不受光照影响,永远是纯色。换成 MeshStandardMaterial,加上灯光,立方体就有了立体感:
// 换成标准材质(受光照影响)
const material = new THREE.MeshStandardMaterial({ color: 0x00ff88 });
// 添加环境光(均匀照亮整个场景,防止背光面全黑)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 颜色, 强度
scene.add(ambientLight);
// 添加方向光(模拟太阳光,有方向,会产生阴影)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5); // 光源位置
scene.add(directionalLight);
五、常用几何体速览
Three.js 内置了很多几何体,直接拿来用:
// 球体:半径, 水平分段数, 垂直分段数(数值越大越圆滑)
const sphere = new THREE.SphereGeometry(1, 32, 32);
// 圆柱体:顶部半径, 底部半径, 高度, 分段数
const cylinder = new THREE.CylinderGeometry(0.5, 0.5, 2, 32);
// 平面:宽, 高
const plane = new THREE.PlaneGeometry(10, 10);
// 圆环体(甜甜圈形):主半径, 管道半径
const torus = new THREE.TorusGeometry(1, 0.3, 16, 100);
六、鼠标控制旋转:OrbitControls
静态场景加上 OrbitControls,用户可以用鼠标旋转、缩放、平移视角:
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 惯性阻尼,松开鼠标后慢慢停下
// 在动画循环里更新控制器
function animate() {
requestAnimationFrame(animate);
controls.update(); // 必须在每帧调用
renderer.render(scene, camera);
}
七、完整代码汇总
<!DOCTYPE html>
<html>
<head>
<style>body { margin: 0; } canvas { display: block; }</style>
</head>
<body>
<script type="importmap">
{ "imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/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();
scene.background = new THREE.Color(0x1a1a2e);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 立方体
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x00ff88 })
);
scene.add(cube);
// 灯光
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
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;
// 动画循环
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.005;
cube.rotation.y += 0.005;
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>
总结
| 概念 | 作用 | 类比 |
|---|---|---|
| Scene | 场景容器 | 摄影棚 |
| Camera | 观察视角 | 摄像机 |
| Renderer | 渲染输出 | 后期制作 |
| Geometry | 几何形状 | 骨架 |
| Material | 外观材质 | 皮肤/涂料 |
| Mesh | 可见物体 | 骨架+皮肤的组合 |
| Light | 光源 | 灯光 |