1
\$\begingroup\$

I am designing a Spritebatch class, for static and dynamic objects with WebGL. A problem I'm facing is that I have read several different opinions on sprite batching but with one goal.

  • Put all vertices in one buffer and render them

So in WebGL I'm using gl.bufferData(....,new Float32Array(size), gl.STEAM_DRAW).

And here is my first problem: when the spritebatch should be dynamic then size is not fixed and will increase, which leads to recreating the Float32Array which I found out is very expensive for n ≥ 10000 (at least on my machine).

Second Problem, let's say I give the Float32Array(maxElements) a maximum size, and I add 4 Sprites then I have allocated much more than I actually need.

Other way: I create Spritebatch when I know how many sprites I have. So basically I put 4 Sprites into my scene, then before rendering I create a Spritebatch with size 4 * numVerticesPerSprite. However let's say I want to update Sprite 2, I need some kind of index structure in my Spritebatch class to identify at which position the vertices of Sprite 2 are stored inside the SpriteBatch (inside Float32Array()).

So my question is :

How is a dynamic Spritebatch supposed to work and can you think of an indexing method to identify Sprite X's vertices inside the Float32Array to update/remove them? (Additionally: Do particle systems solve what i am looking for? I assume they are also some kind of sprite batching)

\$\endgroup\$
4
  • \$\begingroup\$ As far as I know, sprites are just rectangles or squares, so you could just use instanced rendering, so you don't nees to update the vertices array \$\endgroup\$
    – Bálint
    Commented Jun 23, 2017 at 13:07
  • \$\begingroup\$ Yes but instancing is only available in WebGL 2 \$\endgroup\$
    – greedsin
    Commented Jun 23, 2017 at 13:08
  • \$\begingroup\$ Why not have a fixed size for your sprite batch and simply flush/draw the moment the buffer is full and start over with batching next sprites? \$\endgroup\$
    – Sidar
    Commented Jun 27, 2017 at 19:54
  • \$\begingroup\$ This is exactly what happens, still I'm missing a dynamic data binding between the Sprite Object and the the SpriteBatch/Scene \$\endgroup\$
    – greedsin
    Commented Jun 28, 2017 at 9:18

1 Answer 1

1
+50
\$\begingroup\$

For updating sprites: You can use bufferSubData to overwrite a section of the buffer with new data. As far as knowing how to index that sprite, they should all be the same size and don't share any vertices, so it's merely a multiplication of index * sizeof(Sprite).

For adding new sprites: You could have an abstraction layer dynamically reallocate the buffer, doubling in size each time you run out of space. This is how dynamic arrays like vector or ArrayList work in other languages.

However, since reallocating requires storing a copy of your data client-side, you could make do with pre-allocating a fixed buffer that will be a hard limit on your total number of sprites, but it would be okay as long as you're mixing deletions with additions and you can guarantee the total active sprites is less than your pre-allocated capacity.

For deleting sprites: Depending on your workflow, you could do several different strategies.

1) When deleting sprite i, move the last sprite into index i and decrement your total sprite count. This also requires storing the sprite data client-side in a javascript array, so use this strategy only if you're also dynamically reallocating in your addSprite function.

2) When deleting a sprite, zero it out in the array and add its index to a "free list" to make it available for reuse next time you create a new sprite. This lets you recycle unused slots in your array without having to allocate a larger buffer.

JsFiddle proof-of-concept demo: see the var a = batch.addSprite(...); a.moveTo(...); a.delete(); section. https://jsfiddle.net/talyian/6pry2Lr1/

\$\endgroup\$
2
  • \$\begingroup\$ +1 for bufferSubData, didnt know about that. Where would you store the index for an sprite? A counter inside scene? I'm missing the data binding :( \$\endgroup\$
    – greedsin
    Commented Jun 27, 2017 at 7:11
  • \$\begingroup\$ I whipped up a simple example here: jsfiddle.net/talyian/6pry2Lr1 . I used the "free list" approach to delete, which lets me get away without storing any vertex data client side. the example here just uses a fixed size batch buffer for 1000 sprites, although note it only draws as many as have been added. \$\endgroup\$
    – Jimmy
    Commented Jun 27, 2017 at 18:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .