【问题标题】:Android draw transparent bitmap gets discrete colorsAndroid绘制透明位图获取离散颜色
【发布时间】:2014-03-04 00:01:13
【问题描述】:

通过使用 SurfaceView,我正在尝试为在画布中移动的对象制作淡入淡出效果。然后我有一个背景,在每一帧上它都会用一个 alpha 值绘制到画布中(所以之前绘制的所有内容都会褪色),然后绘制对象的下一个位置。

我遇到的问题是,当使用 alpha 值多次绘制背景时,颜色会变得离散。一些图像;顶部的第一帧具有连续的颜色,而底部的帧相同,但之后的许多帧(~50),颜色变得离散。

我放了一些我的代码。初始化部分:

// 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);

然后我有一个线程,它在他的run方法中将帧率设置为30,并调用doDraw(Canvas c)方法来绘制bmpCanvas中的所有内容。然后它将其位图(bmp)绘制到场景画布中(如果我不这样做,那么我会因为 SurfaceView 的双缓冲区而抖动)

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

    // Draw all the objects
}

我尝试通过尝试所有 PorterDuffXFermode 来更改 backgroundPaint 的 Xfermode 来解决它,但似乎没有人适合我。

==============解决方案=========================

受 Lorne Laliberte 的启发,我所做的是双缓冲以使其更快。

基本上我将背景创建为位图。然后我设置了 2 个与背景具有相同宽度和高度的空位图,并为它创建了 2 个画布。我还保留了一个索引,告诉我应该在哪个画布上绘制(称之为iCanvas)。

现在不需要另一个位图来避免 SurfaceView 的双缓冲区,因为我将再次绘制所有内容(所以没有闪烁)。

然后我所做的是在每一帧中,清除 actual 画布,并使用带有一些 alpha(例如 0xE0)的 Paint 绘制 previous,然后在此画布上绘制对象。 然后只需将背景绘制到SurfaceView 的画布,然后是actual 画布。最后只需切换索引iCanvas

我认为这比记住对象的所有先前位置并使用不同的 alpha 再次绘制它们要快得多。这 100% 有效,就像在每一帧中一样,被绘制的对象会逐渐消失,我们不会在同一背景上重新绘制半透明背景。

【问题讨论】:

    标签: android canvas bitmap


    【解决方案1】:

    您正在累积绘制 - 在前一个画布上重新绘制位图,并具有半透明效果,将产生您所看到的效果。如果您希望它保持平滑,则需要通过绘制纯色来擦除先前的位图,例如,如果您在透明画布上进行渲染,则可以使用它:

    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
    }
    

    如果画布是不透明的,你只需要c.drawColor(0);


    编辑:我突然想到你可能正试图在画布中绘制先前绘制的对象,在它们上累积半透明位图以便“淡化”这些对象 - 如果就是这样,那么简短的回答是,如果没有您所看到的各种工件,我认为这种方法行不通。您需要采用不同的方法,例如每帧重绘场景,以递减的 alpha 绘制每个可见对象 - 或将对象绘制到一个缓冲区中,然后在每帧从该缓冲区复制到画布中,然后再绘制该 ONCE用你的半透明背景。

    (也可以将您想要的效果实现为DrawFilter...)

    【讨论】:

    • 完美!这就是我真正需要的!太棒了!我编辑了这个问题,告诉我我最终做了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-08
    • 2020-12-22
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多