Toolkitly

如何放大像素画而不把它变糊

你把一个 32×32 的精灵放大到 256×256,拿回来的是一团糊的东西。 没有哪里坏掉——你的图像软件干的正是它被设计出来要干的事。 下面讲它到底做了什么、为什么这对像素画是错的,以及能修好它的那两个设置。

1. 你的软件为什么把它弄糊了

缩放一张图,意味着凭空造出本来不存在的像素。 重采样滤镜负责决定每个新像素该是什么颜色, 而 Photoshop、GIMP、预览、画图,以及地球上每一个 CMS 的默认值都是双三次双线性: 看周围的源像素,把它们平均起来,按距离加权。

对照片来说这是正确答案。照片是对一个连续场景的采样, 所以在采样之间插值,重建出的东西接近传感器在新分辨率下本来会记录到的样子。

像素画正好相反。底下并没有一个被采样的连续图像—— 那些像素本身就是作品,每一个都是刻意放上去的, 而且通常出自一套只有几十种颜色的配色。 把相邻两个像素平均,会产生一个配色里根本没有的颜色, 原本利落的一像素描边会变成三像素的渐变。放到 8 倍, 精灵里的每一条边都会变成一道柔和的斜坡。

2. 邻近采样:只复制,绝不平均

邻近采样问的是一个更简单的问题: 对这个输出像素来说,哪一个源像素离它最近?把那一个原样抄过来。 不平均,不造新颜色,不产生柔和边缘。

放大 4 倍意味着每个源像素变成一个 4×4 的同色方块。 配色没变,轮廓正好落在画师放的位置上, 结果和「用更粗的笔在那个尺寸上重画一遍」是分辨不出来的—— 而这正是你想要的。

实际操作中,这个设置在 Photoshop 里叫 Nearest Neighbor(硬边缘),在 GIMP 的插值下拉框里叫 ,在多数在线工具里叫邻近采样像素画缩放工具默认就用它,平滑只作为一个需要你主动勾选的选项存在。

3. 按整数倍缩放

光有邻近采样还不够。想想 1.5 倍: 一个源像素没法变成一个半输出像素,于是滤镜只能交替—— 这一个给 2×2 的方块,下一个给 1×1,就这样在整个精灵上轮着来。

什么都没糊,可它看着就是不对。原本一像素粗的线, 现在有的地方一像素、有的地方两像素;一个圆会长出几段平边。 整张画读起来像是画在了格子大小不匀的方格纸上。 2.5 倍、3.7 倍,或者任何不是源尺寸整数倍的目标尺寸,都会这样。

所以:2 倍、3 倍、4 倍、8 倍。 具体是哪个远没有「它是整数」重要。常选 2 倍和 4 倍, 是因为它们同时落在 2 的幂的贴图尺寸上, 而某些 GPU 和较老的移动平台还在意这件事。

如果你确实需要一个中间尺寸——比如要把精灵塞进一个固定的 UI 槽位—— 那就缩放到最接近的整数倍,然后在槽位里居中,或者补上透明边。 不均匀的缩放不是一种折中,它是一个缺陷,而且会出现在动画的每一帧上。

4. 缩小,以及它唯一无损的那种情况

缩小和放大不是对称的。从 64×64 到 32×32 意味着扔掉四分之三的像素, 再怎么放大回去也找不回来。如果这份美术就是需要以 32×32 存在, 诚实的答案通常是重画一遍—— 像素画的自动缩小很少能在一像素级的细节上幸存。

有一个例外,而且在下载来的素材上反复出现: 文件是 512×512,但里面的美术其实是 64×64,有人在保存前放大了 8 倍。 每一个你看到的「像素」其实是一个 8×8 的方块。 把它按 8 除回去,什么都不会丢——那只是在撤销那次放大。

识别这件事是机械的。在一次干净的放大里, 沿着某一行或某一列,每一段连续相同像素的长度都是放大倍数的整数倍, 所以所有这些长度的最大公约数就是那个倍数。 只要有一个杂散的抗锯齿像素,这个公约数就会掉到 1—— 而那是正确答案,因为这时它已经不是一次干净的放大,硬除下去会毁掉真实的细节。

真要除回去时,每个方块取出现次数最多的颜色, 而不是随便采样其中一个像素。如果这张图曾经过平滑滤镜, 采样单个像素可能正好采到一条插值出来的边缘;对整块做多数投票则不会。

5. 导出只完成了一半

一张利落的 PNG 照样可能到了游戏里就发虚, 因为引擎会在导入时套上它自己的贴图过滤。 这一点反复坑人:硬盘上的文件完美无缺,游戏里的精灵是软的。

Godot:选中贴图,打开 Import 面板, 把 Filter 设为 Nearest,然后点 Reimport。 整个项目的话,与其一张张改贴图,不如在项目设置里把默认贴图过滤设成 nearest。

Unity:Texture Type 选 Sprite (2D and UI), Filter Mode 选 Point (no filter),Compression 选 None。 把 Pixels Per Unit 设成你美术的像素尺寸,精灵才会落在整数世界单位上。

Phaser 和网页:在游戏配置里传 pixelArt: true。 用普通 <img> 元素显示的精灵, CSS 里加 image-rendering: pixelated—— 不加的话,只要显示比例不是 100%,浏览器立刻就会把图抹平。

另外,永远导出 PNG。JPEG 的压缩靠丢弃高频细节工作, 换个说法就是「硬边缘」——它会在每一条轮廓周围加一圈光晕, 还会把颜色挪出你的配色。

常见故障

我明明选了邻近采样,边缘还是软的

下游有东西在做过滤。检查引擎的导入设置;网页输出的话检查 CSS—— 被缩放的 <img> 默认就会抹平。

有些像素比另一些宽

缩放倍数不是整数。把目标尺寸取整到源尺寸最接近的整数倍。

缩放后颜色有轻微变化

滤镜仍然在插值,或者文件被存成了 JPEG。 邻近采样加 PNG 输出能让配色一个字节都不变。

透明背景变成白色了

输出格式没有透明通道。导出 PNG 或 WebP,别用 JPEG。

一个小精灵的文件却很大

这份美术多半已经被放大过了。把它还原到原始分辨率,缩放交给引擎在运行时做。

现在就缩放一张