How best to do animated sprites

Started by Nodin, June 17, 2010, 11:01:00 PM

Previous topic - Next topic

Nodin

Hi All,

I'm having a hard time figuring out how to do animated sprites efficiently (and easily!).  Is there a single best way?  Let's say I need hundreds of them animating on the screen at once.  Swapping textures around certainly doesn't seem the best way,...can I change UV coordinates on the fly?

Thanks!

paulscode

There are a couple of ways to do this.  The fastest way is by creating what I call a "mosaic texture", which contains all the frames tiled, and you simply change the u/v coordinates at the proper speed to animate.  You might find the source code for my Animated GIFs project useful.

The second, slower way if you have too many frames to tile onto a texture (a video, for example), is to use an ITextureEffect to alter a single Texture with the proper frames.  For this method, you might find the source code for my Simple Animated Texture Interface project useful.

Technically there is a third method - swapping out textures in the TextureManager, however in my tests, this method was not feasible, due to a noticeable lag when adding or replacing textures in the TextureManager.

I should point out that I have not tried any of these methods in jPCT-AE, so my above evaluation for which methods are faster may not apply.  Perhaps someone else has some experience and can provide input on what works best on Android.

EgonOlsen

#2
AE supports u/v-coordinate changes on the fly via the PolygonManager. However, there are two problems with this. One is, that at compile time, it can't determine that you are going to do this, which is why it compiles everything to either static or dynamic but always assumes static uv-coordinates. Currently, there is no way to speficy, that an Object3D is going to change the uv-coordinates during runtime. I can add this. The second problem is, that changing uv requires some extra processing each time you apply the change. I've no idea how costly this will be...maybe not much, but i'm not sure about this.
Another option might be, to create a set of fixed Object3D for each sprite, one for each animation phase, assign them all as childs of the first one and make all but the current invisible. I don't know if this is feasible in your case though.It will use more memory of course but should usually be faster.

Edit: I was wrong, there already is a way to tell that uv isn't static. Just call build(false); instead of build() on the Object3D in question.

EgonOlsen

I think that there's a third solution, but i have to add some stuff to the engine that that...i'll keep you posted!

EgonOlsen

#4
Ok, i've added the methods in question...however, there's a problem: At least on my phone, it simply doesn't work. The idea is to change the texture matrix of an Object3D. With this option, you can apply a translate on the u/v-coordinates without physically changing them. That would be very useful for animations of that kind. But as said, at least my Samsung Galaxy doesn't seem to care about it. The code runs fine in the emulator and in desktop jPCT....just the Galaxy seems to ignore changes to the texture matrix and renders everything as if there were no change. You can even set the matrix to be all zero but it doesn't change anything. I've experienced a similar effect with environment mapping, which uses the same idea and doesn't work on the Galaxy either...when you combine both, all hell breaks loose. The Galaxy then starts to recognize that there is something to do with the texture matrix but screws everything up completely. Again, this works fine in the emulator.
Because both things run fine in the emulator and desktop jPCT using the exact same code, i consider this to be a kind of driver or hardware bug for now... :'(

Nodin

After a bit of work, I'm in the same boat, although it doesn't work for me in the emulator either.  I can change the UVs for a texture on the fly and it doesn't change on display.  Are we missing some kind of flush function call?

EgonOlsen

Make sure that you've used build(false); and call http://www.jpct.net/doc/com/threed/jpct/Object3D.html#touch() after updating the uv-data and see if that helps.

Nodin

Thanks for your help.  Unfortunately that didn't do the trick.  Here's what I'm basically doing in onDrawFrame, hopefully it's enough for some insight;

               sprite.build(false); //called much earlier outside of onDrawFrame

               //inside onDrawFrame
      quadUVs = animationTexture.getCurrentQuadUVs(); //my own class, the UVs come back correct every frame
      tex1 = new TextureInfo(
                TextureManager.getInstance().getTextureID( "spritetex" ),
                quadUVs.u1, quadUVs.v1, quadUVs.u2, quadUVs.v2,
                quadUVs.u4, quadUVs.v4 );
        tex2 = new TextureInfo(
                TextureManager.getInstance().getTextureID( "spritetex" ),
                quadUVs.u2, quadUVs.v2, quadUVs.u3, quadUVs.v3,
                quadUVs.u4, quadUVs.v4 );
        sprite.getPolygonManager().setPolygonTexture( polyIdOffset,
                                                    tex1 );
      sprite.getPolygonManager().setPolygonTexture( polyIdOffset + 1,
                                                    tex2 );

      sprite.touch();

...I only ever see the first frame, unless I forcibly skip it, then I see the second.  I know the screen is updating as I can see a framerate blit I have going.

EgonOlsen

Please try to attach a dummy Animation (can be empty) and see if that helps. If it does, i have to change compile behaviour for non-static uvs...

Nodin

Thanks, That did the trick.  :D 

I created an animation object with just one keyframe of the sprite's mesh, then set the animationSequence for the sprite, and all is well now with updating the UVs on the fly. 





EgonOlsen

Alright...i'm going to change compilation behaviour then for the next version so that this dummy animation isn't needed anymore.