Agg学习笔记之渲染
八 30
Agg渲染层(Render)分为三层,最底层和RenderBuffer通信,主要封装各种颜色模式和基本的操作,如Copy/Blend。中层主要是BaseRender,作为上下两种的连接层,主要实现基本的裁剪。渲染层最上是应用层,用来和Scanline Rasterizer 层通信。他们的交互通过scanline 来完成。
Scanline Rasterizer 主要用于光栅化上层提供的矢量图形,并且以Y轴将其分解成y条水平线,这些水平线最终存储在scanline中。
关于scanline,这里摘抄一段(http://blog.csdn.net/liyiwen007/archive/2010/06/09/5659411.aspx ):
AGG 中主要的光栅化技术是基于 scanline 的,也就是说,一个多边形会先转换成很多的水平扫描线,然后再逐个描画这些扫描线。同样的, scanline rasterizer 并不是唯一可以用于生成水平扫描线(scanline)的类,你也可以使用一些容器,甚至是你自己的 super-ultra-mega rasterizer 。
在从 rasterizer(光栅化器)到 scanline renderer 之间的信息转换时,用到了 scanline 容器。一个 scanline 由很多的水平的、不相交的 span 组成。这些 span 按 x 轴排序。这就意味着并没有提供排序这个操作,必须在将 span 添加到 scanline 时就把顺序处理好。如果顺序不是按要求排列的,那么可能会出现未定义的行为。
AGG 中有以下三种 scanline 容器。
- scanline_u – 未包装的 scanline 容器。
- scanline_p – 包装过的 scanline 容器。
- scanline_bin – 原始的,“带锯齿”的 scanline 容器。
前面两种容器可以包含去锯齿信息,第三种不行。
包装的(packed) scanline 与未包装的(unpacked) scanline 的区别在于, unpacked scanline 总是会为所有像素保存覆盖值(coverage value),包括那些全部覆盖在多边形内部的像素。而 packed scanlines 则会把具有相同 coverage value 的像素合并成 solid span。
看起来好像使用 packed 版的 scanline 总是会好一点,但在实践中并非如此。但你渲染一些大型的实心多边型时,使用 scanline_p 会更快,那是因为多边型的面积比周长要大很多(从像素的角度来衡量)。但是如果是渲染字符的时候绝对应该使用 scanline_u ,这样就能处理更少的 span 了,(scanline_u 会比 scanline_p)大约少产生三倍左右的 span,而 span 数本身就是一项重要的开销。同样的,在大多数 span 产生器中(比如 gradients, Gouraud shader, 以及 image 产生器等),span 的数量更加是(效能的)关键,所以一般也不会使用 scanline_p。
站在巨人的肩膀上,我也废话几句,Agg抗锯齿信息通过存储在scanline_u和scanline_p中的cover值来体现,虽然cover值不等同alpha值,不过它的大小直接影响到alpha值的大小,这种影响在Agg渲染层顶层中得以体现。
应用层包含几个类和若干工具函数,实际上这些类也就对工具函数进行简单的封装(agg_renderer_scanline.h)。这些类包括:
(http://www.cppprog.com/2009/0821/150_5.html )
template<class BaseRenderer> class renderer_scanline_aa_solid; //实色AA渲染 template<class BaseRenderer> class renderer_scanline_bin_solid; //实色原始渲染 template<class BaseRenderer, class SpanAllocator, class SpanGenerator> class renderer_scanline_aa; // 自定义AA渲染 template<class BaseRenderer, class SpanAllocator, class SpanGenerator> class renderer_scanline_bin; // 自定义原始渲染
关于这四个类,有两种分类方法:
aa/bin(一三/二四),包含aa的使用scanline的反锯齿信息(通过alpha值实现),包含bin的则仅仅根据原始的顶点渲染。这两者的区别可以通过下面的图来说明:
左边使用 renderer_scanline_bin_solid渲染,每一次Span渲染操作都是同一颜色(因为忽略了反锯齿信息),右边使用 renderer_scanline_aa_solid,因为会使用scanline的抗锯齿信息,所以每一次Span都可能包含若干种颜色(通过scanline中cover值改变alpha值,然后alpha blend改变颜色),从而导致锯齿不明显(这也导致了抗锯齿的线比没有抗锯齿的线稍窄)。
另一种分类方法是solid/none(一二/三四),solid(如其意)在渲染Span是只能使用单种颜色,如上图。而后者则可以对一次Span渲染中的每一个像素指定一种颜色。这些颜色从哪里来呢?通过其模板参数 SpanGenerator提供,那SpanGenerator是什么,它的颜色信息从哪里来呢?看看这里 http://www.cppprog.com/2009/0829/153.html 。SpanGenerator用于从一些复杂的颜色源来获取Span颜色信息,例如位图,渐变色等等。
这些工具函数包括render_scanlines、render_scanlines_aa_solid等。其实现也相当之简单,通过遍历Rasterizer来生成Scanline,然后对每一个Scanline调用底层渲染层来完成多边形的渲染。
最近评论