光栅化,又称为扫描转换,用于确定由顶点构成的基本图元内包含了哪些像素,并根据这些像素构成面片,每个面片都有其属性,如颜色、纹理坐标等,可根据顶点的相应值进行插值计算得到。而像素的颜色也是根据顶点的属性如颜色、纹理等计算得到
首先来看顶点在窗口坐标中都为整数的线段
假设有线段如右图中所示,直线两顶点坐标分别为$(x_1,y_1)$,$(x_2,y_2)$,直线方程为$y=mx+h$,其中斜率$m=\frac{\Delta x}{\Delta y}$。并假设已定义了函数write_pixel用于绘制每个像素
DDA为DigitlDifferential Analyzer即数字差分分析的简称,主要用于求解微分方程。
这里假设直线$y=mx+h$满足微分方程形式 $$\frac{dy}{dx}=m=\frac{\Delta y}{\Delta x}=\frac{y_2-y_1}{x_2-x_1}$$
在沿着扫描线$\Delta x=1$的方向,可以执行如下的操作:
for(x=x1;x<=x2;x++){
y+=m;
write_pixel(x,round(y),line_color);
}
DDA算法的主要思想是对每一个x,计算距离其对应值最近的y值,但是对于分辨率较大的线段,会存在问题,如下图所示:
解决此问题,可利用对称性质,即原方法适用于$0\leq m \leq 1$情形,当$m>1$时,交换$x$和$y$的角色,即对每个y,找到其对应值最近的x
DDA算法需要在每一步都执行浮点运算,在Bresenham算法中可避免浮点计算
算法执行利用对称性先考虑$0\leq m\leq 1$的情形,其它情况可根据对称性进行计算。假设像素的中心位置为整数的一半。根据算法,如果从某一个特定像素开始绘制,下一个能够绘制的像素只有两种可能
根据$d=\Delta_x(b-a)$取整,有以下两种情形:
为提高$d$的计算效率,来看$d_k$,其值对应于$x=k$时的值,则有
则对每一个x,只需要一次整数加法和一次判断即可,在显卡核心上,只需要一条指令氷可完成计算
多边开扫描转换,即多边形势填充,关键在于决定哪些像素位于多边形内,而哪些像素位于多边形外,需要分情形讨论。
利用奇偶性测试,即通过扫描线与多边形边的交战数
利用环绕数(Winding number)
环绕数即计算像素点被包围的次数,如图产中所示。一般默认认为环绕数非0,即意味着像素位于多边形内部
帧缓存填充一般在流水线最后阶段进行处理,并且只针对凸多边形,非凸多边形需要先分割为凸多边形的镶嵌。填充的颜色根据顶点的颜色计算得到,并结合深度缓存算法确切计算每个像素应当着色的颜色
图中,$C_1,C_2,C_3$的颜色由顶点着色或glColor指定,$C_4$的颜色根据$C_2$和$C_3$的结果插值计算得到,$C_5$的结果根据$C_1$和$C_3$的结果插值计算得到,同时对于位于$C_4$和$C_5$之间的像素点,则根据这两个点的值插值计算得到
漫填充(Flood Fill),其基本思想是利用多边形内的一个种子点作为起点,以递归的形式开始填充。该起点初始颜色设置为白色,扫描过程中将边及内部的点填充为黑色
flodd_fill(int x, int y){
if(read_pixel(x,y)==WHITE){
write_pixel(x,y,black);
flood_fill(x-1,y);
flood_fill(x+1,y);
flood_fill(x,y+1);
flood_fill(x,y-1);
}
}
维持一个用于表示多边形与扫描线相交情况的数据结构,也可完成填充,其主要过程为两步,一是根据扫描线进行排序,二是对每条扫描线进行填充