在 Web 技术飞速发展的今天,3D 可视化不再是桌面应用的专属领域。随着 WebGL 技术的成熟和硬件性能的提升,浏览器已经能够渲染出令人惊叹的 3D 场景。而 Three.js 作为 WebGL 领域最流行、最成熟的 JavaScript 库,极大地降低了 3D 开发的门槛,让开发者能够无需深入了解复杂的图形学原理,就能在网页中创建和展示 3D 内容。
从产品展示、数据可视化到虚拟展厅、元宇宙应用,Three.js 的应用场景日益广泛,不断拓展着 Web 的边界。截止 2026 年,Three.js 在 GitHub 上已拥有超过 10 万 Star,周下载量超过 200 万次,是 Web 3D 开发领域当之无愧的王者。
本文将系统全面地梳理 Three.js 的核心知识点,从其核心概念到场景搭建,从基础几何体到高级动画,帮助读者建立完整的 3D 开发知识体系。
一、Three.js 概述
1.1 什么是 Three.js
Three.js 是一个基于原生 WebGL 的 JavaScript 3D 库,它对 WebGL API 进行了高度封装,提供了一套简洁、易用的面向对象接口。简单来说,Three.js 让开发者能够用几行代码就能在网页中创建 3D 场景,而无需深入了解着色器语言(GLSL)和复杂的图形学原理。
Three.js 的核心理念可以概括为三个关键词:
1.2 Three.js 的适用场景
得益于其强大的功能和活跃的社区,Three.js 已经被广泛应用于多种领域:
1.3 Three.js 的核心组成
一个最基本的 Three.js 3D 场景需要三大核心组件:
场景(Scene):一个容器,用于存放所有的物体、光源和相机。它就像是一个舞台,演员和设备都在上面。
相机(Camera):决定我们从哪个角度观察场景。Three.js 提供了多种相机,最常用的是透视相机(PerspectiveCamera),它能模拟人眼看到的“近大远小”效果。
渲染器(Renderer):负责将场景和相机结合起来,并把最终图像绘制到浏览器中。Three.js 最常用的是 WebGL 渲染器(WebGLRenderer)。
除了这三大核心组件,一个完整的 3D 场景通常还包括:
物体(Mesh):我们想要展示的 3D 对象,由几何体(Geometry)和材质(Material)组成。
光源(Light):照亮物体,产生明暗和阴影效果,让物体看起来有立体感。
动画(Animation):让场景中的物体动起来,构成完整的 3D 交互体验。
辅助工具(Helpers):辅助调试的工具,如坐标轴辅助器(AxesHelper)、光源辅助器(LightHelper)等。
二、环境搭建与第一个3D场景
2.1 使用 CDN 快速引入(推荐)
最简单入门的引入方式,适合快速原型开发:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Three.js 第一个场景</title>
<style>
body { margin: 0; overflow: hidden; }
#info {
position: absolute;
top: 20px;
left: 20px;
color: white;
background: rgba(0,0,0,0.6);
padding: 10px;
font-family: Arial;
pointer-events: none;
z-index: 100;
}
</style>
</head>
<body>
<div id="info">Three.js 入门示例 - 旋转立方体</div>
<!-- 使用 ES Modules 方式引入 Three.js 核心库及扩展 -->
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.128.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/"
}
}
</script>
<script type="module">
// 代码将在后续章节详细讲解
</script>
</body>
</html>
2.2 使用 npm 安装(工程化项目)
对于大型项目,推荐使用 npm 安装:
npm install three
在项目中导入并使用:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
2.3 第一个完整 3D 场景代码解析
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// ========== 1. 创建场景(Scene)==========
// 场景是一个容器,用来放置所有物体、光源和相机。
const scene = new THREE.Scene();
// 设置场景背景色为深灰色(接近黑色)
scene.background = new THREE.Color(0x111122);
// ========== 2. 创建相机(Camera)==========
// 使用透视相机,参数:视野角度FOV、宽高比、近平面、远平面
// - 视野角度:75度,人眼模拟效果最佳
// - 宽高比:窗口宽度 / 窗口高度
// - 近平面:0.1,相机能看到的最小距离
// - 远平面:1000,相机能看到的最大距离
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 将相机向后移动 5 个单位,以便看到场景中的物体
camera.position.set(0, 2, 5);
// 让相机看向原点 (0,0,0)
camera.lookAt(0, 0, 0);
// ========== 3. 创建渲染器(Renderer)==========
// WebGLRenderer 是 Three.js 中最常用的渲染器,使用浏览器的 WebGL API 进行硬件加速渲染。
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 设置渲染器尺寸为窗口的完整尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 启用阴影映射,让物体可以投射和接收阴影(性能开销较大,按需开启)
renderer.shadowMap.enabled = true;
// 将渲染器的 DOM 元素(canvas)添加到页面的 body 中
document.body.appendChild(renderer.domElement);
// ========== 4. 添加轨道控制器(OrbitControls)==========
// 轨道控制器允许用户通过鼠标/触摸来旋转、缩放和平移场景,极大提升交互体验。
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 启用惯性效果,让运动更平滑
controls.dampingFactor = 0.05; // 惯性系数
controls.zoomSpeed = 1.2; // 缩放速度
controls.rotateSpeed = 1.0; // 旋转速度
// ========== 5. 创建物体 ==========
// 几何体:创建一个长方体,宽 1,高 1,深 1
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 材质:创建标准网格材质,颜色为橙色,并启用阴影
const material = new THREE.MeshStandardMaterial({
color: 0xff6600,
roughness: 0.3, // 粗糙度,值越小表面越光滑
metalness: 0.7 // 金属感,值越高越像金属
});
// 将几何体和材质组合成网格对象
const cube = new THREE.Mesh(geometry, material);
// 设置立方体的位置
cube.position.set(0, 0.5, 0);
// 启用阴影投射和接收
cube.castShadow = true;
cube.receiveShadow = true;
// 将物体添加到场景中
scene.add(cube);
// ========== 6. 添加地板平面(用于展示阴影)==========
const planeGeometry = new THREE.PlaneGeometry(5, 5);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x888888, side: THREE.DoubleSide });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2; // 旋转使其水平放置
plane.position.y = -0.5;
plane.receiveShadow = true; // 接收阴影
scene.add(plane);
// ========== 7. 添加光源 ==========
// 环境光:均匀照亮所有物体,没有方向性,避免阴影区域完全黑暗
const ambientLight = new THREE.AmbientLight(0x404060);
scene.add(ambientLight);
// 点光源:从一点向四周发光的灯泡效果
// 参数:颜色、强度
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(2, 3, 4);
pointLight.castShadow = true;
scene.add(pointLight);
// 辅助光源:从侧面补充照明,增强立体感
const fillLight = new THREE.PointLight(0x4466cc, 0.5);
fillLight.position.set(-2, 1, 3);
scene.add(fillLight);
// ========== 8. 添加辅助工具(调试用)==========
// 添加坐标轴辅助器(红色X轴,绿色Y轴,蓝色Z轴)
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 添加光源位置辅助器(帮助调试光源位置)
const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.3);
scene.add(pointLightHelper);
// ========== 9. 动画循环 ==========
// 使用 requestAnimationFrame 实现流畅的动画效果
function animate() {
// 更新立方体旋转角度(每帧旋转 0.01 弧度)
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 更新轨道控制器(必须在动画循环中调用,以启用 damping 效果)
controls.update();
// 渲染场景:使用相机视角渲染整个场景
renderer.render(scene, camera);
// 请求下一帧动画
requestAnimationFrame(animate);
}
// 启动动画循环
animate();
// ========== 10. 处理窗口尺寸变化 ==========
// 当浏览器窗口大小改变时,需要更新相机的宽高比和渲染器的尺寸
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
// 更新相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix(); // 更新相机的投影矩阵
// 更新渲染器的尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
}