Three.js 字体

在 Three.js 中,我们可以通过 FontLoader 加载字体,并结合 TextGeometry 创建 3D 文本。加载字体是因为字体文件包含了字体的几何信息,例如字体的形状、大小、粗细等,而 TextGeometry 则是根据字体信息生成 3D 文本的几何体。

在下面,我们将分别讲解加载字体和创建文本这两部分内容,并结合参数说明,让你对每一步都有深入理解。

加载字体和创建 3D 文本

Three.js 使用 FontLoader 来加载字体文件(格式为 .json),通过加载后的字体对象结合 TextGeometry 创建文本几何体。

加载字体:FontLoader

以下是使用 FontLoader 加载字体的代码:

javascript 复制代码
const fontLoader = new THREE.FontLoader();

// 加载字体文件(路径需要正确)
fontLoader.load("/path/to/font.json", (font) => {
  console.log("字体加载成功", font);

  // 使用加载的字体创建 3D 文本几何体
  const textGeometry = new THREE.TextGeometry("Hello Three.js!", {
    font: font, // 必须提供加载后的字体对象
    size: 1, // 字体大小
    height: 0.5, // 字体厚度
    curveSegments: 12, // 曲线分段数,值越大越平滑
    bevelEnabled: true, // 是否启用斜角
    bevelThickness: 0.03, // 斜角厚度
    bevelSize: 0.02, // 斜角大小
    bevelSegments: 5, // 斜角分段数
  });

  // 创建材质和网格
  const textMaterial = new THREE.MeshStandardMaterial({ color: 0xff6347 });
  const textMesh = new THREE.Mesh(textGeometry, textMaterial);

  // 设置文本位置
  textMesh.position.set(-5, 2, 0);

  // 添加到场景
  scene.add(textMesh);
});
TextGeometry 参数解析

TextGeometry 的构造函数中,我们需要传入两个参数:文本字符串和配置对象。

参数 1:文本字符串
  • 表示需要显示的文本内容,例如 'Hello Three.js!'
参数 2:配置对象

配置对象是一个 JSON,用于定义文本的样式和几何细节。以下是主要字段的详细说明:

参数名称 类型 默认值 描述
font THREE.Font 必须提供 加载的字体对象,通过 FontLoader 加载后传入。
size number 100 字体大小,值越大,文本越大。
height number 50 字体厚度,用于创建 3D 效果。
curveSegments number 12 曲线分段数,值越大,曲线部分(如圆形字母)越平滑。
bevelEnabled boolean false 是否启用斜角。
bevelThickness number 10 斜角的厚度,仅在启用斜角时有效。
bevelSize number 8 斜角的大小,表示斜角距离文本边缘的距离。
bevelSegments number 3 斜角的分段数,值越大斜角部分越平滑。

Three.js 的 FontLoader 仅支持 .json 格式的字体文件。如果是 .ttf 或其他格式,可以使用工具(如 Facetype.js)将其转换为 .json

例子

示例中,我们将创建一个 3D 文本效果,包含以下特性:

  • 使用 TextGeometry 创建立体文字
  • 添加斜角效果使文字边缘更加平滑
  • 使用 MeshPhongMaterial 材质实现高光效果
  • 通过环境光和方向光打造立体感
  • 实现文本自动居中显示
  • 支持通过鼠标交互旋转和缩放场景

效果如下:

让我们先看看创建 3D 文本的关键步骤:

  1. 加载字体
javascript 复制代码
const fontLoader = new FontLoader();
fontLoader.load(
  "https://threejs.org/examples/fonts/helvetiker_regular.typeface.json",
  (font) => {
    // 加载完成后的回调函数
  }
);
  1. 创建文本几何体
javascript 复制代码
const textGeometry = new TextGeometry("Hello Three.js!", {
  font: font,
  size: 1, // 字体大小
  height: 0.2, // 文字厚度
  curveSegments: 12, // 曲线分段数
  bevelEnabled: true, // 启用斜角
  bevelThickness: 0.03,
  bevelSize: 0.02,
  bevelSegments: 5,
});
  1. 创建材质
javascript 复制代码
const textMaterial = new THREE.MeshPhongMaterial({
  color: 0x00ff00, // 绿色材质
  specular: 0x555555, // 高光颜色
  shininess: 30, // 高光强度
});

const textMesh = new THREE.Mesh(textGeometry, textMaterial);
  1. 文本居中处理
javascript 复制代码
textGeometry.computeBoundingBox();
const centerOffset =
  -0.5 * (textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x);
textMesh.position.x = centerOffset;

下面是完整代码

javascript 复制代码
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";

// 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 10;

// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// 添加灯光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);

// 加载字体
const fontLoader = new FontLoader();

fontLoader.load(
  "https://threejs.org/examples/fonts/helvetiker_regular.typeface.json",
  (font) => {
    // 创建文本几何体
    const textGeometry = new TextGeometry("Hello Three.js!", {
      font: font,
      size: 1, // 字体大小
      height: 0.2, // 文字厚度
      curveSegments: 12, // 曲线分段数
      bevelEnabled: true, // 启用斜角
      bevelThickness: 0.03, // 斜角深度
      bevelSize: 0.02, // 斜角大小
      bevelOffset: 0, // 斜角偏移
      bevelSegments: 5, // 斜角分段数
    });

    // 创建材质
    const textMaterial = new THREE.MeshPhongMaterial({
      color: 0x00ff00, // 绿色材质
      specular: 0x555555, // 高光颜色
      shininess: 30, // 高光强度
    });

    // 创建网格
    const textMesh = new THREE.Mesh(textGeometry, textMaterial);

    // 居中文本
    textGeometry.computeBoundingBox();
    const centerOffset =
      -0.5 * (textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x);
    textMesh.position.x = centerOffset;

    scene.add(textMesh);
  }
);

// 动画循环
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

// 处理窗口大小变化
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

animate();

代码

github

https://github.com/calmound/threejs-demo/tree/main/font

gitee

https://gitee.com/calmound/threejs-demo/tree/main/font

相关推荐
二川bro19 分钟前
第51节:Three.js源码解析 - 核心架构设计
开发语言·javascript·ecmascript
djk88882 小时前
多标签页导航后台模板 html+css+js 纯手写 无第三方UI框架 复制粘贴即用
javascript·css·html
Hilaku2 小时前
别再吹性能优化了:你的应用卡顿,纯粹是因为产品设计烂🤷‍♂️
前端·javascript·代码规范
驯狼小羊羔2 小时前
学习随笔-hooks和mixins
前端·javascript·vue.js·学习·hooks·mixins
风止何安啊3 小时前
JS 对象:从 “散装” 到 “精装” 的晋级之路
前端·javascript·node.js
Achieve前端实验室3 小时前
【每日一面】如何解决内存泄漏
前端·javascript·面试
肥猪大大3 小时前
Rsbuild迁移之node-sass引发的血案
前端·javascript
Moment5 小时前
专为 LLM 设计的数据格式 TOON,可节省 60% Token
前端·javascript·后端
G***66915 小时前
前端性能优化插件,CSS与JavaScript压缩插件实战指南
前端·javascript·css
鹏多多6 小时前
React的useRef的深度解析与应用指南
前端·javascript·react.js