I am relatively new to modern openGL and so I’m still getting to grips with many things.
I have a 2D engine that draws sprites on two triangles on the screen. Super simple. However for the purposes of learning and making a 2D engine that can do super particles, I want to try and convert the engine to use only instancing. In my mind it shall work quite well because the mesh never changes, it’s just a square of two triangles, its matrix changes and it’s texture, thats it. Therefore I’m hardly going to loose much performance by using instancing and it will make the engine faster when rendering many particles.
Anyway moving on. I have taught myself how to use glVertexAttribDivisor to send my matrices into the shader quite well. But I need to send textures in as well. I am having much more difficulty with this as I can’t find much in the way of examples, and I’m too inexperienced to work it out on my own. So is it a thing you can do? Send an array of textures to the shader and use the InstanceID to pick out the correct texture?
If it is possible how do I do it?
You can not change rendering state in the middle of a single draw call. So if your non-instanced pattern was [BindTexture; Draw; BindTexture; Draw], you won’t be able to directly replace that with a single Draw*Instanced call.
Depending on how much texture data you have, you can arrange things to work within a single draw call, via a few different methods:
- combine multiple textures into a texture atlas. Per-instance data must include offsets into the atlas. (good for 2D sprites; but be aware of atlasing complications with texel filtering.)
- combine multiple 2D textures into a 2D array texture. Per-instance data includes the slice into the array. (avoids filtering issues; but note that popular platforms like ES2 on iOS don’t support array textures.)
- bind multiple textures (up to i.e. MAX_TEXTURE_IMAGE_UNITS.) Per-instance data includes the index into the array of samplers. (note that dynamically indexing into an array of samplers may or may not be allowed, depending on your GLSL version.)
Keep in mind that all of these solutions increase the texture footprint that has to be simultaneously accessible to the GPU during the single instanced draw call. If you have a truly huge amount of texels (i.e. exceeding the amount of VRAM on a discrete desktop GPU), the old [BindTexture; Draw; BindTexture; Draw] pattern is potentially better.
Thanks for the info. I think the best approach is to use a texture atlas. In that situation I can batch render sprites using the same texture atlas.
Can I ask another question that pops into my head, when batch rendering by texture/material, how do you go about zdepth sorting, especially when using alpha blending?