Three.js

Three.js 简介与快速上手

了解 Three.js 是什么、它和 ECharts/D3 的区别,认识场景、相机、渲染器三大件,在浏览器里渲染出第一个 3D 立方体。

🎯 引言

学完这篇文章,你能明白 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 / D3Three.js
维度2D 平面3D 空间
底层技术SVG / CanvasWebGL
典型产物柱状图、折线图产品 3D 展示、3D 大屏、网页游戏
上手难度低到中较高
选型建议:平面图表用 ECharts/D3,需要立体空间效果才用 Three.js。比如商品 360° 展示、3D 机房监控、数据地球这类需求,就是 Three.js 的主场。

🚀 安装 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 场景

目标:在页面上渲染一个绿色的立方体。

views/FirstScene.vue
<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> 标签,我们需要手动把它挂到容器里。

下面是这段代码在页面上的真实渲染效果

两个容易踩的坑:
  1. Three.js 代码必须放在 onMounted 里执行,这时容器才真实存在于页面上。
  2. 画面是纯黑看不到物体时,先检查是不是用了 Standard 材质却忘了加灯光。
在高分屏(如 Mac 的 Retina 屏)上画面可能有点模糊,加一行 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() 只调用一次,画面会动吗?

不会,它只是拍了一张静态照片。想让画面动起来需要“渲染循环”,动画篇会专门讲解。


🧪 小练习

在第一个场景的基础上完成改造:

  1. 把立方体的颜色改成你喜欢的颜色。
  2. 把立方体尺寸改成宽 2、高 1、深 1 的长方体,观察形状变化。
  3. camera.position.z 分别改成 3 和 8,感受相机远近对画面大小的影响。
views/MyScene.vue
<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 场景了!下一篇我们来认识更多几何体和材质,让场景里的演员丰富起来。