Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411423 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 19, 2024, 05:06:29 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Draw order with multiple VBOs?
Pages: [1]
Print
Author Topic: Draw order with multiple VBOs?  (Read 981 times)
CheeseCakeMan
Level 0
**


View Profile
« on: February 15, 2017, 06:45:07 AM »

Graphics performance hasn't been a problem in my game so far, so just using SFML and issuing a ton of draw calls was fine, until now. I haven't had much exposure to OpenGL yet so perhaps the solution is obvious to everyone but me.

If I understand VBOs correctly one of the benefits in a purely 2D and topdown environment is that I could draw a grid of tiles in one go. If all the textures are in one atlas the geometry and texture of the map would be in one big package, send in one go reducing the amount of draw calls immensely.

The draw order of the sprites seems to be the order in which the primitives are defined in the VBO. Because I sort manually on the CPU I have to create the VBO sorted as well, no problem here. Drawing two VBOs after another, the latter one seems to be drawn last. In a very simple case sorting wouldn't even be necessary, if the first sprite was in the upper left and the last one in the lower right we would get a reasonable draw order for free, back to front, left to right.

However, I can only use one texture with a VBO, unless I use shaders (and then there seems to be a limit too). Not all of my textures fit into one atlas (not even the largest texture size possibly on my GPU). I figured I just have to create multiple VBOs, each responsible for drawing sprites sharing the same atlas. But now I have no idea how to get the draw order right.

If I had 4 sprites. A, B, C, D. Drawn in that order, sharing the same texture, 1, I would just create one VBO. But what if they don't share the same texture? Perhaps they look like this: A(1), B(2), C(1), D(1).

One VBO would contain (A, C, D), bound to 1. One VBO would contain (B), bound to 2. However, B has to be drawn before C and D. If I would just draw the two VBOs in order, the draw order would be A, C, D, B. Oh.

My only idea so far is to create one VBO spanning each continous group of sprites using the same texture. So A(1), B(2), C(2), D(1), E(1), F(3) would create 4 VBOs; (A) bound to 1, (B, C) bound to 2, (D, E) bound to 1, (F) bound to 3.

That would work incredibly well if all the sprites shared the same textures and completely fall apart if by chance every other sprite would use a different texture. Is there a better way?
Logged
oahda
Level 10
*****



View Profile
« Reply #1 on: February 15, 2017, 06:48:57 AM »

If you're using OpenGL anyway, maybe you could try just setting z values (instead of sorting the vertices) and enable depth testing to ensure the correct appearance even if an object in a later VBO is supposed to be below one in an earlier one.
Logged

zilluss
Level 1
*



View Profile
« Reply #2 on: February 15, 2017, 07:14:41 AM »

Go with Prinsessas solution unless:

1) You are so short on VRAM that you can't afford a depth buffer.
2) You plan to use translucent sprites/fancy color blending that depends on the draw order.

Otherwise, if you still want to use sprite batching, make it explicit (you could make an autobatching system, but this is needlessly complex imo).
If you need a certain draw order just add a new batch to your scene. You can easily afford a bunch of draw calls before you run into performance problems.
Logged

@zilluss | Devlog  Hand Point Right
CheeseCakeMan
Level 0
**


View Profile
« Reply #3 on: February 15, 2017, 09:33:50 AM »

I don't use OpenGL directly. SFML allows some of the underlying stuff to be modified indirectly through a simplified interface. However SFML sprites do not have a z-value. I fear I either have to ditch SFML completely and learn OpenGL, or find a way to make this work with what I'm given.
Logged
JWki
Level 4
****


View Profile
« Reply #4 on: February 15, 2017, 09:42:13 AM »

Ditch SFML.
OpenGL isn't hard to learn especially not when you only care about rendering sprites and it's totally worth the effort to be able to solve issues like this one.
Logged
qMopey
Level 6
*


View Profile WWW
« Reply #5 on: February 15, 2017, 09:46:06 AM »

Actually I don't think the individual draw order of sprites is necessarily defined by the order of the vertices sent to the GPU. However in practice all machines I have run my game on *do* draw triangles in the order they are sent.

What you need is some kind of texture atlas tool. Then you can do one draw call per texture. You will want to create your textures so that sprites likely to be drawn at the same time lay upon the same texture (atlas).

For my own game I use two small C libraries called tinygl and tinydeflate. tinydeflate has a texture atlas creation tool, and tinygl does draw calls. I implemented a sprite sorter that takes sprites and sorts them first based on depth (each sprite has a depth value on the CPU), and then secondarily sorts them based on texture. I wrote a little about it here.

Generally it's fine to have a few different textures and have multiple draw calls. The point is to setup some code to do some automation/sorting, that way when writing your game you don't have to think about it. It's an abstraction. In my own game it looks like:

Code:
PushSprite( sprite );

// where sprite looks like:
sprite.tex = 0x0194F9DC;
sprite.w = 10;
sprite.h = 5;
sprite.uv = uv_coords;
sprite.depth = -4;

PushSprite collects sprite structs into an array. When I go to draw to the screen the array gets sorted into draw calls (like explained above). Each draw call is then sent to the tinygl.h header, and each draw call in tinygl.h gets sent off with glDrawElements. tinygl.h is probably a good header to read if you want to learn OpenGL stuff. Also this website is great for GL too.
Logged
oahda
Level 10
*****



View Profile
« Reply #6 on: February 15, 2017, 11:52:03 AM »

2) You plan to use translucent sprites/fancy color blending that depends on the draw order.
Oops, didn't think about transparency. Angry
Logged

DragonDePlatino
Level 1
*



View Profile WWW
« Reply #7 on: February 15, 2017, 07:50:26 PM »

I've used SFML and I wasn't aware it had support for Vertex Buffers. Are you sure you're not talking about Vertex Arrays like the one used in this example? You said you're avoiding the underlying OpenGL context which is what I did as well.
Logged

CheeseCakeMan
Level 0
**


View Profile
« Reply #8 on: February 16, 2017, 06:29:08 AM »

You're right, that's what I'm using. If I understand them correctly (and I have to admit that the definitions are pretty confusing to me) there is not much of a difference in usage and performance if the mesh is recreated every frame. VBOs seem to be superior if the data does not change and can just live in VRAM.

If I'm not mistaken that means that in this case I'm only reducing draw calls, but not the data shared between CPU and GPU.
Logged
qMopey
Level 6
*


View Profile WWW
« Reply #9 on: February 16, 2017, 09:26:56 AM »

Vertex array object is a dumb thing to store settings on a vertex buffer object. A vertex buffer object is a thing to hold verts. The verts can be updated as frequently or infrequently as the user likes using glMapBuffer/glMapBufferRange calls.

In the case of static geometry in a vertex buffer, you are not saving on draw calls necessarily, just saving some bus bandwidth and CPU time. Instead of sending the entire array to the GPU each game tick, you send an integer handle that represents the buffer sent a single time upon initialization.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic