ThreeJS 对文本的处理相对薄弱,它提供有一个扩展几何体 TextGeometry,需要加载字体,且对非英文字体一点都不友好。故此,若需要给立方体每一个面都添加文本,需要另辟蹊径,其中,通过离线 canvas 绘制文本然后作为纹理贴图贴到立方体的每一个面,是个很常见的实现方法。
ThreeJS 本身就是通过 canvas 标签在2d平面上绘制3d效果,它对 canvas 的支持度非常强,核心库内置有canvas纹理,一个 CanvasTexture 类,构造器复杂无比(CanvasTexture),不过没关系,通常用到的参数主要只是一个 canvas 标签,像这样:
const texture = new THREE.CanvasTexture(canvasElement);
canvasElement 即为canvas画布元素,其上应该是已经绘制好了所需文本。为此,需要熟悉 canvas 绘制文本功能,可以参阅 canvas绘制文本 加以学习掌握,主要学习其上介绍的 fillText 方法,因为 ThreeJS 貌似对 strokeText 支持不好。
为方便复用,我编写了一个在 canvas 画布上绘制文本的函数:
function mkText(txt, font, color, bg, w, h) {
const canv = document.createElement('canvas');
canv.width = w;
canv.height = h;
const ctx = canv.getContext('2d');
ctx.fillStyle = bg;
ctx.fillRect(0, 0, w, h); // 绘制矩形(面的背景色)
ctx.font = font;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = color;
ctx.fillText(txt, w/2, h/2); // 绘制文本
return canv;
};
参数解释:
1. txt : 输出的文本,文本型
2. font : 字体设置,字符型,例如,'bold 20px "宋体"'
3. color : 文本颜色,字符型
4. bg : 背景色,字符型
5. w : 宽度,数值型
6. h : 高度,数值型
可以根据需要修改绘制文本的函数。这是离线创建的 canvas 标签,它没有添加到文档中,不会显示出来。函数返回(return)所创建的 canvas 画布 canv,所以,下一步,以其返回值创建 ThreeJS 纹理:
const texture = new THREE.CanvasTexture(
mkText(
'文字', // 1. 输出的文本
'bold 24px "微软雅黑"', // 2. 字体设置
'white', // 3. 前景色
'purple', // 4. 背景色
100, // 5. 宽度
50 // 6. 高度
)
);
// 代码可以写在一行
// const texture = mkText('文字', '24px "微软雅黑"', 'white', 'purple', 100, 50)
最后创建立由方体几何体 BoxGeometry 和六个面的基础材质 MeshBasicMaterial 构建而成的 Mesh 网格,再初始化 Mesh 的 Pose,加上旋转动画,就大功告成。下面是完整代码,可在线运行:
<script type="module">
import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
basic3();
const texts = ['壹', '贰', '叁', '肆', '伍', '陆'];
let faces = [];
texts.forEach(text => {
const texture = new THREE.CanvasTexture(mkText(text, 'bold 24px "微软雅黑"', 'white', 'purple', 100, 50));
faces.push(new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, map: texture}));
});
const mesh = new THREE.Mesh(new THREE.BoxGeometry(), faces);
mesh.rotateY(Math.PI / 4);
scene.add(mesh);
animate();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mesh.rotation.x -= delta / 2;
renderer.render(scene, camera);
};
function mkText(txt, font, color, bg, w, h) {
const canv = document.createElement('canvas');
canv.width = w;
canv.height = h;
const ctx = canv.getContext('2d');
ctx.fillStyle = bg;
ctx.fillRect(0, 0, w, h);
ctx.font = font;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = color;
ctx.fillText(txt, w/2, h/2);
return canv;
};
</script>