Skip to content

52. SpriteText:开箱即用的文字组件

Published:

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

image.png

但如果需要换行、或者中英文混合的时候,都需要自己计算每个文字的显示位置。

比较麻烦。

既然这种是常见需求,那有没有现成的封装好的方案呢?

有的,就是 three-spritetext 这个包:

image.png

它就是用 canvas 作为 Sprite 的 Texture 来实现的,不过它做了一些封装。

会自动计算文字的文字、换行,还可以设置文字样式:

image.png

开箱即用,非常方便。

一般我们用到 Sprite + canvas 来绘制文字的时候,都直接用这个库。

我们来试一下:

npx create-vite sprite-text-test

image.png

进入项目,安装依赖:

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

image.png

2025-05-22 13.37.17.gif

我们再加俩文字:

image.png

2025-05-22 13.38.26.gif

因为 canvas 宽度不够,现在就显示不全了。

需要动态计算宽度:

image.png

image.png

每个文字大小是 300,我们用 300 * text.length 就是需要的 canvas 宽度。

const w = canvas.width = text.length * 300 * dpr;
sprite.scale.set(str.length  * 300, 300);

2025-05-22 13.43.18.gif

类似这样需要计算的东西挺多的。

而如果你用 SpriteText 呢?

试一下:

创建 mesh2.js

import SpriteText from "three-spritetext";

const spriteText = new SpriteText('aaa测试', 300);

export default spriteText;

image.png

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

2025-05-22 13.48.00.gif

开箱即用。

而且它封装了一些样式:

image.png

spriteText.padding = 80;
spriteText.strokeWidth = 2;
spriteText.strokeColor = 'blue';

设置 padding,然后设置描边样式。

2025-05-22 13.51.25.gif

设置 border 和背景颜色:

image.png

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

image.png

而且支持换行:

image.png

image.png

会自动计算文字的位置。

虽然我们用 canvas 自己画也能实现这种效果,但是计算起来确实挺麻烦,不如直接用 SpriteText。

案例代码上传了小册仓库

总结

这节我们学了 SpriteText,它是用 canvas + Sprite 实现的一个文字组件。

可以设置文字高度、换行、边框、描边等样式,内部会自动计算文字位置并用 canvas 把样式画出来,使用起来和 css 一样。

用到 canvas + Sprite 绘制文字的地方,都可以直接用这个组件,自己画是比较麻烦和没必要的。

评论