4

I'm wondering what would be the best thing to do if I want to draw more than ~6000 different VAOs using the same shader.

At the moment I bind my shader then give it all information needed (uniform) then looping through each VAO to binding and draw them.

This code make my computer fall at ~ 200 fps instead of 3000 or 4000. According to https://learnopengl.com/Advanced-OpenGL/Instancing, using glDrawElementsInstanced can allow me to handle a HUGE amount of same VAO but since I have ~6000 different VAO It seems like I can't use it.

Can someone confirm me this? What you guys would do to draw so many VAO and save many performance as you can?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Xemuth
  • 415
  • 3
  • 12

2 Answers2

7

Step 1: do not have 6,000 different VAOs.

You are undoubtedly treating each VAO as a separate mesh. Stop doing this. You should instead treat each VAO as a separate vertex format. That is, you only need a new VAO if you're passing different kinds of vertex data. The number of attributes and the format of each attributes constitute the format information.

Ideally, you only need between 4 and 10 separate sets of vertex formats. Given that you're using the same shader on multiple VAOs, you probably already have this understanding.

So, how do you use the same VAO for multiple meshes? Ideally, you would do this by putting all of the mesh data for a particular kind of mesh (ie: vertex format) in the same buffer object(s). You would select which data to retrieve for a particular rendering operation via tricks like the baseVertex parameter of glDrawElementsBaseVertex, or just by selecting which range of index data to draw from for a particular draw command. Other alternatives include the multi-draw family of rendering functions.

If you cannot put all of the data in the same buffers for some reason, then you should adopt the glVertexAttribFormat style of VAO usage. That way, you set your vertex format data with glVertexAttribFormat calls, and you can change the buffers as needed with glBindVertexBuffers without ever having to touch the vertex format itself. This is known to be faster than changing VAOs.

And to be honest, you should adopt glVertexAttribFormat anyway, because it's a much better API that isn't stupid like glVertexAttribPointer and its ilk.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thanks Nicol, but to recap : Since all my Data have the same vertex format I should only use One VAO. To do it I must rather put all my Data into one single buffer. Set the "how to read it (using glVertexAttribPointer ?) " and then when I want to draw one of them using glDrawElementsBaseVertex to select what portion of data I want to Draw. – Xemuth Jan 05 '20 at 15:39
2

glDrawElementsInstanced can allow me to handle a HUGE amount of same VAO but since I have ~6000 differents VAO It seems like I can't use it.

So what you should do is to combine your objects into the same VAO. Then use glMultiDrawArraysIndirect or glMultiDrawElementsIndirect to issue a draw of all the different objects from within the same VAO. This answer demonstrates how to do this.

In order to handle different textures you either build a texture atlas, pack the textures into a texture array, or use the GL_ARB_bindless_texture extensions if available.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Thanks, It's a good idea but it mean I cannot draw one of my VAO differently (like drawing everythings in GL_LINES_LOOP , but only one in GL_DRAW) without including it into another VAO. I guess it's not that's importante – Xemuth Jan 05 '20 at 15:29
  • 2
    @Xemuth what's GL_DRAW? If you want to combine GL_LINES with GL_TRIANGLES for example, then yeah, there's no way to combine different kinds of primitives in one call in plain OpenGL. – Yakov Galka Jan 05 '20 at 20:53