Reputation: 39
Can you render a VBO of quads each with a different texture?. Now, i read about sorting by texture or texture atlasses but that still doesn't answer my question. I'm working on a 2d game. Now my animated sprites are going to have a texture atlas for their frames and also a normal map, and all of them are going to share the same VBO (if possible). So each sprite is going to have an atlass (some animations could have lots of frames and poses that could maybe fill a 4096*4096 texture). So is it possible? Yes or no. If not is it efficient to have an indexed VBO for each sprite with all the texture coords for all its animation frames and to send only 4 indices each frame (for a single animation frame) and change the texture for each VBO? EDIT: also some of them may be moving(obviously) and some may be not.
After thinking about it a bit i realised that memory usage is also a problem. Those texture atlasses are going to eat a lot of memory. A 4096*4096 RGBA texture takes 64 MB, wich is a lot (and that's without the normal map wich would double the usage). And i don't think i could cram so many animations into a single atlass. Older games like Diablo, or those on Infinity Engine required only a few megs of VRAM and they looked very good.
Upvotes: 3
Views: 4992
Reputation: 2299
Just to clarify, the VBO can contain texture coordinates but has no knowledge of which textures will be applied to it.
Leave the VBO independent of the textures and compute the texture coordinates in the fragment/pixel shader according to an animation/frame index. Assuming you have quads in your VBO, then you set the texture coordinates so they just map the entire texture. Then in your shader you will scale and translate the texture coordinates to map a single frame on the texture atlas. You can then give the animation index, numbers of frames in the atlas and so on as uniform values to the shader.
Edit (to further clarify):
Texture coordinates for a quad
(0,1) (1,1)
x-------------x
| |
| |
| |
| |
| |
x-------------x
(0,0) (1,0)
This corresponds to mapping the entire texture to this single quad.
Let's say your texture is conveniently split into 16x16 "frames", stacked in a row-column order in your texture atlas. The size of a single frame is therefore 1/16 in texture coordinates in both u and v respectively. This is your moving window. Now in your shader, you pass on the "frame" number for your animation and the texture coordinate for each vertex in your quad is it's texture coordinate scaled by 16 and then translated by the frame (0-based integer):
float scale = 0.0625 // 1/16.
texCoord *= scale;
texCoord += float2(scale*frame%16, scale*(frame/16))
Now I'm writing this off the top of my head here so there might be minor errors. also, this code assumes texCoord is the texture coordinate of the fragment on the quad. Note that computing 1/16 once is much cheaper than repeatedly dividing by 16, per pixel may I add. The line float2(scale*frame%16, scale*(frame/16)) can be confusing if you are not already following me. A simpler case:
(with a total of 64 frames in an 8x8 grid)
frame 0 1 2 3 4 5 6 7 8 9 10 11 12
x = frame%8 0 1 2 3 4 5 6 7 0 1 2 3 4
y = frame/8 0 0 0 0 0 0 0 0 1 1 1 1 1
(note integer division)
Upvotes: 6
Reputation: 36487
Sure, it's possible (assuming texture coordinates stay the same). Just use glBindTexture()
to attach the texture to be used and glActiveTexture()
to select the texture unit to be modified.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE2D, texture_texid);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE2D, normalmap_texid);
DrawStuff();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE2D, texture2_texid);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE2D, normalmap2_texid);
DrawStuff();
Obviously glActiveTexture()
can be skipped if you're working with one texture only.
Upvotes: 1