聊聊 2D 游戏的像素化中的问题

作者:zrix
2019-04-01
35 40 7

既然我是在做像素游戏,这次就聊一聊在对 2D 游戏像素化的过程中都会碰到的问题吧。

1. 照相机的投影

对于引擎来说,其实不管是 2D 游戏还是 3D 游戏它们的运行场景都是在一个 3D 空间下的(所以很多 2D 游戏其实干脆就是用 3D 场景的做法来做的,这样 3D 的渲染技术也可以直接运用到 2D 上)。而照相机的投影方式可以决定最终呈现的效果是 2D 的还是 3D 的。通常在游戏开发中较常使用到的投影方式有两种:

  1. 正交投影方式;
  2. 透视投影方式;

正交投影多用于做 2D 游戏;而透视投影多用于做 3D 游戏。当然啦,事实上透视投影也能做 2D 游戏。至于为啥很少有人用透视投影来做 2D 游戏呢?因为透视投影多了一个 Z 值会对画面的显示尺寸产生影响(透视存在近大远小么),导致操作起来比较麻烦。具体我就不展开了,有兴趣的可以查阅一下相关内容。总之,没啥特殊要求的话,选择正交投影就可以了。

2. 让像素变得有锯齿感

锯齿感是区别像素和非像素游戏的非常重要的感受。不同于其它风格的游戏,它们需要对画面进行平衡,边缘进行模糊来保证画面的圆润和谐。不过像素游戏就需要保留那种马赛克的感觉。除去美术在绘制时控制图片的风格以外,程序要也有相应工作要完成:

1. 关闭与“画面抗锯齿”有关的功能:

我们使用的引擎大多数默认不希望画面出现这种“锯齿感”的,所以它们默认会打开比如叫“反走样”啦,“抗锯齿”啦,“多重采样(俗称 MSAA,全称 Multi-Sample-Anti-Aliasing。以后如果看到某个图形技术的缩写带 AA 后缀的,一般就是处理抗锯齿的。顺便鄙视一下那些技术文档里面随手丢个英文缩写还不给全称和注释的做法,这种做法真的是优越感穷得只剩下英文缩写了)”啦等这些诸如此名的功能。对,没错,名字是很多,干的事情都是一件。大多数像素游戏自然不希望它被打开,所以一般情况下可以选择关掉它们。

2. 使用非平滑的贴图采样方式——最近邻采样方式:

上面的功能是对整个画面进行“抗锯齿”的;而这个功能决定了电脑如何获取图片中的颜色的。除去最近邻采样的方式以外,其它方式都会同时从图片上采样多个颜色,然后在通过某种方式(依据采样模式不同而不同)混合出一个新颜色作为最终从图片上获取到的颜色。这个可以说是对获取图片的颜色进行了“抗锯齿”。对于像素游戏而言,自然大部分情况下我们也不需要它,直接将它设置为最近邻采样吧;

多说一句,并不是所有的像素游戏都会选择关闭它们的,最终还是要依据需要的最终呈现效果而定。

3. 让像素看起来更大

为了复现的像素颗粒感。一般情况下像素游戏都需要显示比实际像素更大的像素。而这个更大,又包含了两个方面:

  1. 让像素变得更大;
  2. 让像素看起来更大;

听起来似乎是一回事,确实这两个方面也确实有些交集。而我们平时做像素游戏一般关心的也就是“让像素变得更大”而已。我们会使用两倍甚至多倍的屏幕像素作为游戏里一个像素(为了区分,后面就把经过放大的像素叫它粗像素好了)。在这种方式下,自然粗像素看起来就变大了。

不过,影响“看起来更大”的不只是只有粗像素的尺寸而已。要知道,像素是衡量屏幕分辩率的东西,它的计量单位可不是厘米毫秒之类的直观尺寸单位。举一个极端点的例子,一个 10 英寸但最大分辩率为 100×100 的屏幕和一个 20 英寸但最大分辩率只有 50×50 的屏幕它们的屏幕像素尺寸就差了整整四倍。也就是我们的游戏如果运行在这个 10 英寸的屏幕上,需要将粗像素扩大到四倍的屏幕像素才能和那个 20 英寸屏幕像素看起来一样大。

我们在做游戏的时候多少会碰到这个问题(尤其是做 UI 的,估计对于这种问题很敏感)。庆幸的是,硬件的行业标准和完善的游戏引擎会让这个问题不会特别麻烦。前者让同类型设备之间的像素实际尺寸相等或是差距不大;而后者则会有对这一块提供了适配功能。而实际过程中,在差距较小或是对像素的实际显示尺寸要求不高的情况下,我们可以只关心如何“让像素变得更大”。但是如果开发者对这方面要求比较高或是存在跨平台的情况,也确实需要注意这个问题。

4. 让像素变得更大

我们在做像素游戏时最常考虑的问题。开发过程中,大致有如下的方式可以让像素变得更大:

1. 让美术资源放大:

这种方式很直接啦。举个例子就是我们把原本 50×50 的资源放大成 100×100。那么显示出来就是两倍于屏幕像素的效果。

2. 对渲染单位进行放大:

渲染单位,就是比如精灵(3D 渲染 2D 可能就是方体或是一个 3D 空间下的四边形)。我们也可以不对美术资源进行放大。转而在使用的过程中,对使用到的渲染单位进行放大来实现像素变大的效果。这种方式基本类同于第一种方式,无非把放大的工作由美术交给了程序。

3. 缩小照相机的视口区域:

这是一种逆向思维的产物。我们可以直接通过放大资源来实现最终呈现效果的放大;也可以通过缩小观察区域,并将其投影到屏幕来实现放大。这个过程简单来说就是两步:1.渲染缩小后的观察区域内的内容;2.将渲染结果投屏。为了完成这个工作,我们需要借助一下渲染到纹理(render-to-target)了:

  1. 缩小观察区域的绘制过程:缩小照相机的视口并创建一张与缩小的视口区域等尺寸的纹理,并一次性将照相机区域的内容渲染到这张纹理上。
  2. 将缩小的结果投影到屏幕:渲染这张纹理并放大贴到屏幕上实现放大投影;

举个简单的例子,假如我们的屏幕尺寸为 100×100;而一般情况下,照相机的视口大小也是 100×100。这个方式通过减小照相机的视口,比如将照相机的视口减小到 50×50,并将这个 50×50 区域内的内容先绘制到一张尺寸同样是 50×50 贴图上;最后再将此贴图再绘制到屏幕上,这样我们就等于实现了放大两倍的效果。

这种方式下,我们对资源以及资源相关的对象没有任何要求,完全一比一地来即可。同时速度和占用资源都会减少(后者自然不必说,前者的话因为第三种方式导致需要绘制的游戏场景区域变小,使得渲染过程更快);还有一点好处,对于严格一点的像素化需求来说,这种做法使得我们在坐标对齐的问题上可以少考虑些(后面会聊到)。

当然啦,这个方式虽然听起来不错,不过需要程序有额外工作量。这个额外工作也不仅仅是一个渲染到纹理的算法,毕竟使用的渲染区域已经不同于原有的区域了,对其他的效果渲染都会产生一定的影响。不过要是各位开发者使用 unity 的话,应该可以比较幸运地找到用这种方式实现像素化的插件。

5. 像素化后的坐标和照相机

其实完成上面的工作以后,我们基本上可以产出一个有像素感的画面了。对于一些非严格要求完全复古像素化的游戏来说,上面的工作已经满足需求。但是对于某一些更严格的像素游戏来说,还不够完善。问题出在我们的像素游戏因为最小单位由原来的一个像素变为现在的一个粗像素。那么展开来说是两个方面:

1. 坐标和尺寸的对齐:

既然我们现在的像素已经被放大,那么我们现在场景的最小单位也转变为粗像素的大小而不是原始的像素大小。我们自然要将场景内所有的游戏单位的坐标也好尺寸也好按照粗像素的大小对齐。没有哪个严格的像素游戏中,一个游戏单位的起点位置是:x 方向 1.5 个粗像素,y 方向 1.5 个粗像素;或者尺寸是:10.5 个粗像素宽;10.5 个粗像素高。

上述三种实现放大的方式中,方式一和二需要考虑坐标的对齐,而尺寸必定是对齐的;方式三无论坐标还是尺寸全部自然对齐,完全不需要考虑此问题(因为是投影等比放大的方式进行放大,所以不管尺寸还是坐标都是天然对齐的)。

2. 照相机的坐标和尺寸的对齐:

照相机自然也和游戏单位一样需要进行对齐:上述三种实现放大的方式中,方式一和二需要同时考虑坐标和尺寸的对齐;方式三仅需要考虑尺寸对齐即可。

我们主要说一说照相机尺寸的对齐:

这个问题会稍微麻烦一点,因为照相机的尺寸和屏幕尺寸有关系,但是屏幕尺寸是固定的。如果需要完美显示场景,我们要保证屏幕像素尺寸能够整除于粗像素的尺寸(这样屏幕上才不会出现类似于显示了半个粗像素的情况)。通常,对于两倍放大的像素游戏而言,基本不存在这个问题(因为几乎所有的显示设备的能够支持的尺寸都能整除2)。不过对于奇数倍或是其它不能够整除的情况,就需要其它方式来处理了。最为常见的方式就是加黑边来填充,通过对称填充黑边的方式来使得显示区域能够整除粗像素的尺寸。

结尾

好啦,这个就是对实现 2D 像素游戏的相关细节啦。希望能对打算开发像素游戏的开发者们提供一些参考。

本文为用户投稿,不代表 indienova 观点。

近期点赞的会员

 分享这篇文章

您可能还会对这些文章感兴趣

参与此文章的讨论

  1. ffnumber1 2019-04-01

    使用像素纹理渲染时,非整数倍分辨率缩放,会丢失很多像素细节,甚至变形,有什么好的应对方案吗?

    • zrix 2019-04-01

      @ffnumber1:
      这个问题一般出现在缩小上。有两种需求,你看看你是哪种需求了:

      1.缩放不需要严格的像素颗粒感:简单说呢,就是缩放的时候可以模糊一点。这种情况下我们就可以使用非最近邻采样来处理了。最直接的方案就是把非最近邻换成线性采样啦,双线性采样啦这些。虽然会模糊,但是失真会好很多。如果想做的更好的话,可以试试再加上mipmap的采样方式(多级采样技术,这玩意一般用于3D的LOD场景需求,避免远端贴图在镜头拉近拉远时贴图的失真,总之就是一种处理贴图缩放失真的技术。它要解决的问题本质上和你碰到的问题一样,所以可以借鉴过来使用)。

      2. 缩放也需要严格的像素颗粒感:这个就比较麻烦。因为采样方式只能是最近邻采样了。这种需求下,一般原则上避免缩放。如果非要做,加上mipmap吧。当然,这种情况下需要设置mipmap的采样方式全部为最近邻采样。

      顺便说一下,如果用mipmap的话shader是需要改动的,主要是贴图采样的函数要换成mipmap专有的贴图采样函数。具体的可以去查一查资料吧。

      稍微说一下mipmap吧,其实这个技术就是为了解决显示像素小于贴图像素时产生的采样失真。显示像素小于贴图像素其实很好理解,就是比如我要在8×8的屏幕区域上显示16×16的贴图。这种情况下就是显示像素(8×8)小于贴图像素(16×16)。

      也就两种情况会出现此问题:
      1.贴图缩小;
      2.3D场景下贴图变远。

      它的解决方式就是把你的贴图按照2的幂次逐级产生多张子贴图。比如一张16×16的贴图,程序就会对你这张贴图产生8×8,4×4,2×2,1×1这几张子贴图。然后采样的时候根据你的缩放比例,选择与缩放比例相邻的两张。再对这两张贴图进行混合采样得到结果。

      希望能解决你的问题。

    • ffnumber1 2019-04-01

      @zrix:mipmap混合采样是个好思路,待我回去试试,多谢赐教。

  2. Sylor 2019-04-01

    一般美术向你要求资源的尺寸的时候,请问怎么提出尺寸要求比较好,个人并没有学过美术,所以具体需要怎样的描述尺寸这个问题不是很清楚

    • zrix 2019-04-01

      @Sylor:这个是设计问题吧,不同游戏都不一样。我也不知道你想要做成什么风格的游戏。建议你最好做个原型,程序写一个原型也好,纸上画一个原型也好。反正和美术聊越有画面越好讲。

  3. Sieger 2020-02-24

    一般2d像素游戏是用什么引擎制作呢

    • zrix 2020-02-24

      @Sieger:如果用来学习游戏制作的话GameMaker2,Construct2,Unity或者是RPGMaker,其中RPGMaker有着最舒适的学习环境(最容易上手么...)。如果用来开发的话还要结合你的2D游戏要做成什么样的,如果要求做成八位机,十六位机那种RPG游戏,RPGMaker比较合适。如果要求再高一点画面更好一点,物理碰撞更真实点的用GameMaker2,Construct2比较好。那么如果你希望能应用体素渲染那种3D渲染效果在你的2D游戏上,选Unity会好一点。

您需要登录或者注册后才能发表评论

登录/注册