Question

By using a SurfaceView, I'm trying to do a fade effect for my objects that move in the canvas. Then I have a background that on each frame it will be drawn into the canvas with an alpha value (so all that was drawn before will be faded), and then draw the next position of the objects.

The problem I have though, is that when the background is drawn multiple times with an alpha value, the colors get discrete. Some images; the top one there's the first frame that's with continuous colors, and on the bottom one there's the same but many frames later (~50), where the colors get discrete.

enter image description here enter image description here

I put some of my code. Init part:

// Inited somewhere in the start of the app
Bitmap bmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas bmpCanvas = new Canvas(bmp);

Paint backgroundPaint = new Paint();

Bitmap background = Bitmap.createBitmap(width, height, Config.ARGB_8888);
// Draw the background image into background
bmpCanvas.drawBitmap(background, 0, 0, backgroundPaint);
backgroundPaint.setAlpha(0x10);

Then I have a thread that in his run method it sets the framerate to 30, and calls the doDraw(Canvas c) method to draw all the stuff in the bmpCanvas. Then it draws its bitmap (bmp) into the scene canvas (If i don't do it this way then I get jitter because of SurfaceView's double buffer)

private void doDraw(Canvas c){
    c.drawBitmap(background, 0, 0, backgroundPaint);

    // Draw all the objects
}

I tried solving it by changing the backgroundPaint's Xfermode by trying all of the PorterDuffXFermode, but no one seems to work for me.

============== SOLUTION =========================

Inspired by Lorne Laliberte answer what I did was a double buffer in order to make it faster.

Basically I create the background as a Bitmap. Then I set up 2 empty bitmaps with the same width and height as the background and create 2 Canvases for it. I also keep an index telling me what canvas should I draw to (call it iCanvas).

There's no need for another bitmap to avoid the SurfaceView's double buffer now, since I'll be drawing everything again (so there's no flicker).

Then what I do is in each frame, clear the actual canvas, and draw the previous with a Paint with some alpha (0xE0 for instance), and draw the objects over this canvas. Then just draw to the SurfaceView's canvas the background and then the actual canvas. Finally just switch the index iCanvas.

I think this is way faster than having to remember all the previous positions of the objects and drawing them again with different alphas. And this works 100%, as in each frame, the objects that were drawn get faded away and we're not redrawing a semitransparent background over the same background.

Was it helpful?

Solution

You're accumulating draws -- redrawing the bitmap on top of the previous canvas, with translucency, will cause the effect you're seeing. If you want it to remain smooth, you need to erase the previous bitmap by painting a solid color, for example you could use this if you're rendering over a transparent canvas:

private void doDraw(Canvas c) {
    // fill the canvas with transparency first
    c.drawColor(0, PorterDuff.Mode.CLEAR);

    c.drawBitmap(background, 0, 0, backgroundPaint);

    // Draw all the objects
}

If the canvas is opaque, you just need c.drawColor(0); though.


Edit: It just occurred to me you might be trying to draw over previously drawn objects in the canvas, to accumulate a translucent bitmap over them in order to "fade" those objects away -- if that's so, then the short answer is I don't think that approach will work without the kinds of artifacts you're seeing. You'll need to take a different approach, for example redraw the scene each frame drawing each visible object with decreasing alpha -- or draw your objects into one buffer, and then copy from that buffer into your canvas each frame before drawing over that ONCE with your translucent background.

(It might also be possible to implement your desired effect as a kind of DrawFilter...)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top