如何用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;
我的问题:
- 怎么设置文本宽度实现自动换行?
- 怎么让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
相关产品推荐
相关产品推荐

