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

如何为Three.js TextGeometry增加顶点 补全文字点云缺失点位

问题根源

TextGeometry本身是为渲染网格面设计的挤出几何体,顶点只会分布在文字轮廓边线、倒角边、挤出侧边上,文字正面、背面的大面积面内部默认没有顶点,直接用Points渲染时自然只会显示轮廓点位,出现中间空心缺失的效果,和你配置的bevelSegments、step参数无关,这些参数只能控制边线的细分密度,解决不了面内无顶点的问题。

实现方案

1. 补充文字内部顶点

核心思路是放弃直接使用TextGeometry的原生顶点,自己对文字区域做均匀采样,保留落在文字轮廓内部的点作为点云顶点:

  1. 先临时生成TextGeometry,计算出文字的整体包围盒范围
  2. 按照你需要的点密度设置采样步长,在包围盒范围内按网格遍历生成2D/3D坐标点
  3. 用点在多边形内的判断逻辑(你已经引入的GeometryUtils自带相关方法,直接调用即可),过滤掉落在文字轮廓外的点
  4. 如果需要带厚度的3D文字点云,沿着Z轴(挤出方向)按层重复采样即可
  5. 采样完成后销毁临时生成的TextGeometry释放内存

核心采样逻辑参考:

const generateTextPointCloud = (text, font, config, sampleDensity = 2, thickness = 3) => {
  const tempTextGeo = new THREE.TextGeometry(text, config);
  tempTextGeo.computeBoundingBox();
  const bbox = tempTextGeo.boundingBox;
  const validPoints = [];

  // 三层循环做3D采样,只要2D效果去掉z轴循环即可
  for (let z = 0; z <= thickness; z += sampleDensity) {
    for (let x = bbox.min.x; x <= bbox.max.x; x += sampleDensity) {
      for (let y = bbox.min.y; y <= bbox.max.y; y += sampleDensity) {
        // 调用GeometryUtils的点包含判断方法,判断点是否在文字形状内部
        const isInTextShape = GeometryUtils.isPointInShape(new THREE.Vector2(x, y), tempTextGeo);
        if (isInTextShape) {
          validPoints.push(x, y, z);
        }
      }
    }
  }

  tempTextGeo.dispose();
  // 直接生成点云用的BufferGeometry
  const pointGeo = new THREE.BufferGeometry();
  pointGeo.setAttribute('position', new THREE.Float32BufferAttribute(validPoints, 3));
  return pointGeo;
}

采样步长越小,点密度越高,显示效果越细腻,对应的性能开销也越大,常规场景下设1~3即可。

2. 点位自定义调整

采样得到所有顶点坐标后,直接遍历坐标数组做自定义修改即可,你可以根据需求实现任意调整逻辑:

  • 给点位加随机偏移,做粒子散点效果
  • 给每个点位绑定自定义属性(动画相位、点大小、颜色值、目标位置等)
  • 按位置做规则变形,比如波浪、球面映射效果

参考调整逻辑:

const positionAttr = pointGeo.getAttribute('position');
const phaseList = [];
// 遍历所有顶点做调整
for (let i = 0; i < positionAttr.count; i++) {
  const x = positionAttr.getX(i);
  const y = positionAttr.getY(i);
  const z = positionAttr.getZ(i);
  // 示例:加随机扰动,边缘点扰动幅度更大
  const offset = (Math.random() - 0.5) * 1.2;
  positionAttr.setXYZ(i, x + offset, y + offset, z + offset * 0.5);
  // 存自定义动画属性
  phaseList.push(Math.random() * Math.PI * 2);
}
// 绑定自定义属性到几何体,供材质或动画逻辑使用
pointGeo.setAttribute('aPhase', new THREE.Float32BufferAttribute(phaseList, 1));
positionAttr.needsUpdate = true;
// 自动对齐到你需要的锚点,对应原组件的hAlign、vAlign参数
pointGeo.computeBoundingBox();
// 按对齐逻辑平移几何体即可

原有代码修改提示

  • 移除组件内直接挂载的<textGeometry>,换成上面方法生成的自定义BufferGeometry传给<points>
  • 采样完成后根据你设置的对齐规则,整体平移几何体的位置即可实现居中、左对齐、上对齐等效果
  • 如果要做点位动画,可以在useFrame钩子中遍历position属性逐帧更新坐标

内容的提问来源于stack exchange,提问作者Y Eng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:18:24