Threejs之认识一下TextGeometry,学习如何创建三维字体

128 阅读5分钟

之前已经用Threejs在三维世界里面创建了很多模型,那么有个疑问来了,三维世界中能否拿来写字呢?后来去查了一下发现是可以的,那么今天就来试一下Threejs里面的三维文本--TextGeometry

TextGeometry

首先如果想要创建TextGeometry的话,不能在Threejs的标准库里面找,得额外的导入进来

import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";

其次,细心的朋友可能已经发现了,TextGeometry它其实就是ExtrudeGeometry的子类,这个意味着它也是有一个二维图形拉伸成为三维图形的,ExtrudeGeometry的属性一样适用于TextGeometry,不记得的可以先去复习一下,现在我们就来创建三维文本,有过前端开发经验的朋友肯定知道,如果需要显示一个文本,那么必须得有个字体,Threejs里面也是一样,第一步就是去加载字体,这里用到了FontLoader这个类,使用下面这行代码导入进来

import { FontLoader } from "three/examples/jsm/loaders/FontLoader";

FontLoader使用load函数去加载字体

export class FontLoader extends Loader<Font> {
    constructor(manager?: LoadingManager);

    load(
        url: string,
        onLoad?: (data: Font) => void,
        onProgress?: (event: ProgressEvent) => void,
        onError?: (err: unknown) => void,
    ): void;

    parse(json: FontData): Font;
}

其中第一个参数url就是字体的加载路径,通常都是本地文件路径,Threejs已经提供给了一些字体给我们使用,它们都在node_modules/three/examples/fonts里面

image.png

可以看到FontLoader加载的字体都是一些json文件,不是直接去加载ttf或者otf文件,当然我们不能直接从node_modules里面直接去加载这些json文件,需要把它们拷贝出来到项目的资源目录下才可以

image.png

那么load函数的第一个参数有了,当FontLoader去加载这个字体的时候,它提供了三个回调函数来获取对应的结果

  • onLoad:加载成功,并且回调一个Font对象
  • onProgress:加载中,并回调一个加载进度对象
  • onError:加载失败

我们这里只使用onLoad函数来获取它的加载结果

var fontload = new FontLoader();
fontload.load(`/fonts/gentilis_bold.typeface.json`, (res) => {

});

在回调函数中就可以用加载得到的Font对象来创建我们的三维文本了,创建文本的函数如下

function loadedFont(data: Font) {
    const textGeometry = new TextGeometry("Test My Text", {
      font: data,
      size: 6,
      depth: 5,
      bevelEnabled: true,
    });
    const textMaterial = new THREE.MeshStandardMaterial({
      color: 0x9400d3,
      metalness: 0.9,
      roughness: 0.3,
    });
    const textMesh = new THREE.Mesh(textGeometry, textMaterial);
    return textMesh;
  }

虽说TextGeometryExtrudeGeometry的子类,但是是否启用倒角的默认值却是不一样的,ExtrudeGeometry是默认启用倒角的,而TextGeometry是默认不启用倒角,所以这里显式的设置了bevelEnabledtrue,将loadedFont函数添加到onLoad函数中,文本就创建成功了

var fontload = new FontLoader();
fontload.load(`/fonts/gentilis_bold.typeface.json`, (res) => {
    scene.add(loadedFont(res));
});
image.png

部分文字在屏幕外面,这个没关系因为x轴是从坐标0开始往正方向绘制的,一会我们可以让它滚动起来,倒角有点大这个倒是需要调整下

const textGeometry = new TextGeometry("Test My Text", {
  font: data,
  size: 6,
  depth: 5,
  bevelEnabled: true,
  bevelThickness:0.5,
  bevelSize:0.5
});
image.png

将倒角深度与倒角与文本的距离都调整为0.5后,现在的文本就看起来好多了,现在文本都是英文的,我们试试看能不能加载中文,写点大家喜欢的

const textGeometry = new TextGeometry("一夜暴富,hahaha", {
  font: data,
  size: 6,
  depth: 5,
  bevelEnabled: true,
  bevelThickness:0.5,
  bevelSize:0.5
});
image.png

发现中文部分加载不出来,变成乱码了,原因是Threejs自带的字体是不支持加载中文的,如果想要加载的话,就必须去添加自定义字体

添加自定义字体

从网上找了一圈,下了个免费的支持中文的ttf字体包,那么问题来了,前面说过FontLoader无法直接加载ttf字体包,那么如何将ttf转换成json文件呢,这里推荐一个网站facetype.js 这里面可以将ttf文件转换成json文件

image.png

第一步选择文件,将下载好的ttf文件导入进来,然后其他选项都使用默认的,点击convert按钮,转换好的json文件就被下载下来了,现在只需要将下载下来的文件导入到项目的资源目录下,就可以去加载它了

image.png
var fontload = new FontLoader();
fontload.load(`/fonts/custom_wenyi.json`, (res) => {
    scene.add(loadedFont(res));
});
image.png

就这样我们成功的将中文也加载了出来,接下来就让文字滚动起来,达到飘的效果

文字滚动

需要实现文字滚动的话就必须改变文字的坐标,所以我们需要一个变量来保存创建好的三维字体

let textMesh = new THREE.Mesh()
var fontload = new FontLoader();
fontload.load(`/fonts/custom_wenyi.json`, (res) => {
    textMesh = loadedFont(res)
    scene.add(textMesh);
});

然后在循环渲染的函数中不断减去textMesh的横坐标就好了,代码如下

let target = 100
const update = () => {
    requestAnimationFrame(update);
    if(textMesh){
      textMesh.position.x -= 0.5
      target -= 0.5
      if(target < 0){
        target = 100
        textMesh.position.x = 0
      }
    }
    render.render(scene, camera);
};
update();

这里的代码可以让文字从右边移动到左边后达到一定的阈值,重新从右边开始移动,另外既然是暴富,那么咱把文字颜色也给染成金色的

const textMaterial = new THREE.MeshStandardMaterial({
  color: 0xFFD700,
  metalness: 0.9,
  roughness: 0.3,
});

现在来看看效果

text001.gif

总结

本篇文章主要学习了如何在三维世界中创建文本几何体,熟悉了TextGeometry的用法,并且知道了如何将ttf文件转换为Threejs需要的json文件,欢迎各位佬们多多指点,拜拜~