Threejs 文字绘制性能优化

一、整体思路

不用TextGeometry。文字多的时候性能太差

  1. 收集场景中需要绘制的所有文字信息
  2. 将所有的文字信息都绘制在一个canvas上并维护好,每个文字信息在canvas上的位置信息,包括,文字绘制在canvas上的第几行、在当前行的位置、文字长度等信息。将canvas生成 THREE.CanvasTexture
  3. 用THREE.Sprite绘制文字,使用步骤2生成的 CanvasTexture,这里注意,需要处理CanvasTexture的offset和repeat属性去匹配文字对应的文理坐标。将绘制的 THREE.Sprite进行适当的缩放

二、具体实现

1. 数据收集具体数据的收集,这里不做说明,简单的展示一下数据结构,方便看下面的代码

const texts = [
    {
        str: '90844',
        position: {
            x: -308922.01328395033,
            y: -674026.0824936354,
            z: 0.009999999776482582,
        },
    },
    ...
]

2. 将所有文字信息绘制在canvas上​​​​​​,并维护好文字在canvas的位置信息

generateTextCanvas(texts: { str: string; position: THREE.Vector3 }[], color = '#fff') {
    // 设置canvas最大宽度为1000
    const maxWidth = 1000;
    let canvasWidth = 0;

    // 存储文字在canvas中的位置信息
    const positionItems: { start: number; lineNum: number; width: number;str:string }[] = [];
    // 记录当前绘制文字在的行数,从0开始
    let curLine = 0;
    // 记录当前绘制文字在当前行的起始位置
    let curStart = 0;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    const lineHeight = 48;
    context.font = `${lineHeight / 2}px sans-serif`;

    for (let i = 0; i < texts.length; i += 1) {
        const measureText = context.measureText(texts[i].str);
        let { width } = measureText;
        width = Math.ceil(width);
        // 绘制的时候如果当前行绘制会超出,记得换行
        if (width + curStart < maxWidth) {
            positionItems.push({ start: curStart, lineNum: curLine, width,str: texts[i].str });
            canvasWidth = Math.max(canvasWidth, curStart + width,str: texts[i].str);
            curStart += width;
        } else {
            curLine += 1;
            positionItems.push({ start: 0, lineNum: curLine, width });
            curStart = width;
            canvasWidth = Math.max(canvasWidth, width);
        }
    }
    const canvasHeight = (curLine + 1) * lineHeight;
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    context.fillStyle = color;
    context.font = `${lineHeight / 2}px sans-serif`;
    // 注意这里要设置为middle,并且这里的设置决定 fillText时的y的位置
    context.textBaseline = 'middle';
    context.textAlign = 'left';
    for (let i = 0; i < positionItems.length; i += 1) {
        const { start, lineNum } = positionItems[i];
        context.fillText(texts[i].str, start, lineNum * lineHeight + lineHeight / 2);
    }
    const texture = new THREE.CanvasTexture(canvas);
    return {
        texture,
        canvasWidth,
        canvasHeight,
        positionItems,
    };
}

3. 用THREE.Sprite绘制文字,并且设置好文理坐标

positionItems.forEach((item, index) => {
    const itemTexture = texture.clone();
    itemTexture.offset.set(
        positionItems[index].start / canvasWidth,
        1 - (positionItems[index].lineNum + 1) / lineLength,
    );
    itemTexture.repeat.set(positionItems[index].width / canvasWidth, 1 / lineLength);
    const material = new THREE.SpriteMaterial({
        map: itemTexture,
        transparent: true,
        // 需要设置,不然文字会有黑色的背景,会遮挡场景中的对象
        depthTest: false,
    });
    const textMesh = new THREE.Sprite(material);
    // 具体缩放多少按实际显示效果去看,但是这里的缩放比例很重要
    textMesh.scale.set(positionItems[index].width / 24, canvasHeight / lineLength / 24, 1);
    textMesh.position.set(item.position.x, item.position.y, item.position.z);
    scene.add(textMesh);
});

这里重点是offset和repeat的设置,scale缩放的时候也要注意,缩放值和实际的文字宽度和高度要一致,否则文字会变形。

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
three.js是一个用于在Web浏览器上创建和显示3D图形的JavaScript库。在处理大场景时,性能优化是非常重要的,以下是一些three.js大场景性能优化的方法: 1. 模型合并:将场景中的相关模型合并为一个单独的模型,可以减少绘制调用的次数,从而提高性能。 2. 纹理压缩:通过使用压缩格式的纹理,如WebP或DDS,可以减少纹理的大小和加载时间,提高渲染性能。 3. 层级着色器:使用层级着色器技术,将复杂的3D模型分层渲染,只绘制可见的部分,隐藏掉被遮挡的部分,从而降低渲染负载。 4. LOD(细节层次):使用LOD技术,根据相机距离来自动切换不同细节层次的模型,以确保远处的物体具有较低的多边形数量,提高性能。 5. 遮挡剔除:使用遮挡剔除技术,可根据相机位置自动计算隐藏在其他物体后面的物体,避免不必要的渲染。 6. 光照优化:减少光源数量和复杂度,使用更简单的光照模型,如平行光或环境光,可以提高渲染性能。 7. 离屏渲染:使用离屏渲染技术,将不经常变化的场景渲染到一个纹理中,然后将该纹理用作场景的背景,避免重复渲染,提高性能。 8. WebGL扩展:利用WebGL的扩展功能,如VAO(顶点数组对象)和instancing(实例化)等,可以优化渲染效率和内存使用。 总之,three.js大场景性能优化的关键在于减少渲染调用次数、降低多边形数量、使用优化的纹理和光照,并合理利用WebGL的扩展功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值