The question is broad so I will try to make it as precise as I can.
I coded program that loads and renders just one model with several textures. Due to fact that I worked with single model I was able to form all buffers, enable all vertex attrib arrays, bind all vertex arrays and bind and set active textures just once prior to loop that was responsible for drawing.
Therefore my program on each iteration of drawing loop was executing just single line- glDrawArrays. Can the same be done in case of numerous objects or I do need to form all buffers, enable attrib arrays, bind and set active textures, set shader programs and so on on each iteration of drawing loop (that means sending tons of data to video card that should be slow)?
OpenGL (Open Graphics Library) is a cross-language, cross-platform application programming interface (API) for rendering 2D and 3D vector graphics. The API is typically used to interact with a graphics processing unit (GPU), to achieve hardware-accelerated rendering.
It is unclear what exactly you are looking for - and how many objects we are talking about.
Therefore my program on each iteration of drawing loop was executing just single line- glDrawArrays. Can the same be done in case of numerous objects or I do need to form all buffers, enable attrib arrays, bind and set active textures, set shader programs and so on on each iteration of drawing loop (that means sending tons of data to video card that should be slow)?
Yes, that would be slow. Buffer objects allow you to store data in a way that is accessible to the GL. In the ideal case, the GL can decide to store that data directly in the VRAM (although you never have total control over that with OpenGL). So if you have static, unchanging mesh data, uploading it once is the way to go. It might also be useful to coalesce the data of many small objects in a single buffer.
You can use Vertex Array Objects (VAOs) storing the vertex attribute pointers and enables, so at draw time, you can just bind the VAO and issue the draw call. Thus, the basic approach for rendering multiple objects would be
// ... at initinialization
for each object:
create and upload VBO(s) and index buffers
create and upload textures
create and initialize VAO
// at draw time
for each object:
bind VAO
bind texture(s)
set all other object-related OpenGL state
(like switching programs, setting unforms for
the model matrix, base colors, ...)
glDraw*(...)
If you only draw a couple of hundred objects per frame, you will probably not run into performance problems using this method. (Don't get me wrong here, I'm only talking of the overhead of a single draw call per object here, not the rendering costs for the actual objects - if your objects have millions of vertices, or you are generating lots of fragments, you can still get the performance down with very few or a single object. In that case, you need a more clever strategy to efficiently render your objects itself, e.g. by applying Level-of-Detail methods)
In general, there are two main approaches to improve the performance of such a render loop:
Reduce the number of state changes.
Switching different GL states implies performance penalties. A standard approach is grouping the objects per shader program, texture and so that you can draw multiple objects without having expensive state switches inbetween.
Have a look at this answer to a related question for the relative costs of different state changes.
Increase the number of objects drawn by a single draw call. In a way, this also implies approach 1, as you can't switch OpenGL state during the draw call. However, with modern GL, you can for example use array textures and put the textures for a different objects into a single texture object (you can also do that without texture arrays by using texture atlasses, and you can combine both).
Other very interesting features in this regard are
In recent years, there have been proposed some strategies to efficiently render many objects, which are known under the title Approaching Zero Driver Overhead (AZDO).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With