Three.js 简介与快速上手
🎯 引言
学完这篇文章,你能明白 Three.js 是什么、它和我们学过的 ECharts、D3 有什么区别,认识 Three.js 的三大件:场景、相机、渲染器。最后我们会在 Vue3 项目中安装 Three.js,在浏览器里渲染出第一个 3D 立方体。
🧱 什么是 Three.js
Three.js 是一个运行在浏览器里的 3D 绘图引擎,它把底层的 WebGL 封装成简单易懂的 API。
WebGL 是浏览器原生的 3D 绘图接口,能力强大但写起来非常繁琐:画一个三角形就要写上百行代码,还要处理着色器、缓冲区这些偏计算机图形学的概念。
打个比方:WebGL 像汽车的发动机,Three.js 像造好的整车。我们不用研究发动机原理,直接开车就行。画一个立方体,Three.js 只需要几行代码。
⚖️ 和 ECharts、D3 怎么分工
前面学过的 ECharts、D3 都是 2D 可视化工具,画的图表是平面的。Three.js 画的是 3D 场景,有前后远近的空间感,这是它们的本质区别。
| 对比 | ECharts / D3 | Three.js |
|---|---|---|
| 维度 | 2D 平面 | 3D 空间 |
| 底层技术 | SVG / Canvas | WebGL |
| 典型产物 | 柱状图、折线图 | 产品 3D 展示、3D 大屏、网页游戏 |
| 上手难度 | 低到中 | 较高 |
🚀 安装 Three.js
当前课程环境使用 Node.js v22.0.0,安装的 Three.js 版本为 0.185.1。在 Vite 创建的 Vue3 项目中,执行:
npm install three
在代码中引入:
import * as THREE from 'three';
THREE 是官方约定的命名空间,场景、相机、几何体等所有类都挂在它下面。
🧱 三大件:场景、相机、渲染器
任何一个 Three.js 画面,都少不了三个角色。用拍电影来理解就很好懂:
- 场景(Scene):摄影棚,演员、道具、灯光全都放进去。
- 相机(Camera):摄像机,决定观众从哪个角度、看到哪块范围。
- 渲染器(Renderer):放映机,把相机拍到的画面投到屏幕上(也就是网页的
<canvas>上)。
少了场景没东西可拍,少了相机不知道看哪,少了渲染器观众看不到画面。三者配合的流程是固定的:
创建场景 → 往场景里放东西(物体、灯光)→ 架好相机 → 渲染器拍照并输出画面
🛠 第一个 3D 场景
目标:在页面上渲染一个绿色的立方体。
<template>
<div ref="containerRef" class="container"></div>
</template>
<script setup>
import { onMounted, ref } from 'vue';
import * as THREE from 'three';
const containerRef = ref(null);
onMounted(() => {
// 1. 创建场景(摄影棚)
const scene = new THREE.Scene();
// 2. 创建相机(摄像机):透视相机,四个参数后面篇章详解
const camera = new THREE.PerspectiveCamera(75, 320 / 240, 0.1, 1000);
camera.position.z = 5; // 相机往后退 5 个单位,否则贴着物体看不清
// 3. 创建立方体:几何体(形状)+ 材质(皮肤)= 网格(演员)
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
cube.rotation.set(0.6, 0.8, 0); // 转个角度,才能看出立体感
scene.add(cube);
// 4. 加两盏灯:环境光打底 + 平行光制造明暗(灯光后面篇章详解)
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
directionalLight.position.set(3, 5, 4);
scene.add(directionalLight);
// 5. 创建渲染器(放映机),设置画幅大小后挂到页面上
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(320, 240);
containerRef.value.appendChild(renderer.domElement);
// 6. 拍照:把相机看到的场景画到 canvas 上
renderer.render(scene, camera);
});
</script>
<style scoped>
.container {
width: 320px;
height: 240px;
}
</style>
这段代码有点长,但结构就是上面说的固定流程,记住这个对应关系:
| 代码 | 拍电影的对应物 |
|---|---|
new THREE.Scene() | 摄影棚 |
BoxGeometry + MeshStandardMaterial + Mesh | 演员(立方体) |
AmbientLight / DirectionalLight | 摄影棚的灯光 |
new THREE.PerspectiveCamera() | 摄像机 |
new THREE.WebGLRenderer() | 放映机 |
renderer.render(scene, camera) | 按下快门 |
有几个细节说明一下:
BoxGeometry(1, 1, 1)创建的是宽、高、深都是 1 的立方体。Three.js 里的单位不是像素,是抽象的空间单位,显示大小全靠相机距离衬托。cube.rotation.set(0.6, 0.8, 0)让立方体绕 x、y 轴各转一点。正对着相机看立方体只是一个正方形,转个角度才有立体感。MeshStandardMaterial是一种“靠灯光才能显形”的材质,加了灯之后朝向光的面亮、背光的面暗,立体感就出来了。材质和灯光分别在第 2、3 篇详解。renderer.domElement就是渲染器创建好的<canvas>标签,我们需要手动把它挂到容器里。
下面是这段代码在页面上的真实渲染效果:
- Three.js 代码必须放在
onMounted里执行,这时容器才真实存在于页面上。 - 画面是纯黑看不到物体时,先检查是不是用了 Standard 材质却忘了加灯光。
renderer.setPixelRatio(window.devicePixelRatio) 就能变清晰。它不影响布局尺寸,可以放心加上。🧾 小节总结
- Three.js 是浏览器里的 3D 绘图引擎,封装了底层 WebGL。
- 平面图表选 ECharts/D3,立体空间效果选 Three.js。
- 三大件:场景(摄影棚)、相机(摄像机)、渲染器(放映机)。
- 物体 = 几何体(形状)+ 材质(皮肤),组合成 Mesh 后用
scene.add()放进场景。 - 固定流程:建场景 → 放物体和灯光 → 架相机 →
renderer.render(scene, camera)拍照。 - 使用
npm install three安装,课程基于 Node.js v22.0.0 和 Three.js 0.185.1。
❓ 知识问答
Q1:Three.js 收费吗?
完全免费。它基于 MIT 开源协议发布,个人和公司都可以免费商用。
Q2:学 Three.js 需要先学 WebGL 吗?
不需要。Three.js 已经把 WebGL 封装好了,直接学 Three.js 即可。等以后要写自定义着色器时,再补 WebGL 基础也不迟。
Q3:颜色为什么写成 0x44aa88 而不是 '#44aa88'?
0x 是十六进制数字的写法,Three.js 的颜色参数默认接收数字。字符串 '#44aa88' 在多数情况也能识别,课程统一用官方示例的数字写法。
Q4:renderer.render() 只调用一次,画面会动吗?
不会,它只是拍了一张静态照片。想让画面动起来需要“渲染循环”,动画篇会专门讲解。
🧪 小练习
在第一个场景的基础上完成改造:
- 把立方体的颜色改成你喜欢的颜色。
- 把立方体尺寸改成宽 2、高 1、深 1 的长方体,观察形状变化。
- 把
camera.position.z分别改成 3 和 8,感受相机远近对画面大小的影响。
<template>
<div ref="containerRef" class="container"></div>
</template>
<script setup>
import { onMounted, ref } from 'vue';
import * as THREE from 'three';
const containerRef = ref(null);
onMounted(() => {
// 请在这里编写代码
});
</script>
<style scoped>
.container {
width: 320px;
height: 240px;
}
</style>
🎉 恭喜你已经渲染出第一个 3D 场景了!下一篇我们来认识更多几何体和材质,让场景里的演员丰富起来。
