Question

Three.js says that can't be loaded 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 am figuring out in split my objects to put in smaller buffers, but it would make me sad. Is there any better solution? Is 65k really the limit amount of vertices?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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 ;-)

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/

You can draw vertices using either drawElements (which traverses an array of indices into an array of vertices) or drawArrays, 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. Using drawArrays 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).

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.

  • Using immediatemode (glBegin...glEnd), there is no restriction in the amount of vertices you can push through, but it's going to be slow with that many vertices.
  • You could try using glGetIntegerv() with GL_INDEX_BITS, GL_MAX_ELEMENTS_VERTICES and GL_MAX_ELEMENTS_INDICES to query the amount of index bits, maximum vertices and maximum indices the card/driver supports.
  • If I remember correctly, Vertex Arrays and VBOs (Vertex Buffer Object) both have similar limits (on the same card/driver), so switching between them probably won't help (not 100% sure on this)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top