Make sprite animation


#1

Hello guys,
I’m wondering what it’s the best way to display an animation of sprites
For now, I load all my sprites and I store them in a vector

But I think that will be better if I would load them in the GPU ?

Is that possible ?


#2

Hi,

You might want to take a look here.


#3

There are a bunch of great ways to do it. Using a spritesheet is definitely one of them. An advantage of something like a spritesheet is that when openGL binds a texture, it only has to do it once per frame, and not multiple times for different textures. This is especially helpful if you have a lot of instances of the same sprite on screen at once.

In the past when I’ve needed to bind a lot of textures and needed great performance, I’ve used 2D sampler arrays. These will let you pass in “3D” arrays of textures, and I think on my system I can pass up to 2048. GL_TEXTURE_2D_ARRAY is the thing to google. You’ll need to write a custom shader, and then in the texture lookup, you pass in a vec3 instead of a vec2, where the z is an index for which texture you’re looking up.

Lastly, a while back I made a simple block for animated gifs. New block - ciAnimatedGif Depending on your app structure and performance needs, this can also work in a pinch.

TLDR: Try spritesheets, and gifs in that order. If you need performance, check out GL_TEXTURE_2D_ARRAY.


#4

Thanks for your answer,
I try to create a shader by myself, with the cinder’s guide but i don’t understand how to use shaders with my images, so do you have any tips ?


#5

Take a look at the shader guide:
https://libcinder.org/docs/guides/opengl/part5.html

In the section of texture loading you can add more textures to your fragment shader.

		uniform sampler2D	uTex0;
		uniform sampler2D	uTex1;
                ....
		uniform sampler2D	uTexN;

The pass it like this

mGlsl->uniform( "uTex0", texture0->getId() );
mGlsl->uniform( "uTex1", texture1->getId() );
...
mGlsl->uniform( "uTexN", textureN->getId() );

I think you can upload the textures just once, but not sure.
You can also control wich texture to draw if you already have a vector of textures:

mGlsl->uniform( "uTex0", textures[id]->getId());

#6

That’s incorrect. The uniform should be set to the texture unit the texture is bound to. So for instance:

texture0->bind( 10 ); // unit can be chosen freely up to a maximum
texture1->bind( 11 );

mGlsl->uniform( "uTex0", 10 );
mGlsl->uniform( "uTex1", 11 );

It’s better to do the following, though:

gl::ScopedTextureBind scpTex0( texture0, 10 );
gl::ScopedGlslProg    scpGlsl( mGlsl );

mGlsl->uniform( "uTex0", 10 );

That way, the OpenGL state will be restored when you’re done drawing. It’s good to get into the habit of managing your state like that.

As @Xumo correctly pointed out, you only need to bind your textures once (if you’re not going to reuse that texture unit for something else), for example in your setup(). And if you do, you also only need to set the uniform once.

-Paul