1、第2章 光栅图形学,2.1直线段的扫描转换算法 2.2圆弧的扫描转换算法 2.3多边形的扫描转换与区域填充 2.4字符 2.5裁剪 2.6反走样 2.7消隐,2.1 直线段的扫描转换算法,直线的扫描转换: 确定最佳逼近于该直线的一组象素,并且按扫描线顺序,对这些象素进行写操作。 三个常用算法: 2.1.1数值微分法(DDA) 2.1.2中点画线法 2.1.3Bresenham算法。,2.1.1 数值微分(DDA)法,基本思想 已知过端点P0 (x0, y0), P1(x1, y1)的直线段L y=kx+b 直线斜率为 从x的左端点x0开始,向x右端点步进。步长=1(个象素),计算相应的y坐标y
2、=kx+B;取象素点(x, round(y)作为当前点的坐标。,计算yi+1= kxi+1+B = k1 xi+B+kx= yi+kx 当x =1; yi+1 = yi+k 即:当x每递增1,y递增k(即直线斜率); 注意上述分析的算法仅适用于k 1的情形。在这种情况下,x每增加1,y最多增加1。 当 k 1时,必须把x,y地位互换,例:画直线段p(0,0)-P1(5,2) x int(y+0.5) y+0.5 0 0 0 1 0 0.4+0.5 2 1 0.8+0.5 3 1 1.2+0.5 4 2 1.6+0.5 5 2 2.0+0.5 注:网格点表示象素,void DDALine(int
3、 x0,int y0,int x1,int y1,int color) int x; float dx, dy, y, k; dx, = x1-x0, dy=y1-y0; k=dy/dx, y=y0; for (x=x0; xx1, x+) drawpixel (x, int(y+0.5), color); y=y+k;,2.1.2 中点画线法,基本思想 当前象素点为(xp, yp) 。下一个象素点为P1或P2。 设M=(xp+1, yp+0.5),为p1与p2 之中点,Q为理想直线与x=xp+1 垂线的交点。将Q与M的y坐标进 行比较。 当M在Q的下方,则P2 应为下一个象素点; M在Q的上
4、方,应取P1为下一点。,构造判别式:d=F(M)=F(xp+1,yp+0.5)=a(xp+1)+b(yp+0.5)+c其中a=y0-y1, b=x1-x0, c=x0y1-x1y0当d0,M在L(Q点)上方,取右方P1为下一个象素; 当d=0,选P1或P2均可,约定取P1为下一个象素;d是xp, yp的线性函数,因此可采用增量计算,提高运算效率。,若当前象素处于d0情况,则取正右方象素P1(xp+1, yp), 要判下一个象素位置,应计算d1=F(xp+2, yp+0.5)=a(xp+2)+b(yp+0.5)=d+a; 增量为a 若d0时,则取右上方象素P2(xp+1, yp+1)。要判断再下
5、一象素,则要计算d2= F(xp+2, yp+1.5)=a(xp+2)+b(yp+1.5)+c=d+a+b ;增量为ab,画线从(x0, y0)开始,d的初值d0=F(x0+1, y0+0.5)=F(x0, y0)+a+0.5b =a+0.5b。可以用2d代替d来摆脱小数,提高效率。 令 d0=2a+b, d1=2a, d2=2a+2b,我们有如下算法 。,例:用中点画线法P0(0,0) P1(5,2) a = y0-y1=-2, b = x1-x0 = 5 d0 = 2a+b = 1, d1= 2a = - 4, d2 = 2(a+b)=6 i xi yi d 1 0 0 1 2 1 0 -
6、3 3 2 1 3 4 3 1 -1 5 4 2 5,void Midpoint Line (int x0,int y0,int x1, int y1,int color) int a, b, d1, d2, d, x, y;a=y0-y1, b=x1-x0, d=2*a+b;d1=2*a, d2=2* (a+b);x=x0, y=y0;drawpixel(x, y, color);while (xx1) if (d0) x+, y+, d+=d2; else x+, d+=d1;drawpixel (x, y, color); /* while */ /* mid PointLine */,
7、2.1.3 Bresenham算法,基本思想 过各行各列象素中心构造一组虚拟网格线。按直线从起点到终点的顺序计算直线与各垂直网格线的交点,然后根据误差项的符号确定该列象素中与此交点最近的象素。,设直线方程为: ,其中k=dy/dx。 因为直线的起始点在象素中心,所以误差项d的初值d00。 X下标每增加1,d的值相应递增直线的斜率值k,即ddk。一旦d1,就把它减去1,这样保证d在0、1之间。 当d0.5时,最接近于当前象素的右上方象素(xi1,yi1 而当d0.5时,更接近于右方象素(xi1,yi)。 为方便计算,令ed-0.5, e的初值为-0.5,增量为k。 当e0时,取当前象素(xi,y
8、i)的右上方象素(xi1,yi1); 而当e0时,更接近于右方象素(xi1,yi)。,可以改用整数以避免除法。由于算法中只用到误差项的符号,因此可作如下替换: 例:Line: P0(0, 0), P1(5,2) k=dy/dx=0.4x y e0 0 -0.51 0 -0.12 1 0.33 1 -0.34 2 0.1 5 2 -0.5,void Bresenhamline (int x0,int y0,int x1, int y1,int color) int x, y, dx, dy;float k, e;dx = x1-x0, dy = y1- y0, k=dy/dx; e=-0.5,
9、x=x0, y=y0;for (i=0; idx; i+) drawpixel (x, y, color);x=x+1,e=e+k;if (e0) y+, e=e-1;,2.2 圆弧的扫描转换算法,圆的特征:八对称性。只要扫描转换八分之一圆弧,就可以求出整个圆弧的象素集 中点画圆法 考虑中心在原点,半径为R 的第二个8分圆, 构造判别式(圆方程),若 d=0, 则应取P2为下一象素,而且下一象素的判别式为第 一个象素是(0,R),判别式d的初始值为,为了进一步提高算法的效率,可以将上面的算法中的浮点数改写成整数,将乘法运算改成加法运算,即仅用整数实现中点画圆法。 使用e=d-0.25代替d e
10、0=1-R,算法过程,MidPointCircle(int r int color) int x,y;float d;x=0; y=r; d=1.25-r;circlepoints (x,y,color); /显示圆弧上的八个对称点while(x=y) if(d0) d+=2*x+3;else d+=2*(x-y)+5; y-; x+; circlepoints (x,y,color); ,2.3 多边形的扫描转换与区域填充,多边形有两种重要的表示方法:顶点表示和点阵表示。 多边形的扫描转换:把多边形的顶点表示转换为点阵表示。 区域可采用内点表示和边界表示两种表示形式。 区域填充:指先将区域的
11、一点赋予指定的颜色,然后将该颜色扩展到整个区域的过程。,多边形分为凸多边形、凹多边形、含内环的多边形。,2.3.1多边形的扫描转换,扫描线算法 基本思想: 按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,即完成填充工作。 对于一条扫描线填充过程可以分为四个步骤: (1)求交(2)排序 (3)配对(4)填色,一个多边形与若干扫描线,数据结构 活性边表(AET):把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中 结点内容x:当前扫描线与边的交点坐标 x:从当前扫描线到下一条扫描线间x的增量 ymax:该边所交的最高扫描线号yma
12、x,新边表(NET):存放在该扫描线第一次出现的边。若某边的较低端点为ymin,则该边就放在扫描线ymin的新边表中上图所示各条扫描线的新边表NET,假定当前扫描线与多边形某一条边的交点的x坐标为x,则下一条扫描线与该边的交点不要重计算,只要加一个增量x。 设该边的直线方程为:ax+by+c=0; 若yyi,x=x i;则当y = y i+1时,其中 为常数,扫描线与多边形的顶点或边界相交时,必须正确的交点的取舍。只需检查顶点的两条边的另外两个端点的y值。按这两个y值中大于交点y值的个数是0,1,2来决定。,算法过程,void polyfill (polygon, color)int colo
13、r; 多边形 polygon; for (各条扫描线i ) 初始化新边表头指针NET i;把y min = i 的边放进边表NET i; y = 最低扫描线号;初始化活性边表AET为空;for (各条扫描线i ),把新边表NET i 中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列; 遍历AET表,把配对交点区间(左闭右开)上的象素(x, y),用drawpixel (x, y, color) 改写象素颜色值; 遍历AET表,把y max= i 的结点从AET表中删除,并把y max i 结点的x值递增x; 若允许多边形的边自相交,则用冒泡排序法对AET表重新排序; /* poly
14、fill */,边界标志算法,基本思想: 帧缓冲器中对多边形的每条边进行直线扫描转换,亦即对多边形边界所经过的象素打上标志。 然后再采用和扫描线算法类似的方法将位于多边形内的各个区段着上所需颜色。 使用一个布尔量inside来指示当前点是否在多边形内的状态。,算法过程,void edgemark_fill(polydef, color) 多边形定义 polydef; int color; 对多边形polydef 每条边进行直线扫描转换;inside = FALSE;for (每条与多边形polydef相交的扫描线y )for (扫描线上每个象素x ) if(象素 x 被打上边标志)inside
15、 = ! (inside);if(inside!= FALSE)drawpixel (x, y, color);else drawpixel (x, y, background); ,用软件实现时,扫描线算法与边界标志算法的执行速度几乎相同, 但由于边界标志算法不必建立维护边表以及对它进行排序,所以边界标志算法更适合硬件实现,这时它的执行速度比有序边表算法快一至两个数量级。,2.3.2区域填充算法,区域指已经表示成点阵形式的填充图形,它是象素的集合。 区域可采用内点表示和边界表示两种表示形式。 区域可分为4向连通区域和8向连通区域。 区域填充指先将区域的一点赋予指定的颜色,然后将该颜色扩展到整
16、个区域的过程。区域填充算法要求区域是连通的,4向连通区域和8向连通区域四个方向运动 八个方向运动 四连通区域 八连通区域,区域填充的递归算法,内点表示的4连通区域的递归填充算法: void FloodFill4(int x,int y,int oldcolor,int newcolor) if(getpixel(x,y)=oldcolor) /属于区域内点oldcolor drawpixel(x,y,newcolor);FloodFill4(x,y+1,oldcolor,newcolor);FloodFill4(x,y-1,oldcolor,newcolor);FloodFill4(x-1,y
17、,oldcolor,newcolor);FloodFill4(x+1,y,oldcolor,newcolor); ,边界表示的4连通区域的递归填充算法: void BoundaryFill4(int x,int y,int boundarycolor,int newcolor) int color;if(color!=newcolor ,区域填充的扫描线算法,算法步骤: 首先填充种子点所在扫描线上的位于给定区域的一个区段 然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。 反复这个过程,直到填充结束。,(1)初始化:堆栈置空。将种子点(x,y)入栈。 (2)出栈
18、:若栈空则结束。否则取栈顶元素(x,y),以y作为当前扫描线。 (3)填充并确定种子点所在区段:从种子点(x,y)出发,沿当前扫描线向左、右两个方向填充,直到边界。分别标记区段的左、右端点坐标为xl和xr。 (4)并确定新的种子点:在区间xl,xr中检查与当前扫描线y上、下相邻的两条扫描线上的象素。若存在非边界、未填充的象素,则把每一区间的最右象素作为种子点压入堆栈,返回第(2)步。 上述算法对于每一个待填充区段,只需压栈一次;因此,扫描线填充算法提高了区域填充的效率。,2.4 字 符,字符指数字、字母、汉字等符号。 计算机中字符由一个数字编码唯一标识。 “美国信息交换用标准代码集”简称ASC
19、II码。它是用7位二进制数进行编码表示128个字符 汉字编码的国家标准字符集。每个符号由一个区码和一个位码(2字节)共同标识。 区分ASCII码与汉字编码,采用字节的最高位来标识,点阵字符:每个字符由一个位图表示 矢量字符:记录字符的笔画信息点阵字符 点阵字库中的位图表示 矢量轮廓字符,特点: 点阵字符:存储量大,易于显示 矢量字符:存储量小,美观,变换方便 需要光栅化后才能显示。,字符属性,字体 宋体 仿宋体 楷体 黑体 隶书 字高 宋体 宋体 宋体 宋体 字宽 字倾斜角 倾斜 倾斜 对齐 (左对齐、中心对齐、右对齐) 字色 红色、绿色、蓝色 写方式:替换方式。与方式,2.5 裁剪,裁剪:确
20、定图形中哪些部分落在显示区之内,哪些落在显示区之外,以便只显示落在显示区内的那部分图形。这个选择过程称为裁剪。2.5.1直线段裁剪 2.5.2 多边形裁剪,2.5.1直线段裁剪,直线段裁剪算法是复杂图元裁剪的基础。复杂的曲线可以通过折线段来近似,从而裁剪问题也可以化为直线段的裁剪问题。,Cohen-Sutherland裁剪,基本思想:对于每条线段P1P2分为三种情况处理分为三种情况处理: (1)若P1P2完全在窗口内,则显示该线段P1P2简称“取”之。 (2)若P1P2明显在窗口外,则丢弃该线段,简称“弃”之。 (3)若线段不满足“取”或 “弃”的条件,则在交点处把线段分为两段。其中一段完全在
21、窗口外,可弃之。然后对另一段重复上述处理。,为快速判断,采用如下编码方法: 每个区域赋予4位编码,编码 线段裁剪,若P1P2完全在窗口内code1=0,且code2=0,则“取” 若P1P2明显在窗口外code1&code20,则“弃” 在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。,计算线段P1(x1,y1)P2(x2,y2)与窗口边界的交点if(LEFT,中点分割裁剪算法,基本思想:与前一种Cohen-Sutherland算法一样首先对线段端点进行编码,并把线段与窗口的关系分为三种情况: 全在、完全不在和线段和窗口有交。对前两种情况,进行一样的处理。 对于
22、第三种情况,用中点分割的方法求出线段与窗口的交点。,求线段与窗口的交点,A、B分别为距p0、p1最近的可见点,Pm为p0p1中点,从 出发找最近可见点的方法 先求出 的中点 若 不是显然不可见的,并且 在窗口中有可见部分,则距 最近的可见点一定落在 上,所以用 代替 ;,否则取 代替 再对新的 求中点 。重复上述过程,直到 长度小于给定的控制常数为止,此时 收敛于交点。 从p1出发找最近可见点采用上面类似方法。,梁友栋Barskey算法,梁-Barskey算法的几何含义,参数化形式写出裁剪条件:可以统一表示为形式:,pk=0且qk0,线段从裁剪边界延长线的内部延伸到外部。 对于每条直线,可以计
23、算出参数u1和u2,它们定义了在裁剪矩形内的线段部分,u1的值由线段从外到内遇到的矩形边界所决定(p0)。对这些边界计算rk=qk/pk 。u2取1和各个rk值之中的最小值。 如果u1u2,则线段完全落在裁剪窗口之外,被舍弃。 否则裁剪线段由参数u的两个值u1,u2计算出来。,void LB_LineClip(x1,y1,x2,y2,XL,XR,YB,YT) float x1,y1,x2,y2,XL,XR,YB,YT; float dx,dy,u1,u2;tl=0;tu=1; dx =x2-x1;dy =y2-y1;if(ClipT(-dx,x1-Xl,bool ClipT(p,q,u1,u2
24、) float p,q,*u1,*u2; float r; if(p*u2)return FALSE;else if(r*u1) *u1=r; return TRUE; 。/下页,else if(p0) r=p/q;if(r*u1)return FALSE;else if(r*u2) *u2=r;return TRUE; else if(q0) return FALSE;return TRUE; ,2.5.2 多边形裁剪,基本思想是一次用窗口的一条边裁剪多边形。 考虑窗口的一条边以及延长线构成的裁剪线该线把平面分成两个部分:可见一侧;不可见一侧 多边形的各条边的两端点S、P。它们与裁剪线的位置
25、关系只有四种,对于情况(1)仅输出顶点P;情况(2)输出0个顶点; 情况(3)输出线段SP与裁剪线的交点I; 情况(4)输出线段SP与裁剪线的交点I和终点P上述算法仅用一条裁剪边对多边形进行裁剪,得到一个顶点序列,作为下一条裁剪边处理过程的输入。 对于每一条裁剪边,算法框图同上,只是判断点在窗口哪一侧以及求线段SP与裁剪边的交点算法应随之改变。,逐次多边形裁剪算法框图,处理线段SP过程子框图,2.5.3 字符裁剪,串精度:将包围字串的外接矩形对窗口作裁剪 字符精度:将包围字的外接矩形对窗口作裁剪 以及笔画象素精度:将笔划分解成直线段对窗口作裁剪待裁剪字符串 串精度裁剪 字符精度裁剪 象素精度裁
26、剪,用离散量表示连续量引起的失真现象称之为走样(aliasing) 用于减少或消除这种效果的技术称为反走样(antialiasing),2.6 反走样,2.6.1提高分辨率,把显示器分辨率提高一倍, 直线经过两倍的象素,锯齿也增加一倍, 但同时每个阶梯的宽度也减小了一倍, 所以显示出的直线段看起来就平直光滑了一些。 增加分辨率虽然简单,但是不经济的方法, 而且它也只能减轻而不能消除锯齿问题,2.6.2 区域采样,基本思想: 每个象素是一个具有一定面积的小区域,将直线段看作具有一定宽度的狭长矩形。当直线段与象素有交时,求出两者相交区域的面积,然后根据相交区域面积的大小确定该象素的亮度值。有宽度的
27、线条轮廓 象素相交的五种情况及用于计算面积的量,面积计算 情况(5)阴影面积为:D2/2m; 情况(4)阴影面积为:D - m/2; 情况阴影面积为:1 - D2/m 为了简化计算可以采用离散的方法n=9,k=3近似面积为1/3,首先将屏幕象素均分成n个子象素, 然后计算中心点落在直线段内的子象素的个数k。 将屏幕该象素的亮度置为相交区域面积的近似值可k/n。 非加权区域采样方法有两个缺点: 象素的亮度与相交区域的面积成正比,而与相交区域落在象素内的位置无关,这仍然会导致锯齿效应。 直线条上沿理想直线方向的相邻两个象素有时会有较大的灰度差。,2.6.3 加权区域取样,基本思想: 使相交区域对象
28、素亮度的贡献依赖于该区域与象素中心的距离 当直线经过该象素时,该象素的亮度F是在两者相交区域A上对滤波器(函数w)进行积分的积分值。滤波器函数w可以取高斯滤波器,可采用离散计算方法 如:我们将屏幕划分为n=33个子象素,加权表可以取作:权函数w(x,y)为微面元dA与象素中心距离d的函数,然后求出所有中心落于直线段内的子象素。 最后计算所有这些子象素对原象素亮度贡献之和 乘以象素的最大灰度值作为该象素的显示灰度值。,2.7 消隐,消隐的分类 消除隐藏线 消除隐藏面 画家算法 Z缓冲区(Z-Buffer)算法 扫描线Z-buffer算法 区域子分割算法 光线投射算法,基本概念,投影变换失去了深度
29、信息,往往导致图形的二义性 要消除二义性,就必须在绘制时消除被遮挡的不可见的线或面,习惯上称作消除隐藏线和隐藏面,简称为消隐。 经过消隐得到的投影图称为物体的真实图形。长方体线框投影图的二义性,消隐的对象是三维物体。三维体的表示主要有边界表示和CSG表示等。 消隐结果与观察物体有关,也与视点有关。线框图 消隐图 真实感图形,2.7.1消隐的分类,按消隐对象分类 线消隐 消隐对象是物体上的边,消除的是物体上不可见的边。 面消隐 消隐对象是物体上的面,消除的是物体上不可见的面。,Southerland按消隐空间分类,物体空间的消隐算法 (光线投射、Roberts) 将场景中每一个面与其他每个面比较
30、,求出所有点、边、面遮挡关系。 图像空间的消隐算法 (Zbuffer、扫描线、Warnock) 对屏幕上每个象素进行判断,决定哪个多边形在该象素可见。 物体空间和图像空间的消隐算法 (画家算法) 在物体空间中预先计算面的可见性优先级,再在图像空间中生成消隐图。,2.7.2消除隐藏线,对造型的要求 在线框显示模型中,要求造型系统中有面的信息,最好有体的信息。 坐标变换 将视点变换到Z轴的正无穷大处,视线方向变为Z轴的负方向。 最基本的运算 判断面对线的遮挡关系.反复地进行线线、线面之间的求交运算,平面对直线段的遮挡判断算法,(1) 若线段的两端点及视点在给定平面的同侧,线段不被给定平面遮挡,转7
31、 (2) 若线段的投影与平面投影的包围盒无交,线段不被给定平面遮挡,转7 (3)求直线与相应无穷平面的交。若无交点,转4。否则,交点在线段内部或外部。若交点在线段内部,交点将线段分成两段,与视点同侧的一段不被遮挡,另一段在视点异侧,转4再判;若交点在线段外部,转4。 (4)求所剩线段的投影与平面边界投影的所有交点,并根据交点在原直线参数方程中的参数值求出Z值(即深度)。若无交点,转5。,(5) 以上所求得的各交点将线段的投影分成若干段,求出第一段中点。 (6) 若第一段中点在平面的投影内,则相应的段被遮挡,否则不被遮挡;其他段的遮挡关系可依次交替取值进行判断。 (7) 结束。视点与线段同侧 包
32、围盒不交 分段交替取值,直线与平面平行, 但在平面之后,前向面、后向面,为了提高算法的效率,需要设法减少求交的工作量。 若V N0,称该多边形为后向面。 若V N0,称该多边形为前向面。 后向面总是看不见的,不会由于后向面的遮挡,而使别的棱成为不可见的。因此计算时,可以把这些后向面全部去掉,这并不影响消隐结果。,前向面 后向面 多面体的隐藏线消除图3中的JEAF、HCBG和DEABC所在的面均为后向面。其它为前向面。,线消隐,基本数据结构面表(存放参与消隐的面) +线表(存放待显示的线) 算法假设E为面F的一条边, 需判别F以外每一个面与E的遮挡关系.,2.7.3消除隐藏面,画家算法(列表优先
33、算法) 先把屏幕置成背景色, 再把物体的各个面按其离视点的远近进行排序,排序结果存在一张深度优先级表中。 然后按照从远到近的顺序逐个绘制各个面。 关键是如何对场景中的物体按深度排序,对场景中的物体按深度排序,深度重叠测试.Zmin(P)Zmin(Q),若Zmax(P)Zmin(Q),则P肯定不能遮挡Q。 投影重叠判断 P和Q在oxy平面上投影的包围盒在x方向上不相交 P和Q在oxy平面上投影的包围盒在y方向上不相交,P和Q在oxy平面上的投影不相交 P在Q之后。P的各顶点均在Q的远离视点的一侧 Q在P之前。Q的各顶点均在P的靠近视点的一侧 精确的重叠测试 以上测试失败,须作进一步判断。计算时不
34、必具体求出重叠部分。在交点处进行深度比较,只要能判断出前后顺序即可。 若遇到多边形相交或循环重叠的情况(如图f),还必须在相交处分割多边形,然后进行判断。,P不遮挡Q的各种情况(ab,c,d,e) 及互相遮挡f,(b),Z缓冲区算法,帧缓存来存放每个象素的颜色值 初值取成z的极小值 深度缓存来存放每个象素的深度值。 初值可放对应背景颜色的值。,算法过程,在把显示对象的每个面上每一点的属性(颜色或灰度)值填入帧缓冲器相应单元前,要把这点的z坐标值和z缓冲器中相应单元的值进行比较。只有前者大于后者时才改变帧缓冲器的那一单元的值,同时z缓冲器中相应单元的值也要改成这点的z坐标值。 如果这点的z坐标值
35、小于z缓冲器中的值,则说明对应象素已经显示了对象上一个点的属性,该点要比考虑的点更接近观察点。 对显示对象的每个面上的每个点都做了上述处理后,便可得到消除了隐藏面的图。,Z-Buffer算法() 帧缓存全置为背景色深度缓存全置为最小Z值for(每一个多边形) 扫描转换该多边形for(该多边形所覆盖的每个象素(x,y) ) 计算该多边形在该象素的深度值Z(x,y);if(Z(x,y)大于Z缓存在(x,y)的值) 把Z(x,y)存入Z缓存中(x,y)处把多边形在(x,y)处的颜色值存入帧缓存的(x,y)处 ,Z-Buffer算法在象素级上以近物取代远物。形体在屏幕上的出现顺序是无关紧要的。 这种取
36、代方法实现起来远比总体排序灵活简单,有利于硬件实现。 缺点:占用空间大,没有利用图形的相关性与连续性。,只用一个深度缓存变量zb的改进算法。 一般认为,Z-Buffer算法需要开一个与图象大小相等的缓存数组ZB,实际上,可以改进算法,只用一个深度缓存变量zb。,算法过程,z-Buffer() 帧缓存全置为背景色for(屏幕上的每个象素(i,j) 深度缓存变量zb置最小值MinValuefor(多面体上的每个多边形Pk) if(象素点(i,j)在pk的投影多边形之内)计算Pk在(i,j)处的深度值depth;,if(depth大于zb) zb = depth;indexp = k;If(zb !
37、= MinValue) 计算多边形Pindexp在交点 (I,j) 处的光照颜色并显示 ,关键问题:判断象素点(i,j)是否在pk的投影多边形之内 计算多边形Pk在点(i,j)处的深度。设多边形Pk的平面方程为:,点与多边形的包含性检测,射线法由被测点P处向 y = - 方向作射线 交点个数是奇数,则被测点在多边形内部 否则,偶数,在多边形外部。 若射线正好经过多边形的顶点,则采用“左开右闭”的原则来实现。即:当射线与某条边的顶点相交时,若边在射线的左侧,交点有效,计数;若边在射线的右侧,交点无效,不计数。,如下情况又咋办?,弧长法(a)被测点p在多边形外 (b)被测点p在多边形内 以被测点为
38、圆心,作单位圆,计算其在单位园上弧长的代数和。 代数和为0,点在多边形外部; 代数和为2,点在多边形内部; 代数和为,点在多边形边上。,以顶点符号为基础的弧长累加方法。 将坐标原点移到被测点P。各象限内点的符号对分别为(,),(,),(,),(,)。 算法规定:若顶点pi的某个坐标为0,则其符号为。若顶点pi的x、y坐标都为0,则说明这个顶点为被测点,我们在这之前予以排除。于是弧长变化如下表。,表 :符号对变化与弧长变化的关系(sxi , syi) (sxi+! , syI+1) 弧长变化 象限变化 (+ +) (+ + ) 0 I I (+ +) (- + ) /2 I II (+ +) (
39、- - ) I III (+ +) (+ - ) -/2 I IV .,值得注意的是,当边的终点Pi+1在起点Pi的相对象限时,弧长变化可能增加或减少。设(xi,yi)和(xi1,yi1)分别为边的起点和终点坐标。计算若f0.则边穿过坐标原点。若f0,则弧长代数和增加,若f0,则弧长代数和减少,扫描线Z-buffer算法,算法思想: 在处理当前扫描线时,开一个一维数组作为当前扫描线的Z-buffer。首先找出与当前扫描线相关的多边形,以及每个多边形中相关的边对。 对每一个边对之间的小区间上的各象素,计算深度,并与Z-buffer中的值比较,找出各象素处可见平面。 计算颜色,写帧缓存。采用增量算
40、法计算深度。,数据结构 多边形Y表:将所有多边形存在多边形Y表中。根据多边形顶点中最小的y坐标,插入多边形Y表中的相应位置。多边形Y表中只保存多边形的序号和其顶点的最大y坐标。根据序号可以从定义多边形的数据结构中取多边形信息待消隐对象 多边形y表,活化多边形表APT:与当前扫描线相交的多边形。APT是一个动态的链表边Y表ET:活化多边形表中的每一个多边形都有一个边表ET多边形P1的边表ET,活化边对表AET 在一条扫描线上,同一多边形的相邻两条边构成一个边对。活化边表AET中存放当前多边形中与当前扫描线相交的各边对的信息。 xl xl ylmax xr xr yrmax zl IP za zb
41、,扫描线Z-buffer算法() 建多边形y表;对每一个多边形根据顶点最小的y值,将多边形置入多边形y表。活化多边形表APT,活化边表AET初始化为空。For(每条扫描线i,i从小到大) 1. 帧缓存CB置为背景色。2. 深度缓存ZB (一维数组) 置为无穷大。3. 将对应扫描线i的,多边形y表中的多边形加入到活化多边形表APT中。4. 对新加入的多边形,生成其相应的边Y表。5. 对APT中每一个多边形,若其边Y表中对应扫描线I增加了新的边,,将新的边配对,加到活化边对表AET中。6. 对AET中的每一对边:6.1 对xl x xr 的每一个象素,按增量公式z = z - za计算各点深度de
42、pth。6.2 与ZB中的量比较,depth ZB(I), 则令ZB(I) =depth,并计算颜色值, 写帧缓存。 7. 删除APT中,多边形顶点最大y坐标为I的多边形,并删除相应的边。8. 对AET中的每一个边对,作如下处理: 8.1 删除ylmax或ylmax 已等于I的边。若一边对中只删除了其中一边,需对该多边形的边重新配对。 8.2 用增量公式计算新的xl 、xl 和zl ,区间扫描线算法,基本思想: 它是把当前扫描线与各多边形在投影平面的投影的交点进行排序后,使扫描线分为若干子区间。只要在区间任一点处找出在该处z值最大的一个面,这个区间上的每一个象素就用这个面的颜色来显示。,两个平
43、面在屏幕上的投影 无贯穿的情形 相互贯穿的情形 如何确定小区间的颜色可分为三种情况: (1)小区间上没有任何多边形,如a4,a5,这时该小区间用背景色显示。 (2)小区间上只有一个多边形,如a1,a2a5,a6这时可以对应多边形在该处的颜色显示。,(3)小区间上存在两个或两个以上的多边,形如a6,a7,必须通过深度测试判断哪个多边形可见。 若允许物体表面相互贯穿时,还必须求出它们在扫描平面(ZX平面)的交点。用这些交点把该小区间分成更小的子区间(称为间隔),在这些间隔上决定哪个多边形可见。如将a2,a3区间分成a2,bb,a3两个子区间。 确定某间隔内哪一多边形可见: 可在间隔内任取一采样点(
44、如间隔中点),分析该点处哪个多边形离视点最近,该多边形即是在该间隔内可见的多边形。,区域子分割算法 (Warnack算法),基本思想: 把物体投影到全屏幕窗口上,然后递归分割窗口,直到窗口内目标足够简单,可以显示为止。区域子分的过程,算法步骤 该算法把初始窗口取作屏幕坐标系的矩形,将场景中的多边形投影到窗口内。 如果窗口内没有物体则按背景色显示; 若窗口内只有一个面,则把该面显示出来。 否则,窗口内含有两个以上的面,则把窗口等分成四个子窗口。对每个小窗口再做上述同样的处理。这样反复地进行下去。 如果到某个时刻,窗口仅有象素那么大,而窗口内仍有两个以上的面,这时不必再分割,只要取窗口内最近的可见
45、面的颜色或所有可见面的平均颜色作为该象素的值。,窗口与多边形的覆盖关系有四种:内含、相交包围和分离。如图所示。内含 多边形与窗口相交 包围 窗口和多边形分离,下列情况之一发生时,窗口足够简单,可以直接显示: 所有多边形均与窗口分离。该窗口置背景色 只有一个多边形与窗口相交,或该多边形包含窗口,则先整个窗口置背景色,在对多边形在窗口内部分扫描线算法绘制。 有一个多边形包围了窗口,或窗口与多个多边形相交,但有一个多边形包围窗口,而且在最前面最靠近观察点。,区域子分割算法流图,光线投射算法,基本思想: 考察由视点出发穿过观察屏幕的一象素而射入场景的一条射线,则可确定出场景中与该射线相交的物体。 在计
46、算出光线与物体表面的交点之后,离象素最近的交点的所在面片的颜色为该象素的颜色; 如果没有交点,说明没有多边形的投影覆盖此象素,用背景色显示它即可。,将通过屏幕各象素的投影线与场景中的物体表面求交,算法过程:,for屏幕上的每一象素 形成通过该屏幕象素(u,v)的射线;for 场景中的每个物体 将射线与该物体求交;if 存在交点以最近的交点所属的颜色显示象素(u,v)else以背景色显示象素(u,v) ,光线投射算法与Z缓冲器算法相比,它们仅仅是内外循环颠倒了一下顺序,所以它们的算法复杂度类似。 区别在于光线投射算法不需要Z缓冲器。 为了提高本算法的效率可以使用包围盒技术,空间分割技术以及物体的层次表示方法等来加速。,