允许更多的WebGL上下文

8

我正在制作一个有商品列表的网站,每个商品都有缩略图,并且我正在使用PixiJS为所有商品添加着色器效果。问题是列表上有超过16个商品,所以我遇到了以下错误:

警告:太多活动的WebGL上下文。 最旧的上下文将会丢失。

有没有办法增加此限制? 我不能制作整个页面的WebGL,而且使用非常有限(无交互,轻量级效果),因此我认为更多的WebGL上下文不会使页面变得卡顿或其他问题。

2个回答

19

不,无法增加限制。(好吧,你可以编写自己的浏览器)。

要创建项目列表,您可以使用像这个Q&A中的解决方案。

在同一页上使用多个WebGL模型

这些解决方案在WebGL的这篇文章three.js的这篇文章中有详细介绍。

以下是3种解决方案。

  1. (fastest) Use a single WebGL canvas that covers the page. Use place holder elements to mark where you want to draw things. Loop through those elements calling element.getBoundingClientRect and use the viewport and scissor settings to draw in those places, only drawing the ones that are visible (some may be offscreen and don't need to be drawn). This is the soution shown in the links above.

  2. Use a single offscreen WebGL canvas. Put 2D canvases in your page. Draw each item to the offscreen canvas and use drawImage to draw it to the correct 2D canvas. this solution is slightly more flexible since the 2D canvas elements can be more freely styled but it's slower than the previous solution and uses more memory.

    Note: it's probably best to make the WebGL canvas the size of the largest 2D canvas, then for each 2D canvas, set gl.viewport to the size of that 2D canvas and then use the full form of drawImage to select a portion of the WebGL the correct size portion of the WebGL canvas to draw the current 2D canvas. Resizing a canvas is a heavy operation I believe. In other words something like:

    for each 2D canvas
       webgl canvas size = max(webgl canvas size, 2D canvas size) // for each dimension
       gl.viewport(0, 0, 2D canvas size);
       draw scene for canvas
       ctx.drawImage(
           0, 0, 2D canvas size, 
           0, webgl canvas height - 2d canvas height, 2D canvas size)
    
  3. Use a virtual webgl context which you can implement on your own or use a library. Not recommended (slowest) but it is a quick solution.

注意:拥有多个上下文不是推荐的解决方案。WebGL上下文之间不能共享纹理、顶点和着色器。这意味着,如果您在2个或更多上下文中使用相同的图像,则必须为每个上下文加载一次图像。同样,对于每个上下文使用的着色器,都必须为每个上下文进行编译和链接。换句话说,使用多个上下文会使用更多的内存,并显著增加启动时间。
很遗憾,由于您同时标记了WebGL和pixi.js,所以这个答案可能与您无关。我不知道在pixi.js中是否可能做到这一点。我没有看到任何文档表明如何高效地实现它。

1
假设它们不是同时可见的(您必须滚动),您可以有几个上下文并在它们之间切换(与虚拟列表相同的原理)。 - XCS
这听起来像是一个慢速的解决方案。着色器和资源不能共享,因此每次交换时,您都必须编译正确的着色器并将正确的资源加载到该上下文中。 - gman
2
@gman 你不必真正交换上下文,你可以重复使用画布并将它们移动,就像虚拟列表一样。如果你有一个长滚动列表,这个解决方案可能会起作用,但这取决于他的内容/布局设计。我不建议这个解决方案,这只是一个可能的替代方案。 - XCS
1
@Aerodynamic 同样的方式,虚拟化列表也是这样工作的。如果您有一个包含20行的列表,但在视口中只有4行可见,那么您可以为4行(上方和下方各1行)创建画布。当您向下滚动时,只需将第一行(之前被隐藏的)移动到最后一行下面,并在其上绘制新的缩略图。请参阅此图像参考:https://webdev.imgix.net/virtualize-long-lists-react-window/difference-in-scrolling.jpg - XCS
1
@xcs,这样做是行不通的,因为您无法在上下文之间任意移动资源。您有画布A(立方体),B(球体),C(棱柱体)。当A滚动到底部时,您将其放置在底部,现在有B(球体),C(棱柱体),A(圆环体)。现在,A需要在该画布中放置任何所需内容(圆环体),但它已经具有状态为立方体的上下文。 - gman
显示剩余5条评论

4

如果您可以控制正在使用的浏览器,那么有一种替代解决方案。 Chrome具有以下命令行开关以控制活动上下文的最大数量。

--max-active-webgl-contexts=<number>

您可以使用此参数设置快捷方式,以获得没有限制的Chrome浏览器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接