How to properly utilize unique shader data across 10k ish sprites

Godot Version

v4.5.1.stable.mono.official [f62fdbde1]

Question

I am porting an older game that has a map space of 54x54 tiles. There is 3 Layers (Tile, Objects, Characters) and a couple of other times that sprites are drawn. This results in a possible maximum sprite count of ~8748. All of these sprites historically have had several effects done via “shaders” (they were originally just directdraw blitting, then when I ported it to SDL they were shaders.

When I got to this stage in godot, I got the shader working, I got it using instance uniforms, so that I could just use the same shader across tiles/objects. And immediately started getting errors about the Instance Buffer Size? Mine is currently set to 65536, and i’m super hesitant to increase it, because for something so simple it makes me think I’m doing it wrong.

When googling, I don’t really get any advice from reddit other than increase the size. I also found a couple of videos talking about MultiMeshInstance2D, which maybe an option, but I can’t quite figure out how to get it to even render a single sprite, let alone an actual sprite from my atlas, with the shader.

The google ai response seems to try and point me toward encoding the effect data into modulate and then ripping it out from that in the shader.

For the vast majority of these sprites, I just need to pass 1 unique int, that I can unpack into the various possible effects. The only other shader esque thing I have need of now, is that magic effects are technically done with a blend_add shader, that draws a specific hexagon type shape. I was going to attach it to a sprite on each character, and show it when it’s needed. But I’d love to just add it to the main shader for each character sprite. The magic shader needs a vec3 color, and an int strength.

I realize I never ran into this issue when I did SDL because I wasn’t batching very many draw calls.

What is the idiomatic way to accomplish this?

Have you looked at Godot’s tile map? Other than than, multi mesh instance should be able to do this.

1 Like

If you are using per-instance uniforms then, yes, you’ll need to make the buffer size bigger with that many instances. They have some limitations:

The default value 65536 can hold up to 4096 instances (65536/16 values per instance = 4096)

The buffer also has a hard limit of 1024 if you are using the compatibility renderer.

I did but I ran into a lot of limitations with shading individual tiles, which is done for lighting. Once I solved that creatively (bound texture) for the background tiles which are consistently 32x16. I could do it for the irregularly sized tiles or partially used tiles on the object layer. But there are significantly less objects on screen generally.

So you have any recommended reading or view for how to correctly use multimeshinstance2d.

I feel like I read in the doc that 4096 was already close to the limits for even modern gpus which is where my hesitance was. But now that you got me thinking about it is that limit per draw call, could I give each later a unique material but the same shader to bypass it? Since each layer alone seemed fine when running I only hit the issue when doing the second and first layer

It’s the same as using the 3D counterpart. There’s a basic tutorial on this in the docs:

If you have any specific question/problem - aks away.