I’m looking for any tips on animation.
I’m currently drawing 25 128 x 128 images in a short animation, on a non-retina screen connected to a rMBP, I can get 60 fps, but on the Retina display it drops down to only 25 fps and sometimes there is visible jerkiness.
I’ve tried using NSAnimation, a Timer and even a tight loop calling refresh, I’ve looked into using Core Animation layers and didn’t notice any speed gains, but faced other issues.
What I’m worried about is this is basic animation compared to what I’m planning to do and it the performance is bad at the moment, it’s only going to get worse.
So if anyone has any tips or suggestions then I’d be happy to hear them.
Redraw(reduce) the 25 to 11 or 12, but include stuttered, faded, previous position. Basically you need to copy Disney, which ran very smoothly at 24 fps.
Thanks for the idea. I’ll have to re-think my engine as it currently doesn’t allow for this.
I have managed to squeeze a few more FPS out by drawing to a CGLayer first and then drawing that in the paint event.
The less work you do every frame, the better your performance will be. A few ideas
- Consider that there is additional overhead in scaling the image for Retina. Try using graphics.AntiAlias=false and/or setting the interpolation quality appropriately as to strike a balance between quality and performance.
Here’s the method I use to set the interpolation. You can change the 4 to alter the quality.
[code]Sub EnableInterpolation(g as Graphics)
Declare Sub CGContextSetInterpolationQuality lib “Cocoa” (handle as integer, inValue as integer)
Dim CGContextRef as integer = g.handle( graphics.HandleTypeCGContextRef )
if CGContextRef<>0 then
CGContextSetInterpolationQuality( CGContextRef, 4 )
2. Are you compositing multiple elements every single frame? Then do what you can to reduce the number of elements that need to be composited. For example if you have a scrolling background with trees and bushes, you’d draw it all to a single image and reuse that image until you need to recompose.
- Consider also how you’re running the animation. Ideally you’d use a timer, and the frame drawing would be time based (at time X we need frame Y).
Thanks for the tips Thomas,
#1 I had tried both of those, sadly they made no perceivable difference on the Retina machine.
#2 Yes, each of the 25 elements is being animated, resized and rotated to simulate leaves floating down.
#3 I opted for a path based model, so each element would have a random path every time the animation is run. I tried it with a Timer, I tried using NSAnimation and I even tried it with a tight loop calling refresh after each frame. (we used to use tight loops when building games).
In the end I decided to change my animation, and I’m working on something else which I think will not only be more engaging to the user but also require less work (one hopes).
It’s pretty sad, I did get it to about 23fps, so a Retina MBP 2.6Ghz runs animation as well as a 2008 MBA 1.8Ghz
I bet the rotation is going to be the most costly operation, so I’d start by disabling it. And if you see a big performance increase then that’s where you can optimize by caching the rotated images.
Assuming degrees, you’d truncate your rotation angle to an integer (to reduce the number of frames needed), then composite the rotated mask and surface to a picture. Now you just draw the pre-composited image instead of re-calculating rotations on every draw.
I’d wrap this all up in a function like follows:
DrawLeaf( g as graphics, leafID as integer, x as integer, y as integer, rotationInDegrees as integer )
The leafID is how we track which leaf image we need. I’d use constants like kImageLeafMaple=1, kImageLeafElm=2, etc.
Hope that helps.
Ironically enough, I thought the bulk of the slow down may be the rotation, so I did try it without, but alas it didn’t make as much difference as not altering the size of the images.
Hopefully one day, I’ll understand exactly why it runs so slow and be able to fix it. In the meantime, most of my animation is now CGLayer based and providing I’m not altering the size, it’s nice and smooth.