Spritesheet Animation in OpenGL

Adfa6cf87d3749a0e1acd928285b3f23
1
WDR 106 Jan 19, 2014 at 17:20 spritesheet animation opengl

Hi… Could someone please point me to a tutorial or method on how to accomplish sprite sheet animation in OpenGL. So far, I haven’t found anything proper on Google pertaining to the subject. I did find one tutorial (sort of) that shows how to do animation using sprites (OpenGL Animating Textures). However, this person loads each sprite texture separately in a texture array rather than a single sprite sheet. He then used each array element as a frame and then incremented the frames in the display function in a steady loop. Though this method gives off an effect of movement, I’m pretty sure it is a very crude way of animation because it does not make use of a fixed time step between frames or frame-rate or any sort of time function for that matter. Also, the animation coupled with translation of the sprite, gives off a very choppy animation effect. How do I achieve this without it giving off a choppy effect using a fixed frame-rate? I am perfectly able to display individual sprites from a sprite sheet, no problems there. Just want to know how to animate a sprite sheet using those individual sprites. Please help me. Thank you.

4 Replies

Please log in or register to post a reply.

6837d514b487de395be51432d9cdd078
3
TheNut 179 Jan 19, 2014 at 20:59

I’m not aware of any tutorials on this subject. I developed my solution simply on intuition. You seem to have an idea what to do. You know for instance that you need a proper timer to cycle between frames and you’re looking for how to work with sprite sheets (aka: sprite atlases), so I’ll try and give you a few pointers.

1. Textures I assume you are already fluent with OpenGL textures? How to load them into video memory, bind them, and place them on polygons? That’s about 80% of the problem. The other 20% is how to display only portions of the texture on the screen (see point 3 and 4).

2. Sprite Sheets You will need some sort of file format that describes your (x,y) locations and width x height dimensions of all the sprites in your sprite sheet. I use my own Texture Packer tool, which outputs a single image file + XML file describing the coordinates. There are other tools out there more dedicated to that. Just doing a Google search for “Sprite Packer” will net you a few links.

It’s important to pack relevant textures into a sprite sheet. Sprite sheets serve two purposes. The first purpose was to reduce wasted texture space back when textures had to be a power of two. Simply uploading a single 100x200 image would expand to 256x256 in video memory, creating waste. Although that’s not a big concern anymore (video graphics has matured), speed is another key reason. Binding a single texture and then rendering a dozen sprites is more efficient than binding a texture for each sprite. This is most important when you get into rendering bitmap fonts (it follows the same principles as this).

3. Coordinates Once you load in your sprite sheet, you want to translate the coordinates into texture space. When you deal with images, you often work in pixels. A 320x400 image for example. In video graphics, texture coordinates are normalized. That is, they are represented between 0.0 and 1.0. So let’s say you pack all your sprites in a 1024x1024 texture. Let’s say your 320x400 image is located at the offset (x,y) = (200,100). You need to prepare what I call a “Sprite Frame” that describes these coordinates in texture space. Simply put:

Frame.X = 200 / 1024; Frame.Y = 100 / 1024; Frame.Width = 320 / 1024; Frame.Height = 400 / 1024;

You now have the texture space coordinates for your sprite.

4. Rendering the frame I assume you know how to render polygons in an orthographic view (although you could also render sprites in perspective if you wanted). Regardless of your geometry and its transformations, if you wanted to render the above sprite on the geometry, you would pass the sprite frame coordinates into your vertex shader and do something like this.

spriteUV = SpriteFrame.xy + (UV * SpriteFrame.zw);

You pack your sprite frame into a 4d vector, where (x,y) represents the normalized top-left position in the texture and (z,w) is the width and height you calculated in step 3. UV is the original texture coordinates of the geometry, which generally should be planar. If you visualize this in your head, you’ll see that the sprite will be drawn to fill the entire area of the geometry (typically a quad). In your fragment shader, it’s a direct texture assignment:

gl_FragColor = texture2D(Sample0, spriteUV);

Et Voila!

5. Timing Timing is a bit more involved. Don’t think of timing just for your sprite animations, think of it as a global feature that you will want to use all over in your engine. I wrote my own timer class, which is based on an event and delegate design. In my render/update loop, I update the core timer (a singleton event that all instantiated timer objects listen to). Each timer object has a set interval and when that interval has passed, it will dispatch an event and notify the delegates. In my sprite engine, each timer triggered event will advance the sprite frame of the animation, which is generally defined in the sprite sheet. It looks a little something like this.

void MyRenderLoop () { Timer::Update(); }

void SpriteClass::InitTimer () { // Set interval to 30 FPS mMyTimer.SetInterval(1.0 / 30.0); }

void SprintClass::OnTimer () { ++mSpriteFrameIndex; } </code>

Hopefully this should get the idea across, but there’s a couple edge cases you have to take into account, such as when the frame rate of your game drops. You may want to skip frames, in which case you would need to check the interval that has passed and advance the number of frames based on that value. In my case, I would do this by setting the timer’s interval to 0 and getting updates every frame, then checking the elapsed time. Generally you don’t want to skip to many frames otherwise your animations get chaotic, so you have to design it with an upper bound in mind.

Hopefully this will get you started. Most of this stuff should feel intuitive. As long as you know the OpenGL API and how to render surfaces, textures, etc, then this should just be an application of logic.

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Jan 19, 2014 at 22:45

Thank you so much, TheNut! Since I couldn’t find any tutorial, I did assume it was something based on logic. Only thing, I didn’t know how to approach it. You did save me a lot of head scratching, and hopefully I still have most of my hair. Your very clear and detailed explanation helped me understand it very clearly, thank you. One more question, though… How would I go about animating sprites of different sizes? And I am not talking about empty pixels of wasted space. No, this is about a series of sprites that are already packed. They are of different dimensions.

It’s like this… The first frame sprite is a character standing idly, so his whole body takes center frame in the sprite. Next two frames show him outstretching his arm towards the left, and the final frame shows his arm completely outstretched. The final frame has his body to the right of the sprite image and his arm to the left end of the image. Basically, the final frame is wider than the first.

So, if I animate it as it is, his body offsets to the right a bit. Now, throughout the sequence, his head does not move, so what I was thinking was maybe putting an anchor point on any fixed point on his head and use this anchor point while animating the sprites. That way, his body stays where it is and his arm moves forward. Is this the right way of approaching it?

But then, some sprites show him bending, so head might not be a great anchor point. I was thinking his feet would be better as they stay fixed on the ground. Depends on the sprite… But the point is, am I approaching this correctly? Please clarify this. Thank you.

6837d514b487de395be51432d9cdd078
2
TheNut 179 Jan 20, 2014 at 02:56

The easiest way to animate sprites of different sizes is to enlarge the canvas so that all frames are the same size and are centred in the image. This way the animation appears proper for all frames, but also leads to texture waste.

For tightly cropped sprites, you have the right idea. You need to pin a source object and have your sprite offset to align correctly with the animation. This means your transforming the actual rectangle and not the texture. So when your sprite frame increases in size by 20 pixels, you need to enlarge your rectangle to compensate, and then offset it so that the animation is pinned correctly. This is pretty tricky and some artists I know do this by hand. They have tools and whatnot to help them, but generally it’s quite manual.

A alternative solution is to look into skeletal sprites. For example, you can checkout this tool for Unity. Break your object down into smaller pieces that you can join together into a skeletal structure. This isn’t always possible though, so it depends on your needs.

Adfa6cf87d3749a0e1acd928285b3f23
0
WDR 106 Jan 20, 2014 at 04:02

Well, I am not much of an artist, just basic Photoshop. Uni2D seems a bit out of my reach. Just wanted to know whether my sprite alignment method was right. Thank you, TheNut. Your help has been great so far. Giving both your replies the up arrow (like button?) beside the post. I’ll be sure to ask if I have any more questions! :-)

EDIT: OK… So, it increases the rep. Cheers.