GraphicsFilter: How do I get an image with a lot of diagonal jaggies in it to scroll without flickering?
December 1, 2007 2:06 AM
GraphicsFilter: How do I get an image with a lot of diagonal jaggies in it to scroll without flickering? I think it's more of a general graphics problem than a Flash issue, but I've included the Flash details anyway.
I'm scrolling (by which I mean moving) a large bitmap using Flash CS 3. I'm doing this by putting the bitmap in a MovieClip and then changing the x property of the instance of the MovieClip in an OnEnterFrame listener.
It doesn't look outright horrible, but it definitely flickers in places.
Part of the issue may be the nature of the image. It's drawing-like, rather than photo-like. There are jaggies, and the areas of the image with the highest concentrations of them flicker the most. (I notice that even the Bros. Chaps' excellent developer whose name I forgot couldn't quite avoid this happening in the foreground of the Stinkoman game.) This is a requirement, however: The jaggies are intentional.
Some other details:
- Tracing the bitmap into a vector doesn't help.
- I move it 10 pixels per frame. When I change it to move 1 pixel per frame, it's smooth-looking. Unfortunately, I need it to move at a faster rate.
- It doesn't matter whether I set the frame rate to 12 or 60 fps. At 12, it flickers, and at 30 or over, it just looks blurry.
- Same thing with making the movement rate a multiple of four. (Each block in the jaggies is 4x4 pixels in size.)
- I had some other code (but not much) subscribed to the ENTER_FRAME event, but I dropped it so that the only code that executed on each frame entrance was myMovieClip.x += 10;. No help. So, it's not a processor load issue.
- I tried having it move in direct response to a keyboard event instead of the ENTER_FRAME event, but that didn't matter, either.
- Doing this via tweening doesn't seem to help.
Any clues? My Google attacks do not seem to be hooking anything relevant.
I do have a plan B, but I'd really like for this to work.
I'm scrolling (by which I mean moving) a large bitmap using Flash CS 3. I'm doing this by putting the bitmap in a MovieClip and then changing the x property of the instance of the MovieClip in an OnEnterFrame listener.
It doesn't look outright horrible, but it definitely flickers in places.
Part of the issue may be the nature of the image. It's drawing-like, rather than photo-like. There are jaggies, and the areas of the image with the highest concentrations of them flicker the most. (I notice that even the Bros. Chaps' excellent developer whose name I forgot couldn't quite avoid this happening in the foreground of the Stinkoman game.) This is a requirement, however: The jaggies are intentional.
Some other details:
- Tracing the bitmap into a vector doesn't help.
- I move it 10 pixels per frame. When I change it to move 1 pixel per frame, it's smooth-looking. Unfortunately, I need it to move at a faster rate.
- It doesn't matter whether I set the frame rate to 12 or 60 fps. At 12, it flickers, and at 30 or over, it just looks blurry.
- Same thing with making the movement rate a multiple of four. (Each block in the jaggies is 4x4 pixels in size.)
- I had some other code (but not much) subscribed to the ENTER_FRAME event, but I dropped it so that the only code that executed on each frame entrance was myMovieClip.x += 10;. No help. So, it's not a processor load issue.
- I tried having it move in direct response to a keyboard event instead of the ENTER_FRAME event, but that didn't matter, either.
- Doing this via tweening doesn't seem to help.
Any clues? My Google attacks do not seem to be hooking anything relevant.
I do have a plan B, but I'd really like for this to work.
//hack to smooth animating bitmaps
//mc is the jaggy bitmap
mc._visible = false; //hide the original
var bmd:BitmapData; //make a new bitmap
//make the new bitmap the same size as the original
bmd = new BitmapData(mc._width,mc._height,true);
//make a new movieclip
var mc2:MovieClip = new MovieClip(); //this will the smooth one
//attach the bitmap to the new movieclip
mc2.attachBitmap(bmd,mc2.getNextHighestDepth(),"auto",true);
//copy the pixels from the original into the bitmap
bmd.draw(mc);
//now animate mc2
posted by grumblebee at 7:55 AM on December 1, 2007
//mc is the jaggy bitmap
mc._visible = false; //hide the original
var bmd:BitmapData; //make a new bitmap
//make the new bitmap the same size as the original
bmd = new BitmapData(mc._width,mc._height,true);
//make a new movieclip
var mc2:MovieClip = new MovieClip(); //this will the smooth one
//attach the bitmap to the new movieclip
mc2.attachBitmap(bmd,mc2.getNextHighestDepth(),"auto",true);
//copy the pixels from the original into the bitmap
bmd.draw(mc);
//now animate mc2
posted by grumblebee at 7:55 AM on December 1, 2007
Grumbleblee has it right on. You need to convert your imported image into a bitmap object. Not only will it animate more smoothly, but you can scale, rotate, and apply displacement to it without it getting excessively jaggy.
posted by kaseijin at 12:49 PM on December 1, 2007
posted by kaseijin at 12:49 PM on December 1, 2007
Tracing the bitmap into a vector doesn't help
NO, it won't! Bitmaps are WAY more performant than vector images, which very quickly eat into your CPU resources as the complexity of the image increases (or as the size of the image increases). Bitmaps traditionally take more memory to store, but are much faster to work with.
Doing this via tweening doesn't seem to help
Right, it won't help at all. You're just letting Flash take care of the looping code, but it's still the same operation.
typically, for flickering problems, the solution is double-buffering
Double-buffering helps when the computation of the image transformation is stalling the redraw. In the "olden" days, you would use different areas of the video ram to store two images: one was for display, the other was where you built the next image. Once the second image was built, you swap the display and repeat the cycle.
The best candidates for double-buffering solutions in Flash are games where a lot of sprites are interacting with each other combined with physics engines and object collision detection and such. I don't know enough about Flash internals to know if you'd benefit from double-buffering for a single image, but you might.
grumblebee is on the right track: you need to use the Bitmap object to hold your image data. Here is some sample code that combines Bitmaps and double-buffering. Hope that gets you going in the right direction.
posted by Civil_Disobedient at 3:42 PM on December 1, 2007
NO, it won't! Bitmaps are WAY more performant than vector images, which very quickly eat into your CPU resources as the complexity of the image increases (or as the size of the image increases). Bitmaps traditionally take more memory to store, but are much faster to work with.
Doing this via tweening doesn't seem to help
Right, it won't help at all. You're just letting Flash take care of the looping code, but it's still the same operation.
typically, for flickering problems, the solution is double-buffering
Double-buffering helps when the computation of the image transformation is stalling the redraw. In the "olden" days, you would use different areas of the video ram to store two images: one was for display, the other was where you built the next image. Once the second image was built, you swap the display and repeat the cycle.
The best candidates for double-buffering solutions in Flash are games where a lot of sprites are interacting with each other combined with physics engines and object collision detection and such. I don't know enough about Flash internals to know if you'd benefit from double-buffering for a single image, but you might.
grumblebee is on the right track: you need to use the Bitmap object to hold your image data. Here is some sample code that combines Bitmaps and double-buffering. Hope that gets you going in the right direction.
posted by Civil_Disobedient at 3:42 PM on December 1, 2007
I suspect the problem here is one of perception, not performance.
Verify that your image really does lie on a 4x4 grid pattern. That is to say, make sure that you don't have a stair-step pattern, then a gap of, say, 7 pixels, then the start of another stair-step pattern.
Be certain that your MovieClip (and the image inside it) have whole pixel upper-left origins.
Animate your MovieClip at a rate that is a multiple of 8. Given your grid of 4x4, a rate of 10 may cause a noticeable flicker, and 12 may be horrible (particularly in areas with a checkerboard pattern).
Also note that grumblebee's bitmap hack (which is a fine hack), is only necessary if you are loading the bitmap at runtime from an external file. If you're importing the image to your library, simply double-click the image asset there, and check the Smoothing box. Or, if you're using AS3, I don't think you need the hack anymore...
Good luck.
posted by thinman at 4:53 PM on December 1, 2007
Verify that your image really does lie on a 4x4 grid pattern. That is to say, make sure that you don't have a stair-step pattern, then a gap of, say, 7 pixels, then the start of another stair-step pattern.
Be certain that your MovieClip (and the image inside it) have whole pixel upper-left origins.
Animate your MovieClip at a rate that is a multiple of 8. Given your grid of 4x4, a rate of 10 may cause a noticeable flicker, and 12 may be horrible (particularly in areas with a checkerboard pattern).
Also note that grumblebee's bitmap hack (which is a fine hack), is only necessary if you are loading the bitmap at runtime from an external file. If you're importing the image to your library, simply double-click the image asset there, and check the Smoothing box. Or, if you're using AS3, I don't think you need the hack anymore...
mc.stage.quality = StageQuality.BEST;
now achieves the same thing, I believe, even for loaded bitmaps.Good luck.
posted by thinman at 4:53 PM on December 1, 2007
I'm a bit confused by your description; I can't see any 'flickering' in Stinkoman, and everything's buffered in Flash anyway, so I assume you're concerned about the slight jerkiness that's inevitable in creating the illusion of movement using bitmap graphics.
All you can do is use the highest frame rate that performance will allow (probably around 20fps for most Flash movies, but many machines will still struggle to get near that with large/complex imagery), thereby minimising the number of pixels moved per frame to achieve the same speed.
Beyond that you'll have to apply motion blur to the image to smooth out the jumps, or make the transition shorter and more interesting to mask the defects (steadily moving a large, static image into view invites our vision system to look for imperfections and so often looks iffy).
posted by malevolent at 3:55 AM on December 2, 2007
All you can do is use the highest frame rate that performance will allow (probably around 20fps for most Flash movies, but many machines will still struggle to get near that with large/complex imagery), thereby minimising the number of pixels moved per frame to achieve the same speed.
Beyond that you'll have to apply motion blur to the image to smooth out the jumps, or make the transition shorter and more interesting to mask the defects (steadily moving a large, static image into view invites our vision system to look for imperfections and so often looks iffy).
posted by malevolent at 3:55 AM on December 2, 2007
Thanks, guys. I still haven't fixed this and have put it on the backburner, but I did try various forms of double buffering as suggested, but that wasn't the problem. (I also switched to using the bitmap directly with Bitmap and BitmapData instead of a MovieClip, so I could use the Bitmap::scroll function for convenience.)
I think it really is a problem of perception as thinman suggested. However, things were really on a 4x4 grid, and moving things at a rate of a multiple of 8 didn't help anything, nor did using Smoothing.
I'm seeing what people on the FlashKit forums say. I'll post here if I get it working. Regardless of outcome, I appreciate the suggestions!
posted by ignignokt at 12:28 AM on December 4, 2007
I think it really is a problem of perception as thinman suggested. However, things were really on a 4x4 grid, and moving things at a rate of a multiple of 8 didn't help anything, nor did using Smoothing.
I'm seeing what people on the FlashKit forums say. I'll post here if I get it working. Regardless of outcome, I appreciate the suggestions!
posted by ignignokt at 12:28 AM on December 4, 2007
All right. some Flash dudes have let me know that:
1. Real double buffering is not possible in Flash because it can't VSync.
2. Even with VSync, it is a perception problem that can take effect if the image is moved by an "off" number of pixels per frame.
At least I know I can move on.
posted by ignignokt at 2:56 PM on December 4, 2007
1. Real double buffering is not possible in Flash because it can't VSync.
2. Even with VSync, it is a perception problem that can take effect if the image is moved by an "off" number of pixels per frame.
At least I know I can move on.
posted by ignignokt at 2:56 PM on December 4, 2007
« Older Have you ever tasted your wife/girlfriend's breast... | Tell me a story, or atleast help it along... Newer »
This thread is closed to new comments.
The way this typically works is that you have two buffers. You display your image in the first buffer. Then you draw your moved image in the second buffer, and tell the system to switch the two on vblank... that is, during the vertical refresh interval. Once the system indicates the two have switched, you now draw the image, moved even more, back into frame 1 again, and then tell the system to swap on vblank. Draw in 2 and swap, draw in 1 and swap. As long as you sync with the vertical refresh, you get no flicker.
How you do this in Flash, I have no idea, but I see smooth, flicker-free Flash animations all the time, so there's likely to be an easy method available.
posted by Malor at 3:09 AM on December 1, 2007