Pixi.js: 如何在渲染大量文本并更新其位置时实现较高的FPS?

创建于 2020-09-25  ·  10评论  ·  资料来源: pixijs/pixi.js

嗨,我目前正在研究PixiJS的一个新项目,到目前为止我真的很喜欢! 关于应用程序的性能有一些要求。 真正棘手的部分是,这将导致许多显示的文本标签不断更新。 我找不到进一步提高性能的方法,而我的最后希望是在这个社区中找到一些帮助。

目标

1500个文字标签
每秒60个位置更新
60 FPS

xi溪游乐场

我已经使用BitMapText创建了一个最小的示例,在MacBook Pro上导致〜28 FPS。
https://www.pixiplayground.com/#/edit/rLbAN_xrw7yUU_cg_c8Xv

您是否有任何改善的想法? 在此先多谢!

🤔 Question

最有用的评论

谢谢,它以某种方式可以从文本生成纹理并在子画面上使用它。 但是我目前不明白为什么,也无法在操场上复制它。 😄

但是,该应用程序现在每帧以60FPS更新所有1500个标签位置。 此外,文本内容每秒都会更新一次。 这导致每秒短暂冻结。 因此,下一步将是使这些文本更新异步,例如在Web worker中。 我目前正在阅读有关ImageBitmap和OffscreenCanvas的文章。 这对其他人可能很有趣,所以我将分享我的进展。

所有10条评论

您确定要在所有时间上显示1500吗? 剔除屏幕外的标签将对性能有很大帮助。 Pixi并没有进行任何淘汰,但是有一些社区插件(例如@SukantPal的@pixi-essentials/cull )可以在这里为您提供帮助。

所有1500个标签都唯一吗? 如果有很多重复项,则可以使用RenderTexture将其转换为Sprite,并以更多的内存为代价共享引用。

@ChristophWalter您展示的示例可能会因@bigtimebuddy提到的剔除而

将MESH.BATCHABLE_SIZE设置为较高的值(例如200)可能会有所帮助。 我没有进行全面测试,因为在iMac上CPU速度降低6倍后,它仍然可以通过45 FPS供电。

我没有过多地介绍该示例。 但是,如果您正在从事商业项目,而这实际上是GPU方面的瓶颈,那么您可能会考虑将所有字母(所有A,然后所有B,所有C等)呈现在一起的乱序为了改善纹理的局部性,开发平铺引擎和/或进行diff-rect优化,以渲染具有changed_(即基于1500个标签中的60个更新)的屏幕部分。 这只是想法,应该这样考虑。

感谢您的帮助!

实际上,我们将使用剔除,并且不太可能同时显示多个标签。 但是出于基准测试的原因,我们需要与非Web应用程序竞争。 我们已经对这些要求提出了质疑,但是如果可以证明webgl也可以解决这个问题,那将大有帮助。

标签将是唯一的。 但是他们可能不会经常改变。 该示例完全不更改文本内容。 因此,可能存在一些优化的潜力。 我注意到,即使我不更新职位(游乐场),FPS仍保持不变。 是否只有在文本更改时才可以重新渲染?

设置MESH.BATCHABLE_SIZE并没有改变我的立场。 我会看一下您的其他想法,或者建议您购买iMac。

嗯,如果您确实在优化该特定示例,那么最高的方法就是做一次@bigtimebuddy所说的,

这提供了两个主要好处:

  • 这将消除批处理渲染器缓冲阶段的开销。
  • 顶点数将减少112倍(4 /文本而不是4 /字符)。 这将顶点降至6K。
  • 场景中只有一个DisplayObject。

因此,基本上,该过程将如下所示:

  1. 将BitmapText渲染为RenderTexture
  2. 创建具有1500 * 4顶点的网格。
  3. 直接对顶点进行动画处理。 您必须小心,因为每个实例有四个顶点(即矩形)。 因此,您将计算第一个顶点的位置。 那么其他三个将是(x +宽度,高度),(x +宽度,y +高度),(x,y +高度)。

这应该是一个简单的过程。 请告诉我们情况如何!

嘿,我尝试执行您的建议。 将BitmapText转换为纹理似乎可行。 但是我目前仍在尝试在网格中显示纹理。 我尝试使用PIXI.Mesh和PIXI.SimpleMesh。 我需要创建自己的着色器还是可以使用PIXI.MeshMaterial?

const bitmapFontText = new PIXI.BitmapText(
    'Lorem ipsum dolor\nsit amet consetetur\nsadipscing elitr sed', 
    { font: '55px Desyrel', align: 'left' }
);

const texture =  PIXI.RenderTexture.create({ width: 800, height: 600 });
app.renderer.render(bitmapFontText, texture);

const vertices = [
    -0.5, -0.5,
    0.5, -0.5,
    0.5, 0.5,
    -0.5, 0.5
];
const uvs = [
    0, 0,
    1, 0,
    1, 1,
    0, 1,
];
const indices = [0, 1, 2, 0, 2, 3];
const geometry = new PIXI.MeshGeometry(vertices, uvs, indices);
const shader = new PIXI.MeshMaterial(texture);

const mesh = new PIXI.Mesh(geometry, shader);
app.stage.addChild(mesh);

https://www.pixiplayground.com/#/edit/7RHqFti0tdSzw -6iOtylk

-
_Edit_:已修复。 顶点需要表示像素坐标。 _下一步_:在网格中使用多个纹理。

const vertices = [
    0, 0,
    500, 0,
    500, 500,
    0, 500
];

-
_编辑2_:这仅在所有标签都使用一种纹理时才起作用,对吗? 我可能说错了。 标签将是唯一的,但内容不会在每一帧中都改变。

我注意到,即使我不更新职位(游乐场),FPS仍保持不变。 是否只有在文本更改时才可以重新渲染?

PIXI.Mesh可以帮助您吗? 您知道我可以从中获得任何有关PixiJS渲染过程的资源吗?

@ChristophWalter您可以自己创建渲染器(而不是使用应用程序),设置一个代码循环,当场景改变时调用Renderer.render _only_。

您还可以将autoStart: false传递给Application选项,然后在发生更改时调用app.render() 。 相同的差异

谢谢,它以某种方式可以从文本生成纹理并在子画面上使用它。 但是我目前不明白为什么,也无法在操场上复制它。 😄

但是,该应用程序现在每帧以60FPS更新所有1500个标签位置。 此外,文本内容每秒都会更新一次。 这导致每秒短暂冻结。 因此,下一步将是使这些文本更新异步,例如在Web worker中。 我目前正在阅读有关ImageBitmap和OffscreenCanvas的文章。 这对其他人可能很有趣,所以我将分享我的进展。

几周前我停止调查后的简短更新
我在网络工作者中渲染了文本,该工作实际上非常简单:

// render-text-worker.js
onmessage = function(event) {
    const textLines = event.data.text.split(/\n/);
    const index = event.data.index;
    const offscreen = new OffscreenCanvas(150,45);
    const ctx = offscreen.getContext("2d");
    ctx.font = "15px monospace";
    textLines.forEach((text, index) => {
        ctx.fillText(text, 0, 15 + index * 15)
    })
    const imageBitmap = offscreen.transferToImageBitmap();
    postMessage({imageBitmap, index});
};
// index.js
const worker = new Worker("render-text-worker.js");
const callbacks ={}
function getLabelTexture(index, text, callback) {
  callbacks[index] = callback
  worker.postMessage({ index, text });
}
worker.onmessage = function({ data }) {
  const callback = callbacks[data.index]
  callback(PIXI.Texture.from(data.imageBitmap));
}

不幸的是,我的用例没有任何改善。 渲染文本时,框架仍然掉落。 可能是由于从工作人员传输图像位图所需的工作。

对于我们的特定用例,我们建议减少每个标签的文本长度,以达到性能要求。

此页面是否有帮助?
0 / 5 - 0 等级