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

如何用Three.js实现文本自动换行与3D文本居中?

基于Three.js + Google Maps 3D文本自动换行与居中实现

我需要渲染如图所示的多行文本,但内容是动态生成的,手动添加换行不是理想方案。
目标文本效果

目前我的代码只能显示单行文本:

import React, { useEffect } from "react";
import * as THREE from "three";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { ThreeJSOverlayView } from "@googlemaps/three";

const Text = (props) => {
  useEffect(() => {
    props.map.setCenter(props.mapOptions.center);
    const overlay = new ThreeJSOverlayView({
      anchor: {
        lat: props.mapOptions.center.lat,
        lng: props.mapOptions.center.lng,
        altitude: 0,
      },
      upAxis: "Y",
    });
    overlay.setMap(props.map);

    const fontLoader = new FontLoader();

    fontLoader.load("./font.json", function (font) {
      const title = "HYATT HOTEL VANCOUVER";

      const geometry = new TextGeometry(title, {
        font: font,
        size: 60,
        height: 5,
      });

      const material = new THREE.MeshPhongMaterial({
        color: 0x4285f4,
        specular: 0xffffff,
      });

      const mesh = new THREE.Mesh(geometry, material);

      mesh.position.copy(
        overlay.latLngAltitudeToVector3({
          lat: props.mapOptions.center.lat,
          lng: props.mapOptions.center.lng,
        })
      );

      mesh.position.setY(130);
      mesh.scale.set(0.3, 0.3, 0.3);
      mesh.rotation.y = -Math.PI;

      overlay.scene.add(mesh);
    });
  }, []);
};

export default Text;

我的问题:

  1. 怎么设置文本宽度实现自动换行?
  2. 怎么让3D文本居中?

解决方案

1. 实现自动换行

Three.js自带的TextGeometry没有自动换行功能,得自己写逻辑拆分文本:

  • 根据字体和字号计算每行能容纳的内容宽度
  • 设定最大行宽,遍历文本内容,累计宽度超过阈值时插入换行符\n
  • 把处理好的带换行的文本传给TextGeometry

新增文本拆分函数,修改后的字体加载逻辑:

// 新增自动换行处理函数
function splitTextToWrap(text, font, maxWidth, fontSize) {
  const words = text.split(' ');
  let currentLine = '';
  let resultText = '';

  words.forEach(word => {
    const testLine = currentLine + word + ' ';
    // 计算当前测试行的宽度
    const lineWidth = font.computeBoundingBox(testLine).width * fontSize / font.data.resolution;

    if (lineWidth > maxWidth && currentLine) {
      resultText += currentLine + '\n';
      currentLine = word + ' ';
    } else {
      currentLine = testLine;
    }
  });
  // 加上最后一行
  resultText += currentLine;
  return resultText;
}

fontLoader.load("./font.json", function (font) {
  const title = "HYATT HOTEL VANCOUVER";
  // 设定最大宽度(根据需求调整,示例设为180)
  const maxLineWidth = 180;
  // 处理成带换行的文本
  const wrappedTitle = splitTextToWrap(title, font, maxLineWidth, 60);

  const geometry = new TextGeometry(wrappedTitle, {
    font: font,
    size: 60,
    height: 5,
  });

  // ... 后续材质、mesh创建逻辑不变
});

2. 实现3D文本居中

要让文本对齐锚点中心,需要基于文本的包围盒计算偏移量,把几何体平移到中心位置:

const geometry = new TextGeometry(wrappedTitle, {
  font: font,
  size: 60,
  height: 5,
});
// 计算文本几何体的包围盒
geometry.computeBoundingBox();
// 计算中心偏移量,把几何体原点移到文本中心
const centerOffset = new THREE.Vector3(
  -(geometry.boundingBox.max.x - geometry.boundingBox.min.x) / 2,
  -(geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2,
  0 // Z轴方向不需要偏移,文本厚度方向不影响居中
);
// 平移几何体到中心
geometry.translate(centerOffset.x, centerOffset.y, centerOffset.z);

// 后续创建mesh并设置位置即可,此时mesh的原点就是文本中心,对齐地图锚点后自然居中
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(overlay.latLngAltitudeToVector3({
  lat: props.mapOptions.center.lat,
  lng: props.mapOptions.center.lng,
}));
mesh.position.setY(130);
mesh.scale.set(0.3, 0.3, 0.3);
mesh.rotation.y = -Math.PI;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:02:52