嗨,我目前正在研究PixiJS的一个新项目,到目前为止我真的很喜欢! 关于应用程序的性能有一些要求。 真正棘手的部分是,这将导致许多显示的文本标签不断更新。 我找不到进一步提高性能的方法,而我的最后希望是在这个社区中找到一些帮助。
1500个文字标签
每秒60个位置更新
60 FPS
我已经使用BitMapText创建了一个最小的示例,在MacBook Pro上导致〜28 FPS。
https://www.pixiplayground.com/#/edit/rLbAN_xrw7yUU_cg_c8Xv
您是否有任何改善的想法? 在此先多谢!
您确定要在所有时间上显示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所说的,
这提供了两个主要好处:
因此,基本上,该过程将如下所示:
这应该是一个简单的过程。 请告诉我们情况如何!
嘿,我尝试执行您的建议。 将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));
}
不幸的是,我的用例没有任何改善。 渲染文本时,框架仍然掉落。 可能是由于从工作人员传输图像位图所需的工作。
对于我们的特定用例,我们建议减少每个标签的文本长度,以达到性能要求。
最有用的评论
谢谢,它以某种方式可以从文本生成纹理并在子画面上使用它。 但是我目前不明白为什么,也无法在操场上复制它。 😄
但是,该应用程序现在每帧以60FPS更新所有1500个标签位置。 此外,文本内容每秒都会更新一次。 这导致每秒短暂冻结。 因此,下一步将是使这些文本更新异步,例如在Web worker中。 我目前正在阅读有关ImageBitmap和OffscreenCanvas的文章。 这对其他人可能很有趣,所以我将分享我的进展。