distance font rendering

使用bitmap font 时有一个缺陷就是在字体缩放时, 会显示出明显的锯齿. 所以, 通常会为某种字体创建诸如 small ,normal ,big 等不同大小的字体以应对不同的缩放区间.

这样会造成巨大的内存开销.  value 的论文 http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf 中提到一种

scale friendly 的方法, 实现的结果如下. 

实现方法:

1. 使用freetype,或者windows gdi 创建字符的位图. 这里用了super-sample. 对于基准20高度的字体, 使用20 X SuperSampleScale 的字体来创建位图. 在上图中是以20 X 4 来创建的.

2. 针对每个字符的位图, 转换并down scale 到signed distance field. 这里要注意的是, 通常在bitmap-font 中我们总以字符位图的最小包围盒来存储并渲染字符. 可是对于distance field, 必须

   在字符的包围盒外围进行较大的扩展. 比如 'A' 的位图大小是16X20, 那么对于创建Distance Field而言, 我们得扩展到 (16+PaddingX*2) *(20 +PaddingY*2), 然后将字符位图放入到中间位置后进行

distance 计算. 否则纹理采样中, 会应为线性过滤导致字符的边缘跨入到相邻字符上. 

3. 将down scale 后的distance 转换为位图, 打包存储. 

      基本上现在google出来的文章中提到的都是对一整张打包后的Bitmap进行处理,比如:

  https://github.com/libgdx/libgdx/wiki/Distance-field-fonts

     https://crimild.wordpress.com/2013/09/01/improving-text-rendering-with-signed-distance-fields/

  https://www.mapbox.com/blog/text-signed-distance-fields/

这种方式我觉得有问题, 它要求字符在atlas 中排列得非常稀疏, 并且小心地指定一个扫描半径, 以保证在某个字符的区域内, distance 不会受其它字符的影响. 

上图中, 由于排列和扫描半径的问题, 导致在A字符包围区的像素, 红线标记区域, 其distance 所计算的最近边缘可能位于G字符上. 在渲染的时候将会出现不正确的结果. 

调整扫描半径和padding 后的处理结果. 

 

  • . singed distance field font 在放大的时候具有较好的效果, 但是在字体缩小时会非常难看.
  •  关于smoothstep .
smoothstep(0.5 - SmoothBais, 0.5 + SmoothBais, Distance);

 SmoothBais 的值会严重影响最终渲染质量. 我最后选择了 FontHeight / TextureSize . SmoothBais 是一个跟随纹理大小,采样模式较为敏感的数据, 或许用ddx ddy 会更好.

 

WIP:

  • render quality.
  • glow & shadow.  

 

posted @ 2015-08-15 14:58  访问异常  阅读(557)  评论(0编辑  收藏  举报