前面我们用 Sprite + Canvas 绘制过文字:

但如果需要换行、或者中英文混合的时候,都需要自己计算每个文字的显示位置。
比较麻烦。
既然这种是常见需求,那有没有现成的封装好的方案呢?
有的,就是 three-spritetext 这个包:

它就是用 canvas 作为 Sprite 的 Texture 来实现的,不过它做了一些封装。
会自动计算文字的文字、换行,还可以设置文字样式:

开箱即用,非常方便。
一般我们用到 Sprite + canvas 来绘制文字的时候,都直接用这个库。
我们来试一下:
npx create-vite sprite-text-test

进入项目,安装依赖:
npm install
npm install --save three
npm install --save-dev @types/three
改下 src/main.js
import './style.css';
import * as THREE from 'three';
import {
OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import mesh from './mesh.js';
const scene = new THREE.Scene();
scene.add(mesh);
const directionLight = new THREE.DirectionalLight(0xffffff, 2);
directionLight.position.set(500, 400, 300);
scene.add(directionLight);
const ambientLight = new THREE.AmbientLight();
scene.add(ambientLight);
const width = window.innerWidth;
const height = window.innerHeight;
const helper = new THREE.AxesHelper(500);
scene.add(helper);
const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 10000);
camera.position.set(500, 600, 800);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
document.body.append(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
创建 Scene、Light、Camera、Renderer。
改下 style.css
body {
margin: 0;
}
我们先用之前的方案 canvas + Sprite 来画个文字
创建 mesh.js
import * as THREE from 'three';
function createCanvas(text) {
const canvas = document.createElement("canvas");
const dpr = window.devicePixelRatio;
const w = canvas.width = 500 * dpr;
const h = canvas.height = 300 * dpr;
const c = canvas.getContext('2d');
c.translate(w / 2, h / 2);
c.fillStyle = "#ffffff";
c.font = "normal " + 300 * dpr + "px 微软雅黑";
c.textBaseline = "middle";
c.textAlign = "center";
c.fillText(text, 0, 0);
return canvas;
}
const texture = new THREE.CanvasTexture(createCanvas('aaa'));
const spriteMaterial = new THREE.SpriteMaterial({
map: texture
});
const sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(500, 300);
export default sprite;
500 * 300 的 Sprite,上面的 canvas 的尺寸要 * dpr 再画,这样才不模糊。
跑一下:
npm run dev


我们再加俩文字:


因为 canvas 宽度不够,现在就显示不全了。
需要动态计算宽度:


每个文字大小是 300,我们用 300 * text.length 就是需要的 canvas 宽度。
const w = canvas.width = text.length * 300 * dpr;
sprite.scale.set(str.length * 300, 300);

类似这样需要计算的东西挺多的。
而如果你用 SpriteText 呢?
试一下:
创建 mesh2.js
import SpriteText from "three-spritetext";
const spriteText = new SpriteText('aaa测试', 300);
export default spriteText;

不需要自己创建 canvas 和计算尺寸。

开箱即用。
而且它封装了一些样式:

spriteText.padding = 80;
spriteText.strokeWidth = 2;
spriteText.strokeColor = 'blue';
设置 padding,然后设置描边样式。

设置 border 和背景颜色:

spriteText.borderColor = '#ffffff';
spriteText.borderWidth = 10;
spriteText.borderRadius = 100;
spriteText.backgroundColor = 'lightpink';

而且支持换行:


会自动计算文字的位置。
虽然我们用 canvas 自己画也能实现这种效果,但是计算起来确实挺麻烦,不如直接用 SpriteText。
案例代码上传了小册仓库。
总结
这节我们学了 SpriteText,它是用 canvas + Sprite 实现的一个文字组件。
可以设置文字高度、换行、边框、描边等样式,内部会自动计算文字位置并用 canvas 把样式画出来,使用起来和 css 一样。
用到 canvas + Sprite 绘制文字的地方,都可以直接用这个组件,自己画是比较麻烦和没必要的。