What is the best way: if I use glDrawArrays
, or if I use glDrawElements
? Any difference?
-
The accepted answer is slightly outdated. Following the doc link in Jorn Horstmann's answer, Apple describes **how to use "degenerate-triangles" trick with DrawElements**, thereby gaining the best of both worlds. The minor savings of a few indices by using DrawArrays isn't worth the savings you get by combining ***all*** your data into a single GL call, DrawElements. (You could combine all using DrawArrays, but then any "wasted elements" would be wasting vertices, which are much larger than indices, and require more render time too.) BEST: A single DrawElements call with GL_TRIANGLE_STRIP. – ToolmakerSteve Sep 24 '15 at 13:11
4 Answers
For both, you pass OpenGL some buffers containing vertex data.
glDrawArrays is basically "draw this contiguous range of vertices, using the data I gave you earlier". Good:
- You don't need to build an index buffer
Bad:
- If you organise your data into GL_TRIANGLES, you will have duplicate vertex data for adjacent triangles. This is obviously wasteful.
- If you use GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN to try and avoid duplicating data: it isn't terribly effective and you'd have to make a rendering call for each strip and fan. OpenGL calls are expensive and should be avoided where possible
With glDrawElements, you pass in buffer containing the indices of the vertices you want to draw.
Good
- No duplicate vertex data - you just index the same data for different triangles
- You can just use GL_TRIANGLES and rely on the vertex cache to avoid processing the same data twice - no need to re-organise your geometry data or split rendering over multiple calls
Bad
- Memory overhead of index buffer
My recommendation is to use glDrawElements

- 2,979
- 18
- 22
-
Not sure how good this would be for something with tons of static verts, like terrain-- the overhead of indices seems too great. The benefit of drawrangeelements seems ideal for terrain though in terms of rendering flexibility, and seems like it would outweigh any downsides. Just a thought. – scape Oct 01 '13 at 13:17
-
@scape - IMHO even if the verts are static, because an index is so much smaller than the vertex data itself, its not a big deal to send all those indices. I say stick to DrawElements for the flexibility. (Or with vbos, do the equivalent by including an index buffer). – ToolmakerSteve Sep 24 '15 at 12:43
-
@ryanm - FWIW, if someone has a reason to use DrawArrays, there is a widely-described trick for combining strips in order to send them all in a single call: duplicate the last vertex of one strip and the first vertex of the next strip. The result is two degenerate triangles, that have zero area. I just mention this, to stop the mis-information that DrawArrays inevitably is highly inefficient. But personally its too much of a pain for minimal gain, compared to having indices... *UPDATE* I just saw that Jorn Horstmann mentions this in his answer. – ToolmakerSteve Sep 24 '15 at 12:45
-
UPDATE #2: Just read the doc link from Jorn Horstmann's answer. Merging triangle strips works well with DrawElements also, so there is no reason to bother with DrawArray. As the doc says, it is more important to minimize the number of gl calls you make, so take ***all*** your data, and combine it into a single triangle strip. This allows you to mix "efficient" triangle strips with arbitrary geometry, all in a single call. – ToolmakerSteve Sep 24 '15 at 12:57
The performance implications are probably similar on the iphone, the OpenGL ES Programming Guide for iOS recommends using triangle strips and joining multiple strips through degenerate triangles.
The link has a nice illustration of the concept. This way you could reuse some vertices and still do all the drawing in one step.
For best performance, your models should be submitted as a single unindexed triangle strip using glDrawArrays with as few duplicated vertices as possible. If your models require many vertices to be duplicated (because many vertices are shared by triangles that do not appear sequentially in the triangle strip or because your application merged many smaller triangle strips), you may obtain better performance using a separate index buffer and calling glDrawElements instead. There is a trade off: an unindexed triangle strip must periodically duplicate entire vertices, while an indexed triangle list requires additional memory for the indices and adds overhead to look up vertices. For best results, test your models using both indexed and unindexed triangle strips, and use the one that performs the fastest.
Where possible, sort vertex and index data so that that triangles that share common vertices are drawn reasonably close to each other in the triangle strip. Graphics hardware often caches recent vertex calculations, so locality of reference may allow the hardware to avoid calculating a vertex multiple times.
The downside is that you probably need a preprocessing step that sorts your mesh in order to obtain long enough strips. I could not come up with a nice algorithm for this yet, so I can not give any performance or space numbers compared to GL_TRIANGLES. Of course this is also highly dependent on the meshes you want to draw.

- 1
- 1

- 33,639
- 11
- 75
- 118
-
NOTE: The current version of that document no longer mentions DrawArrays. Instead, they show DrawElements, and using the degenerate triangles trick with that. This gives the best of both approaches: can handle arbitrary models (at a slight overhead, but the overhead is extra indices, not extra vertex data, so is minor), and gain the optimization of minimizing data when your triangles are in strips. – ToolmakerSteve Sep 24 '15 at 12:54
The accepted answer is slightly outdated. Following the doc link in Jorn Horstmann's answer, OpenGL ES Programming Guide for iOS, Apple describes how to use "degenerate-triangles" trick with DrawElements, thereby gaining the best of both worlds.
The minor savings of a few indices by using DrawArrays isn't worth the savings you get by combining all your data into a single GL call, DrawElements. (You could combine all using DrawArrays, but then any "wasted elements" would be wasting vertices, which are much larger than indices, and require more render time too.)
This also means you don't need to carefully consider all your models, as to whether most of them can be rendered as a minimal number of strips, or they are too complex. One uniform solution, that handles everything. (But do try to organize into strips where possible, to minimize data sent, and maximize GPU likeliness of re-using recently cached vertex calculations.)
BEST: A single DrawElements call with GL_TRIANGLE_STRIP, containing all your data (that is changing in each frame).

- 18,547
- 14
- 94
- 196
Actually you can degenerate the triangle strip to create continuous strips so that you don't have to split it while using glDrawArray.
I have been using glDrawElements and GL_TRIANGLES but thinking about using glDrawArray instead with GL_TRIANGLE_STRIP. This way there is no need for creating inidices vector.
Anyone that knows more about the vertex cache thing that was mentioned above in one of the posts? Thinking about the performance between glDrawElements/GL_TRIANGLE vs glDrawArray/GL_TRIANGLE_STRIP.

- 36
- 3
-
See the doc link in Jorn Horstmann's answer, and my comment on that. Don't try to eliminate the index buffer. Use the triangle-strip-plus-degenerate-triangles technique with DrawElements. The extra cost of having index buffer is minor, and this allows you to combine ***all*** your geometry into a single call. Without wasted vertices, which are costly. Don't have to weigh trade-off between well-stripped geometry and arbitrary models that don't form good strips. – ToolmakerSteve Sep 24 '15 at 13:01