时隔一个多月,我重新打开了 Three.js 编辑器。今天来做 3D 文字,并在周围散布 100 个甜甜圈。
效果预览

接下来我会从7个方面仔细讲解制作的流程,跟我一起来吧!
1.引入文字加载器
我们需要认识两个Three.js 官方示例里的扩展模块: 1.FontLoader:专门加载字体文件(.typeface.json--这个是一种字体格式)的加载器。
2.TextGeometry:根据字体数据生成文字形状的几何体。
那FontLoader 和 TextGeometry 究竟是什么?
生活比喻:做饼干
想象你要做一批字母饼干:
- FontLoader 是饼干模具的图纸------它告诉系统"字母A应该长什么样、B应该长什么样"
- TextGeometry 是压模的动作------用图纸把面团压成字母形状
- 两者配合,才能做出真正的字母饼干
javascript
js
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'
注意:两个模块都需要单独引入
小贴士:Three.js 核心库(three)只包含最基础的功能------场景、相机、渲染器、几何体、材质等。这些是"地基"。
但是文字生成 不是所有3D场景都需要的功能,所以 Three.js 团队把它放在 examples/jsm/ 目录下,作为"扩展包"提供。你需要的时候再单独导入。
2.创建文字加载器
这个非常简单,只需:
arduino
const fontLoader = new FontLoader()
和纹理加载器(TextureLoader)类似,字体加载器也是用来异步加载外部资源的。
3.加载字体 + 创建文字
less
js
fontLoader.load(
'/fonts/helvetiker_regular.typeface.json', // ① 字体文件路径
(font) => { // ② 加载完成的回调函数
const textGeometry = new TextGeometry(
'King Yueyue!', // ③ 要显示的文字
{ // ④ 文字配置参数
font: font,
size: 0.5,
depth: 0.2,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegments: 3
}
)
// 后续处理:居中、材质、添加到场景
}
)
① 字体文件路径:'/fonts/helvetiker_regular.typeface.json'
这是字体数据文件的位置。helvetiker_regular 是 Three.js 官方提供的默认字体(Helvetica 的变体),.typeface.json 是一种特殊的 JSON 格式,包含了字体的轮廓数据------也就是"每个字母由哪些点和曲线组成"。
② 回调函数:(font) => { ... }
fontLoader.load() 是异步的------加载字体文件需要时间(从服务器读取文件)。回调函数会在字体加载完成后执行,font 参数就是加载好的字体数据。
④ 文字配置参数(这里是重点)
| 参数 | 说明 | 示例值 | 生活比喻 |
|---|---|---|---|
font |
加载好的字体数据 | font |
选定了"什么字体"(黑体/宋体/楷体) |
size |
文字大小 | 0.5 |
字号大小(相当于Word里的字号) |
depth |
文字的厚度(Z轴方向) | 0.2 |
字母的"高度",像浮雕凸起多少 |
curveSegments |
曲线平滑度 | 4 |
字母边缘的分段数,越高越平滑 |
bevelEnabled |
是否启用倒角 | true |
字母边缘是否做圆角处理 |
bevelThickness |
倒角的厚度 | 0.03 |
边缘圆角的"宽度" |
bevelSize |
倒角的大小 | 0.02 |
边缘圆角的"深度" |
bevelOffset |
倒角偏移 | 0 |
倒角位置偏移(一般不动) |
bevelSegments |
倒角分段数 | 3 |
圆角过渡的平滑度 |
关于 bevel(倒角)的直观理解
javascript
arduino
bevelEnabled: true // 开圆角
bevelThickness: 0.03 // 圆角有多厚
bevelSize: 0.02 // 圆角有多大
三个参数分别控制什么?
1. bevelEnabled: true ------ 要不要开倒角?
true = 字母边缘做圆角处理(推荐,看起来更精致)
false = 字母边缘是锐利的直角(硬边风格)

2. bevelThickness: 0.03 ------ 倒角延伸了多远
这个参数控制的是:圆角从边缘往内部走了多少距离。
3. bevelSize: 0.02 ------ 倒角向上走了多高
这个参数控制的是:圆角从底部往上延伸了多少距离。
以上两个参数同时增加的话,这个圆角会变的很大,很圆,就好像桌角被打磨成一个光滑的圆角一样。
当前的值(前面有相关代码):

当我给一个大一些的值:
yaml
bevelEnabled: true,
bevelThickness: 0.09,
bevelSize: 0.09,

通过以上的对比可以看出,当这两个数值增加的时候,圆角看起来弧度更大,同时你也可以只增加其中一个值。
4. 居中(重点)
TextGeometry 生成的文字,默认原点在左下角,需要把它移到中心。
如果我们肉眼看不清楚具体的中心在哪里,可以借助之前学习的坐标轴辅助器(axesHelper)
csharp
//坐标轴
const axesHelper = new THREE.AxesHelper()
scene.add(axesHelper)
居中方法我们直接使用内置方法,一行代码,自动居中。简单直接,建议用这个。
markdown
textGeometry.center()

直接居中了,节约了非常多的时间。
5.赋予材质
终于来到最好玩步骤之一,我们使用的材质依旧是之前代码中出现过的,这里用了 Matcap 材质(纹理贴图模拟光照),不需要添加光源就能有立体感。
MeshMatcapMaterial 是什么?
一句话解释:
Matcap(Material Capture,材质捕获)是一种"假光照"技术------用一张贴图模拟光照效果,不需要在场景里添加任何光源,物体就有立体感,就像日常拍照喜欢添加滤镜一样,不需要真实的光源就可以让照片拥有质感,Matcap就是3d世界的"光照滤镜"。
arduino
/**
* Textures创建纹理加载器,加载所需纹理
*/
const textureLoader = new THREE.TextureLoader()
const matcapTexture = textureLoader.load('/textures/matcaps/8.png')
//把纹理涂在文字上,文字出现在场景中
const material = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })
const text = new THREE.Mesh(textGeometry, material)
scene.add(text)
可以看到文字拥有一种光泽,柔和的陶瓷或塑料质感。

6. 创建甜甜圈(装饰元素)
arduino
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)
TorusGeometry 是什么?
一句话解释:
TorusGeometry 是 Three.js 用来生成"甜甜圈"形状(数学上叫圆环体)的几何体。它像一个被拉圆的游泳圈,或者一个饱满的甜甜圈。
四个参数详解
arduino
new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments)
// ↑ ↑ ↑ ↑
// 主半径 管道半径 径向分段数 管状分段数
radius(0.3):甜甜圈整体大小,从中心到管道的距离tube(0.2):甜甜圈的粗细,管道半径radialSegments(20):环绕圈数的分段数,值越大越圆滑tubularSegments(45):管道截面的分段数,值越大横截面越圆
这四个值一起决定了甜甜圈的胖瘦、大小和光滑程度。我用的这组数值做出来就是比较饱满圆润的效果,看着挺好吃的。
7. 调整甜甜圈的位置、旋转、大小
用循环生成 100 个甜甜圈,每个都随机分布:
ini
for(let i = 1; i < 100; i++) {
const donut = new THREE.Mesh(donutGeometry, material)
// 位置随机(范围 -5 到 5)
donut.position.x = (Math.random() - 0.5) * 10
donut.position.y = (Math.random() - 0.5) * 10
donut.position.z = (Math.random() - 0.5) * 10
// 旋转随机(0 到 180度)
donut.rotation.x = Math.random() * Math.PI
donut.rotation.y = Math.random() * Math.PI
// 缩放随机(0 到 1 之间)
const scale = Math.random()
donut.scale.set(scale, scale, scale)
scene.add(donut)
}
至于我们为什么要调整这些参数,就是想把甜甜圈分散开来,文字是主角,甜甜圈是气氛组。100个随机洒在周围,有大有小、转得乱七八糟,画面就不那么死板了。主要是让场景看着热闹一点,不然就几个字母杵在那儿太孤单了。

总结
今天搞了三件事:加载字体、生成文字、洒了100个甜甜圈当气氛组。
文字是主角,甜甜圈是群演,随机洒在周围,让画面看着热闹不孤单。TextGeometry 的参数调一调能玩出不少花样,matcap 材质也省去了打光的麻烦。
虽然就是个简单的3D文字,但加上甜甜圈之后,场景就变得不那么死板了。你可以换文字内容、换字体、换装饰物,或者寻找一些可以使用的matcap材质进行切换,甚至把甜甜圈换成别的东西------发挥空间还挺大的。
📚 本文是学习 Three.js Journey(Bruno Simon 的付费课程)的学习笔记,代码为个人练习所写,概念讲解融入了个人的理解和比喻。