讲一讲一种新型的字体渲染方式

新的方式,其实一点也不新,其实是一种称为signd distance field的矢量图保存和渲染方法。

早在二零零几年,就已经有一些游戏应用了这种技术,而他用于字体渲染也被发掘多时。

但是这个世界,技术成果转化的速度总是很慢很慢,这个优势明显的技术一直没有普及开来。

 

1.矢量的优势

我们先来说说矢量和位图的区别:

一个汉字,人眼看起来就是一个形状

这是位图,是上面那个汉子用位图存储方式放大后的一个局部

再来看看矢量化放大的效果

瞎子也能明白,矢量是适合缩放的。

现在游戏中,因为大量使用位图字体,而位图字体并不适合缩放,于是如果要用不同大小

位图放大后都是这个屌样子。

2.Signeddistancefield表示法

这也是为什么我们要引入signddistancefield,他是一种矢量表示法。

用位图,表示矢量,表示方法我随便一说,你随便一听,并不是太有所谓。因为我会给你一套东西,你能照猫画虎用起来。

还是这张图,把他存成一个很小的像素图,只不过每个像素存的不是颜色,而是离边的最短距离。

现在白色部分,在形状内,存为负值,黑色部分,在形状外,存为正值。

请忽略我拙略的绘图技巧。

这样保存后的图片,你可能会问我,一个像素分量是0~255,咋存正负,我会告诉你,128当零,行不行。

这个细节不深究,让我们换个方法来表示,本质上是为了区分边的内外。比如我设定颜色255在形状内最深的地方,127是形状边,0是离形状最远的地方,当然我们也不需要离边太远的数据,可以让离边超出一定距离的数据全是255和零,只有在边附近,有过度。

这是一个文字用signeddistancefield表示法保存后的结果。

如我们所言,255是离边最远,在形状内的部分,外边的纯透明部分,是alpha为零里边最远的部分。

 

这样的表示法,在还原成形状的时候,我们只要判断 >就行了,>127的部分画出来,就是原来的形状

>200的部分画出来,是个向内收缩的形状。

>100的部分画出来,是个向外扩张的形状。

我们如果要做描边,可以在shader里写个if

比如>127纯白 100-127 黑色。

你可能会发现一个问题,这种情况只有透明不透明,两种情况。

这个问题可以解决,往下看

 

而且因为源数据是离边的距离,两个像素的插值就是当前像素离边的距离。

这个信息是线性的,插值数据不会偏离太远,抗缩放性能非常好。

3.实战SignedDistanceField

第一步,把图片或者字体保存为signeddistancefield

因为SDF实际上已经是应用很多的技术,所以工具并不缺乏。

我就找到了两个。

http://www.gamedev.net/topic/491938-signed-distance-bitmap-font-tool/

我们简称他BFTool,我很喜欢这个工具,因为很小巧,几百k,还包括源码和测试字体和图片。

还有龚敏敏的KLAYGE里面也提供了一个字体保存为signeddistancefield的工具

不过这玩意从他的一堆c++代码里剥出来要花点功夫。

我们这里就介绍一下BFTool

先下载这个工具

http://www.lonesock.net/files/SDFont.zip

他没有图形界面,but,whocare

找到这个文件

可以把一张png 或者一个ttf拖上去

然后输入一些参数,就会生成啦。

先找张图片

比如这个,至少1024以上

让我们把他输出成32*32的sdf图像

你可能无法期待这32*32个像素可以输出什么像样的效果。

来吧,见证奇迹的时刻到了。

这就是32*32的SDF图像还原出的效果,还顺便做了描边

更粗的描边

向内描边

使用的shader关键代码如下

http://code.taobao.org/p/fightbeta/src/trunk/dfbitmap/

 

很简单,就是ifif,描边没有任何开销,不过去狗牙要多几次采样。(这地方是我考虑不周到)

后来考虑了一下,不用多次采样,将距离多分几段插插值,不用额外采样就能完美去狗牙

注,这张图是展示去狗牙效果,是128分辨率的,和上面的不一致。

能明白我再说什么的人自然明白。

4.关于字体

你已经看到了32*32的SDF图像能做到什么,如果你把文字生成为32*32的足够精细了。

一张2048的贴图,可以放4000个32*32的文字。

而且抗缩放,大小字号一图搞定。

只要把一个ttf字库拖入sdfont.exe

给他参数,你就能得到一张sdf图片,和一张字符uv描述文件

加油吧,骚年。

posted @ 2015-03-07 15:37  疯光无线  阅读(7452)  评论(6编辑  收藏  举报