You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Three.js的TextGeometry实现3D文本动态绘制效果?

实现Three.js TextGeometry涂鸦式逐步构建动画

嘿,我完全懂你想要的那种效果——游戏结束时,得分数字像涂鸦一样在墙上慢慢“画”出来,而不是直接跳出来,对吧?用TextGeometry完全能实现这个需求,你之前想到的顶点渐进显示思路是对的,下面给你具体的实现方案和代码示例:

核心思路:用着色器控制顶点渐进显现

直接操作几何体顶点来显示/隐藏虽然可行,但性能不够友好(尤其是复杂字体)。更优的方式是用自定义着色器材质(ShaderMaterial),给每个顶点添加延迟显示的属性,通过着色器根据时间动态控制每个顶点的可见性,这样能实现流畅的涂鸦动画。

具体步骤 + 代码示例

1. 加载字体并创建TextGeometry

首先加载字体文件,创建文本几何体,然后给每个顶点添加自定义的延迟属性:

import * as THREE from 'three';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';

// 初始化场景、相机、渲染器(基础代码省略,你应该已经有了)
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.z = 5;

// 加载字体(替换成你自己的字体路径)
const fontLoader = new FontLoader();
fontLoader.load('fonts/helvetiker_regular.typeface.json', (font) => {
  // 创建得分文本几何体
  const scoreText = '9999'; // 这里可以替换成动态得分
  const textGeometry = new TextGeometry(scoreText, {
    font: font,
    size: 1.5,
    height: 0.15,
    curveSegments: 12,
    bevelEnabled: true,
    bevelThickness: 0.08,
    bevelSize: 0.08
  });
  textGeometry.center(); // 让文本居中

  // 给每个顶点添加延迟显示属性
  const delayArray = [];
  const totalVertices = textGeometry.attributes.position.count;
  // 这里我们按顶点索引分配延迟,让文本从左到右、从上到下逐步显现
  // 如果要更精准的笔画顺序,后面会讲优化方案
  textGeometry.attributes.position.array.forEach((_, idx) => {
    // 计算每个顶点的延迟时间,总动画时长设为2秒
    const delay = (idx / totalVertices) * 2;
    delayArray.push(delay, delay, delay); // 每个顶点对应xyz三个分量
  });

  // 将延迟属性添加到几何体
  textGeometry.setAttribute('aDelay', new THREE.Float32BufferAttribute(delayArray, 3));

  // 创建自定义着色器材质
  const graffitiMaterial = new THREE.ShaderMaterial({
    uniforms: {
      uTime: { value: 0 },
      uFadeDuration: { value: 0.3 }, // 单个顶点的淡入时长
      uTextColor: { value: new THREE.Color(0x00ff00) } // 绿色涂鸦效果,可自定义
    },
    vertexShader: `
      attribute float aDelay;
      uniform float uTime;
      uniform float uFadeDuration;
      varying float vOpacity;

      void main() {
        // 计算当前顶点的透明度:时间超过延迟后开始淡入
        vOpacity = clamp((uTime - aDelay) / uFadeDuration, 0.0, 1.0);
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragmentShader: `
      varying float vOpacity;
      uniform vec3 uTextColor;

      void main() {
        // 完全透明时丢弃片段,避免影响性能
        if (vOpacity < 0.05) discard;
        gl_FragColor = vec4(uTextColor, vOpacity);
      }
    `,
    transparent: true,
    side: THREE.DoubleSide
  });

  // 创建文本网格并添加到场景
  const textMesh = new THREE.Mesh(textGeometry, graffitiMaterial);
  scene.add(textMesh);

  // 动画循环
  function animate() {
    requestAnimationFrame(animate);
    // 更新时间,控制动画进度
    graffitiMaterial.uniforms.uTime.value += 0.01;
    renderer.render(scene, camera);
  }
  animate();
});

2. 优化:按笔画顺序显现

上面的示例是按顶点索引顺序显现,如果你想要更贴近真实涂鸦的笔画顺序,可以:

  • 从TextGeometry中提取每个字形的Shape对象
  • 使用THREE.ShapeUtils遍历Shape的曲线路径,计算每个顶点在路径上的位置占比,以此作为延迟时间的依据
  • 这样每个数字会按照它的笔画顺序逐步显现,更符合涂鸦的感觉

3. 额外效果增强

  • 可以在顶点着色器中添加微小的位移动画,让顶点显现时稍微“跳动”一下,模拟涂鸦的随性
  • 给材质添加纹理,模拟喷漆或粉笔的质感,让效果更真实

关键提示

  • 字体加载是异步操作,一定要在加载完成后再创建几何体
  • 如果得分是动态变化的,每次更新得分时需要重新生成TextGeometry并添加延迟属性
  • 调整uFadeDuration和总动画时长参数,可以控制涂鸦速度的快慢

内容的提问来源于stack exchange,提问作者JJ Gerrish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:02:35