通过使用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
画布,并用previous
绘制Paint
一些alpha(例如0xE0),然后绘制对象这个画布。
然后只需在SurfaceView
的画布上绘制背景,然后绘制actual
画布。最后只需切换索引iCanvas
。
我认为这比必须记住对象的所有先前位置并使用不同的alpha再次绘制它们要快得多。并且这可以100%地工作,就像在每个帧中一样,绘制的对象会逐渐消失,我们不会在同一背景上重绘半透明背景。
答案 0 :(得分:2)
你正在累积绘图 - 在上一个画布上重绘位图,具有半透明效果,会产生你所看到的效果。如果您希望它保持平滑,则需要通过绘制纯色来擦除前一个位图,例如,如果您在透明画布上渲染,则可以使用此位图:
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
...)