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

相关推荐
dancing9991 小时前
cocos3.X的oops框架oops-plugin-excel-to-json改进兼容多表单导出功能
前端·javascript·typescript·游戏程序
萌萌哒草头将军2 小时前
🚀🚀🚀Prisma 发布无 Rust 引擎预览版,安装和使用更轻量;支持任何 ORM 连接引擎;支持自动备份...
前端·javascript·vue.js
书语时2 小时前
ES6 Promise 状态机
前端·javascript·es6
拉不动的猪2 小时前
管理不同权限用户的左侧菜单展示以及权限按钮的启用 / 禁用之其中一种解决方案
前端·javascript·面试
西陵3 小时前
前端框架渲染DOM的的方式你知道多少?
前端·javascript·架构
海的诗篇_3 小时前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
じ☆ve 清风°3 小时前
理解JavaScript中map和parseInt的陷阱:一个常见的面试题解析
开发语言·javascript·ecmascript
江城开朗的豌豆3 小时前
eval:JavaScript里的双刃剑,用好了封神,用不好封号!
前端·javascript·面试
江城开朗的豌豆3 小时前
JavaScript篇:前端定时器黑科技:不用setInterval照样玩转循环任务
前端·javascript·面试
江城开朗的豌豆4 小时前
JavaScript篇:自定义事件:让你的代码学会'打小报告'
前端·javascript·面试