其他可能的改进
投影增强
前面我们在进行扩散投影模拟的时候,是同时对周围八个点进行采样,但是事实上,有时为了控制投影的方向,可以只对一侧的点进行采样:
如图所示,只需要对右下角的五个格子采样,就可以模拟出左上角的光照。
这样造成的效果是亮的部分会凸起,暗的部分会产生凹陷的效果:
函数的拟合
前面在计算相邻点的加权颜色值时,用到了一个指数函数。指数函数的效果的确很好,考虑到在某些平台上 exp 的消耗可能有点大。另外,任意两个像素之间的欧几里得距离不会超过2.3个像素,所以我们尝试对函数进行一个拟合,如0.926+1.441x + 0.6578x^2 + 0.0417x^4
其实我们还可以将把它化成1/(7x^2 +1),效果也还可以,只是无论是哪种情况,在 PC 上测试差距并不明显(也有可能适得其反)
扫描线
考虑到有些游戏中,会出现一些因为曝光过度而无法显示扫描线的情况。于是,我们就需要对扫描线进行加强:
- float limit = 1 - step(257.0, min(frac(i.pixel_no.x), 1- frac(i.pixel_no.y)) * _MainTex_TexelSize.z);
- float bright = Luminance(out_color);
- return fixed4(out_color *(1.8 - limit * bright * bright * 0.89), 1.0);
但是对于某些偏暗的游戏,如果为了提高整体亮度,而扫描线同时也强化的很厉害,那么就会导致“碳化”:
虽然这样的扫描线加强在其他场合正是我们需要的,但在这里只会让画面变得很脏。关于这个问题并没有很好的解决方案,这需要根据不同游戏对参数做出调整。作为游戏开发,如果美术风格及早的确定,颜色的选择有所参照,将会对程序的优化有极大的帮助。而2D 像素游戏由于很少受光照影响,再加上像素画本身也极其依赖于 palette,所以如果 palette 控制的好,是可以根据其调试出一个很好的状态的。
由于目前只用针对一款游戏,所以上面的手工调整可以接受。如果我们需要大量的调整,我在想,可能还有一种思路是像 tone mapping 一样,将亮度映射在一个合理的区域内,这样既保留了细节又处理了边界状况。
Tactics Ogre 的特殊处理
刚开始我为 Taactic Ogre(中文译为:皇家骑士团)写 shader 的时候,出现了一个问题。由于很容易知道 psp 的分辨率是480*272,我就将其硬编码到 shader 中。但是却出现了一些意想不到的状况。在横坐标方向上,扫描线的分布不均匀。由于是周期性的,并且随着窗口的扩大问题更为严重,我最开始猜测是模拟器的精度出现了问题,我查了下 changelog 也的确提到了这个问题,只是我使用的版本应该已经修复了这个问题。另外,我测试了其他的游戏,发现一切都很正常,如果真的是精度问题,不该只出现在这一款游戏上。查看了整个 render 过程后发现 Tactics Ogre 中有些地方与其他游戏做的不同,比如:
Tactics Ogre 在 draw 顶部的滚动文本时,二手游戏账号购买并不会对其裁剪,而是放到了第二个 color pass 里才进行裁剪:
不过 ppsspp 模拟器提供了 u_texelDelta 这样一个 uniform,我们可以利用它得知当前输入纹理的 resolution:
- vec2 c_resolution = 1.0f / u_texelDelta;
这样,即使在某些场景中,屏幕的分辨率发生变化,我们也能够保证显示正确的扫描线。
最终 PSP 模拟器效果图
在这里给出自己制作的在 PSP 模拟器上的最终效果,请放大后观察。
结语
本文主要讨论了针对细像素游戏的画质增强,但是这并不意味着像素游戏的增强方式只有一种,相反,光是这里?就提到多种后期特效。我们也无法说哪种效果比另一种更好。更多的时候,还是需要根据对游戏的定位来定制自己的后期特效,从而让画面为游戏核心服务。程序和美术之间的沟通是否充分也是能否有效的构建出成功的游戏画面中很重要的一个因素。
最后,你们觉得这是一篇讨论像素游戏中画面增强的文章吗?
不,不是的,我只是在安利 Tactics Ogre