« lua 5.4 可能会增加 to-be-closed 特性 | 返回首页 | 粒子系统的设计 »

一种 16 倍抗锯齿字体渲染的方法

昨天读了几篇文章,讲解了一种新的抗锯齿字体渲染的方法

我觉得颇有意思,就试着实现了一版 CPU 版本,想看看针对中文的效果。虽然最后觉得这个算法对游戏领域的实用性不大,不过还是挺有启发的。这里写写我对这个算法的理解,以及我所理解的算法局限性。

原文讲解的非常细致,还配了不少图片,我就不再重复了,只简单说两句。

我认为发明这个算法的动机是 “Our UI has a lot of smooth animation, text should be able to move smoothly across the screen.” 这是过去很多传统字体渲染算法很难解决的。

当我们输出的文字略微偏移 1/4 个屏幕像素时,通常会糊掉。但是这个算法则可以尽可能地保留信息。

因为这个算法的本质是把 16 倍大的字形,以黑白二值位图的形式保存在一个每像素 16bit 的贴图中。和传统的保存字形位图的方式不同,它不储存字体抗锯齿后的灰阶图片,而是一个 bit 保存一个像素。贴图的一个图素保存了 4x4 共 16 个像素。把 16 个点阵像素压缩到贴图的一个图素中带来的并不仅仅是压缩的好处,更重要的是,可以让 gpu 做采样时,可以一次拿出更多的字形信息,方便做抗锯齿处理。

我们在纹理采样时,从贴图上采到的一个图素其实包含了 16 个字形像素的信息。如果我们采样 4 次,就可以拿到 16x16 = 256 像素的位图。然后,计算出真正采样的范围,统计这个采样区域 bit 1 的个数,就可以精确的算出灰阶。

相比传统储存方法,偏移部分像素,就只能通过简单的混合算法求出平均灰阶,这种储存方法相当于推迟了字型抗锯齿计算灰阶的时机。

我做了一个简单的动画,让一个 23 像素高的 “好”字在一个像素范围内轻微位移转圈,我们可以看到,好字的包围盒并没有扩大,但肉眼明显能感知到字的移动。

我们把好字的半像素位移展开, X Y 方向各移动 1/4 1/2 3/4 像素,得到 16 个字,是这样的:

放大点可能看的更清楚:

如果我们把灰阶改成类似微软 ClearType 的方法,利用液晶屏 RGB 三个子像素,可以做到更清晰。这部分工作我懒得做了。


但我认为,这个方法对于目前游戏并没有太大意义。因为用 GPU 实现过于复杂,而收益(文字移动平滑这个特性)并不大。

而且算法本身有个弱点,原文并没有解决。那就是当字体放大或缩小时,其实贴图到帧缓冲的算法就不再是 1:1 的关系。如果按原文的方法 4x4=16 像素的窗口去采样,结果是不对的。如果最终显示的文字比原始字型点阵要小,就应该用大于 4x4 的采样窗口;如果要放大原始点阵,则应该用更小的采样窗口。

这个方法的极限可以把字形放大 4x4 倍而不失真。当你需要输出 4x4 倍大的文字时,其实每次只应该在贴图上采样一个 bit (1x1 窗口)。

用 CPU 可以勉强解决这个缩放问题,GPU 来做也未尝不可。我构想的方法是另外做一种带 mipmap 的纯色贴图,不同的 mipmap 层填充不同的颜色通道,比如第一层用纯红,第二层用纯绿,然后根据采样的颜色结果的红绿比例,可以推测出贴图到帧缓冲的映射比。

对英文来说,缩放问题并不麻烦。只要可以快速生成需要的大小的贴图(这也是原文第三篇讨论的话题),加上合适的 cache 即可;但是中文字形太多,我们就需要太大的 cache 。这也是我认为该算法(对中文)并不实用的原因之一。

Comments

你可以去问问微软为啥要发明 cleartype 。

你的意思就是这个技术主要是为了解决UI动画会产生模糊情况而产生的。那为什么字体会偏移四分之一屏幕像素?都让UI部件以一个像素为最小单位移动不就行了吗

@A

请提高中文及英文阅读能力:

> 我认为发明这个算法的动机是 “Our UI has a lot of smooth animation, text should be able to move smoothly across the screen.”

不缩放不解决渲染到屏幕坐标不是整数像素点的位置的问题。

英文原文有更多解释,以及分析过包括 SDF 在内的历史上已经存在过的字体渲染方法。

还有想要字体清楚,不缩放就好了,比较频繁的缩放使用SDF好了,不频繁的重新渲染符合字当前大小的位图

“公司边新开了家湘菜馆。”

“好吃不如饺子。”

嗯,那为啥不用SDF呢?

我在本 blog 最早提及 Signed Distance Field 是在 2013 年https://blog.codingnow.com/2013/09/edge_font.html

喷子请离远点。

btw , 省略号请用 …

Signed Distanced Fields take a different approach. Instead of storing a shade, the distance to the nearest glyph edge for a pixel is stored. The advantage of this method is that this data scales a lot better for curved edges than shades do. When scaling a glyph up, curves remain smooth. The downside is that straight and hard edges get smoothed out. Advanced solutions like FreeType that store shade data achieve a much higher quality than SDF fonts can.

8012年都过去了,居然连distance field都不知道。。。。

大神终于研究到中文和西文了。。这是排版中的心结~哈哈

Post a comment

非这个主题相关的留言请到:留言本