Three.js 入门系列(7):让甜甜圈围着我转 —— 3D文字生成

时隔一个多月,我重新打开了 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 的付费课程)的学习笔记,代码为个人练习所写,概念讲解融入了个人的理解和比喻。

相关推荐
gitboyzcf1 小时前
mpegts.js解决Chrome无法播放7568×142分辨率报错 DOMException问题
前端·后端
yio_yin1 小时前
MyBatis
java·前端·mybatis
棒棒的唐1 小时前
非常棒的向量数据库chroma的前端管理工具及向量模型配置
前端
芭拉拉小魔仙2 小时前
前端文件下载与错误处理实战指南
前端
Yao8063 小时前
MinIO自建对象存储,省OSS费用的完整方案
前端·后端
2501_933923253 小时前
设计网页的时候加载不出来怎么办?认识常见的状态码
前端·spring
only-lucky3 小时前
QML深入学习五(Controls模块)
前端·javascript·学习
程序员黑豆3 小时前
鸿蒙应用开发之路由:Router 页面路由使用教程
前端·harmonyos
gyx_这个杀手不太冷静3 小时前
Agent开发进阶指南(第 2 章):Agent 运行全流程拆解、上下文窗口、流式输出、记忆系统与 Function Call 实战
前端·架构·agent