在画布上绘制单个位图与多个位图的质量(Android)

在画布上绘制单个位图与多个位图的质量(Android),android,canvas,bitmap,zooming,Android,Canvas,Bitmap,Zooming,我有一组小图片。如果我在画布上单独绘制这些图像,与在屏幕大小的大位图上绘制这些图像并在画布上绘制该位图的情况相比,绘制质量要低得多。特别是线条会变形。见下面(右侧) 根据下面的代码,画布还支持缩放(缩放)。这个问题发生在小规模因素上 问题是如何将多幅小图像的绘制量提高到大图像的标准 这是在画布上绘制的多个位图的代码 canvas.scale(game.mScaleFactor, game.mScaleFactor); canvas.translate(game.mPosX, game.mP

我有一组小图片。如果我在画布上单独绘制这些图像,与在屏幕大小的大位图上绘制这些图像并在画布上绘制该位图的情况相比,绘制质量要低得多。特别是线条会变形。见下面(右侧)

根据下面的代码,画布还支持缩放(缩放)。这个问题发生在小规模因素上

问题是如何将多幅小图像的绘制量提高到大图像的标准

这是在画布上绘制的多个位图的代码

 canvas.scale(game.mScaleFactor, game.mScaleFactor);
 canvas.translate(game.mPosX, game.mPosY);

 for (int i = 0; i < game.clusters.size(); i++) {

                Cluster cluster = game.clusters.get(i);
                canvas.drawBitmap(cluster.Picture, cluster.left,
                            cluster.top, canvasPaint);

            }
画笔设置了以下属性。`所有位图都是Bitmap.Config.ARGB_8888

    canvasPaint.setAntiAlias(true);
    canvasPaint.setFilterBitmap(true);
    canvasPaint.setDither(true);`

我能想到一对,取决于你,你正在画拼图块的边界

您遇到的问题是,当缩放单个图像时,线条将与图像的其余部分一起过滤,并且看起来平滑(混合是正确的)。当拼图是逐块绘制时,过滤读取拼图块上的相邻像素,并将其与拼图块混合

方法1

第一种方法(一种很容易做到的方法)是以游戏的逻辑大小渲染到FBO(RTT),然后使用全屏四边形将整个纹理缩放到画布上。这将得到与
single
相同的结果,因为像素混合涉及相邻块

方法B

用出血来解决问题。切割拼图时,请将相邻拼图的重叠部分包括在内。不要将丢弃的像素设置为零,只将alpha设置为零。这将导致混合函数拾取与放置在单个图像上相同的值。此外,将边界线加倍,但将外部边界alpha设置为零

接近决赛

最后一个是最复杂的,但对于任何缩放都是平滑的(AF)

将拼图块的alpha通道转换为有符号距离场,并使用专门的着色器进行渲染,该着色器将在任意距离平滑输出。此外,SDF允许您在渲染期间使用着色器绘制轮廓,并且轮廓将平滑

事实上,SDF可以是单独的纹理,您可以将其加载到第二个纹理阶段。将源图像绑定为tex单元0,tex单元1上的sdf拼图块剪切,并使用sdf着色器确定来自sdf的alpha和来自tex0的颜色,然后根据sdf计算混合轮廓


SDF是从布尔映射生成的。您的拼图块剪纸需要以单色剪纸开始,然后使用上面列出的工具或类似工具转换为SDF(脱机)。Valve和LibGDX具有示例SDF着色器以及上面列出的工具。

在固定大小的画布上渲染高分辨率图像意味着每个目标像素的源像素比较小大小的源图像多,结果是较大图像的下采样质量更好。若要为较小的图像获得相同的结果,请从相同的高分辨率源以需要渲染的分辨率(即比例应为1)创建它们,谢谢您的评论。大位图是画布大小的2倍(绘制到最大缩放级别)。小图像是大位图的片段,大小较小,但其比例为2。因此,比例因子范围为0.5到1(表示缩放级别为2)。当比例大小为0.5(即正常画布大小,但图像的一半)时,会出现此问题。从右侧看,图像线在0.5级受到显著影响。你认为我必须根据缩放级别创建多个图像吗?或者所有的小图像都应该是大图像的大小?这两种方法都有问题,因为在某些情况下,我有400张小图像。我仔细查看了图像,较低的质量与双线性向下采样产生的质量损失相匹配。在
canvasPaint.setFilterBitmap(true)上进行双线性过滤    canvasPaint.setAntiAlias(true);
    canvasPaint.setFilterBitmap(true);
    canvasPaint.setDither(true);`