WebGL 中的顶点数有限制吗?
Three.js 表示它无法加载超过 65k 个顶点。
在我的纯 webgl 应用程序中,它没有说什么,但当我尝试大对象时,它不会显示整个对象。
我可以将我的对象分割成更小的缓冲区,但这会让我感到难过。
还有更好的解决办法吗? 65k真的是顶点数量的限制吗?
Three.js says that it can't load more than 65k vertices.
In my pure webgl application, it doesn't say anything, but it doesn't show the entire object when I try big objects.
I could split my objects into smaller buffers, but it would make me sad.
Is there any better solution? Is 65k really the limit amount of vertices?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
是的,WebGL 的顶点索引缓冲区目前仅限于 16 位。这是因为他们的目标是使 1.0 版本尽可能跨平台,因此倾向于使内容以最低公分母为目标 - 在这种情况下,移动平台具有有限的图形硬件。
一旦 1.0 发布并且最初的热潮结束,他们可能会在扩展的帮助下放松这些限制——应用程序将能够询问实现是否支持给定的扩展,如果支持则使用它就像常规桌面 OpenGL 一样。已经有一些可用的扩展,但同样,它们只允许具有非常广泛的硬件支持的扩展,因此没有任何东西可以帮助您增加顶点数。然而,一旦他们放宽了跨平台要求,他们很可能支持诸如允许 32 位顶点索引的 GL_OES_element_index_uint 扩展之类的东西。
您可以在公共 WebGL 邮件上阅读 这些问题的一些讨论列表。
Yes, WebGL's vertex index buffers are limited to 16-bit right now. This is because they're aiming to make version 1.0 as cross-platform as possible, so there's a tendency to make stuff target the lowest common denominator -- in cases like this, mobile platforms with limited graphics hardware.
Once 1.0 is out and the initial rush is over, they're likely to loosen these constraints with the help of extensions -- an app will be able to ask whether a given extension is supported by the implementation, and make use of it if it is -- just like in regular desktop OpenGL. There are already a few extensions available, but again they've only allowed ones with very broad hardware support, so nothing that would help you increase your vertex count. However, once they loosen the cross-platform requirement, they are likely to support something like the GL_OES_element_index_uint extension that allows 32-bit vertex indices.
You can read some discussion of these issues on the Public WebGL mailing list.
一般来说,其他答案是正确的,但我想我应该添加一些说明:
WebGL(和 OpenGL ES 2.0)接受的唯一索引数据类型是无符号字节和无符号短整型。由于无符号短整型的范围为 0-65535,这意味着如果您使用 gl.DrawElements(大多数框架都这样做),则每次绘制调用只能引用 65k 个顶点。几乎可以肯定,这就是 Three.js 限制的来源。请注意,一次绘制调用中可以有超过 65k 个三角形,只要它们只共享 65k 个顶点。
如果您使用非索引几何体(gl.DrawArrays),则每次调用可以有更多顶点,但请记住,几乎总是需要重复其中一些顶点。我认为在大多数情况下,GPU 内存使用量的减少将证明拆分绘制调用是合理的。
Generally the other answers are correct, but I figured I would add a bit of clarification:
The only data types accepted by WebGL (and OpenGL ES 2.0) for indices are unsigned bytes and unsigned shorts. Since an unsigned short has a range of 0-65535, this means that if you are using gl.DrawElements (which most frameworks do) you can only reference 65k vertices per draw call. This is almost certainly where the three.js restriction comes from. Please note that you can have a lot more than 65k triangles in one draw call, as long as they only share 65k verts.
If you use non-indexed geometry (gl.DrawArrays), you can have a lot more vertices per-call, but bear in mind that almost always have to repeat some of them. I think in most cases the reduction in GPU memory usage will justify splitting up the draw calls.
目前,您可以做的是将大对象分为多个段,每个段有 65K 个元素,然后重新索引每个段,以便所有段的索引都从 0 到 65K。我已经测试过了,WebGL 允许这样做。
现在,您必须计算分段之间共享的那些顶点。在这种情况下,最简单的替代方法是复制该顶点,这样就不再有共享顶点。但还有更多内存友好的替代方案。
我有一个关于此工作的小型演示(具有大约 350K 顶点的大脑模型,分为 5 个部分)http://youtu.be/AXZiNHkMpZs# t=2m33s
我希望它有帮助;-)
For the moment being, what you can do is to divide your big object in several segments of 65K elements each and re-index every segment so all the segments have indexes from 0 to 65K. I have tested it and WebGL allows it.
Now, you will have to workout those vertices that are shared among segments. In that case the simplest alternative is to duplicate that vertex so there are not shared vertices anymore. But there are more memory friendly alternatives.
I have a small demo of this working (brain model with approx 350K vertices divided in 5 segments) http://youtu.be/AXZiNHkMpZs#t=2m33s
I hope it helps ;-)
因为我无法对 Giles 发表评论,所以我将此评论放在这里:
OES_element_index_uint 已添加到“社区批准的 WebGL 扩展”中!
该扩展已在 Chrome Canary 中启用。
http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/
Because i can't comment on Giles i put this comment here:
OES_element_index_uint has been added to 'Community approved WebGL Extensions'!!
The extension is already enabled in chrome canary.
http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/
您可以使用
drawElements
(将索引数组遍历到顶点数组)或drawArrays
(直接遍历顶点数组)来绘制顶点。当您使用
drawArrays
时,属性缓冲区中的顶点数量似乎没有任何限制。使用drawArrays可能不太理想,因为对于典型的网格,您必须在每次顶点出现在基元中时指定它。另一方面,根据您的场景,这可能是减少 WebGL 调用次数的简单方法。我之所以提到这一点,是因为在阅读了这个问题及其接受的答案后,我很长一段时间都认为
drawArrays
中的顶点数量也被限制为 65K。偶然我发现事实并非如此,并且最终通过将具有常见材质的对象聚合到单个顶点数组中而获得了很大的加速(从而绕过了目前似乎给 ANGLE 实现带来负担的每个缓冲区的性能开销)。You can draw vertices using either
drawElements
(which traverses an array of indices into an array of vertices) ordrawArrays
, which traverses an array of vertices directly.There doesn't seem to be any limit on the number of vertices in an attribute buffer when you use
drawArrays
. UsingdrawArrays
is possibly less desirable because for a typical mesh you have to specify each vertex every time it appears in a primitive. On the other hand, depending on your scene, this may be an easy way of reducing the number of WebGL calls.I mention this only because after reading this question and its accepted answer I assumed for a long time that the number of vertices in a
drawArrays
was also limited to 65K. By accident I discovered it wasn't, and ended up getting a large speedup by aggregating objects with common materials into single vertex arrays (thus getting around the per-buffer performance overheads that seem to currently burden ANGLE implementations).十年过去了,自最近的 Safari 15 以来,WebGL2 现在已相当普遍。WebGL2 提供了所需的信息:
以及更多约束和其他数据,请参阅 此处[MDN]
A decade passed by and WebGL2 is now pretty universal since the recent Safari 15. WebGL2 provides the required information:
And a lot more constraints and other data, see here[MDN]
据我所知,这通常受到硬件和/或驱动程序软件的限制(硬件使用 16 位索引等)。也许 Three.js 只是为了安全起见,并尝试确保您的 webgl 应用程序适用于所有卡。也许最好的方法是将模型分解为更小的块,这将确保您的应用程序支持大多数(如果不是全部)当今使用的 GPU。
As far as I know, this is usually limited by the hardware and/or driver software (hardware is using 16-bit indices or such). Maybe Three.js just plays it safe and tries to makes sure your webgl-app works on all cards. Probably the best way is to break your models down into smaller chunks, this will make sure your app supports most if not all GPUs in use today.