zoukankan      html  css  js  c++  java
  • 讲一讲一种新型的字体渲染方式

    新的方式,其实一点也不新,其实是一种称为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描述文件

    加油吧,骚年。

  • 相关阅读:
    struts2文件上传报错
    简述算法和程序的区别并举例说明
    JAVA中TreeMap集合筛选字母及每一个字符出现的次数
    Myeclipse2014破解步骤
    修改ubuntu的终端提示符
    gcc 引用math.h头文件,编译出现undefined reference to `pow‘等错误时,需要加参数lm.
    几篇文章
    gdb调试gcc出现:Missing separate debuginfos, use: debuginfoinstall glibcx.i686
    【达内C++学习培训学习笔记系列】C语言之三循环语句和数组
    code::block之spell checker配置
  • 原文地址:https://www.cnblogs.com/crazylights/p/4320431.html
Copyright © 2011-2022 走看看