使用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.