ChapterTwo光栅图形学
作者:互联网
2光栅图形学
计算机图形学 光栅图形学笔记notion
光栅图形显示器可以看做一个像素的矩阵。在光栅显示器上显示的任何一种图形,实际上都是一些具有一种或多种颜色的像素集合。本章介绍光栅图形学中几个重要的概念及基相应算法。
-
图形的扫描转换或光栅化
确定最佳逼近图形的像素集合,并用指定属性写像素的过程称为图形的扫描转换或光栅化。
-
区域填充
对于一维图形,在不考虑线宽时,用一个像素宽的直、曲线来显示图形;二维图形的光栅化必须确定区域对应的像素集,并用指定的属性或图案显示,即区域填充。
-
裁剪
任何图形进行光栅化时,必须显示在屏幕的一个窗口里,超出窗口的图形不予显示。确定一个图形的哪些部分在窗口内,必须显示;哪些部分落在窗口之外,不该显示的过程称为裁剪。(裁剪通常在扫描转换之前进行,从而可以不必对那些不可见的图形进行扫描转换。)
-
消隐
当不透光的物体阻挡了来自某些物体部分的光线,使其无法到达观察者时,这些物体部分就是隐藏部分。隐藏部分是不可见的,如果不删除隐藏的线或面,就可能发生对图的错误理解。为了使计算机图形能够真实地反映这一现象,必须把隐藏的部分从图中删除,习惯上称做消除隐藏线和隐藏面,或简称为消隐
-
走样
对图形进行光栅化时,由于显示器的空间分辨率有限,对于非水平、垂直、士45°的直线,因像素逼近误差,使所画图形产生畸变(台阶、锯齿)的现象称之走样(aliasing)。用于减少或消除走样的技术称为反走样(antialiasing)。
提高显示器的空间分辨率可以减轻走样程度,但这是以提高设备成本为代价的。实际上,当显示器的像素可以用多亮度显示时,通过调整图形上各像素的亮度也可以减轻走样程度。
光栅图形学研究的主要内容
- 直线段的扫描转换算法
- 多边形的扫描转换与区域填充算法
- 裁剪算法
- 反走样算法
- 消隐算法
直线段的扫描转换算法
本节的算法仅适用于 ∣ k ∣ ⩽ 1 |k|\leqslant1 ∣k∣⩽1的情形。在这种情况下, x x x每增加 1 1 1, y y y最多增加 1 1 1。当 ∣ k ∣ > 1 |k|\gt1 ∣k∣>1时,必须把 x , y x,y x,y的地位互换, y y y每增加 1 1 1, x x x相应增加 1 k 1 \over k k1。 y y y与 k k k必须用浮点数表示,而且每一步都要对 y y y进行四舍五入后取整,这使得该算法不利于硬件实现。
有限的点逼近无线的点
求出过 P 0 P 1 P_0P_1 P0P1的直线段方程,像素的坐标都是整数,要进行取整处理
y = k x + b y=kx+b y=kx+b
k = y 1 − y 0 x 1 − x 0 ( x 1 ≠ x 0 ) k=\dfrac{y_1-y_0}{x_1-x_0}(x_1 {\not=}x_0) k=x1−x0y1−y0(x1=x0)
取消乘法提高效率?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLcXJsEa-1622816376826)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled.png)]
-
采用增量的思想 D D A \bold{DDA} DDA算法(数值微分法)
-
改进效率( △ x = 1 , △ x k = k \bigtriangleup{x}=1,\bigtriangleup{x}{k}=k △x=1,△xk=k)
y i + 1 = y i + k y_{i+1}=y_i+k yi+1=yi+k
—般情况下k与y都是小数,而且每一步运算都要对y进行四舍五入后取整。
唯一改进的途径是把浮点运算变成整数加法! -
从直线方程类型做文章
两点式,一般式 ⟹ \Longrightarrow ⟹中点画线法
void DDALine(int x0,int y0,int xi,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,x<=x1;x++) { drawpixel(x,int(y+0.5),color); y = y+k; } }
-
-
中点画线法
直线的一般式方程
F ( x , y ) = 0 F(x,y)=0 F(x,y)=0
A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0
其 中 , A = − ( △ y ) , B = ( △ x ) , C = − B ( △ x ) 其中,A=-(\bigtriangleup{y}),B=(\bigtriangleup{x}),C=-B(\bigtriangleup{x}) 其中,A=−(△y),B=(△x),C=−B(△x)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0REvrO4-1622816376836)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%201.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpYYdwDU-1622816376841)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%202.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2Hmhrry-1622816376847)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%203.png)]
如何判断Q在M的上方还是下方?
把M代入理想直线方程: F ( x m , y m ) = A x m + B y m + C F(x_m,y_m)=Ax_m+By_m+C F(xm,ym)=Axm+Bym+C
d i = F ( x m , y m ) = F ( x i + 1 , y i + 0.5 ) = A ( x i + 1 ) + B ( y i + 0.5 ) + C d_i=F(x_m,y_m)=F(x_i+1,y_i+0.5)=A(x_i+1)+B(y_i+0.5)+C di=F(xm,ym)=F(xi+1,yi+0.5)=A(xi+1)+B(yi+0.5)+C
中点画线法的基本原理
y = { y + 1 d<0 y d ⩾ 0 \red{y = \begin{cases} y+1 &\text{d<0} \\ y &\text{d}\geqslant0 \end{cases}} y={y+1yd<0d⩾0
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(x<x1) { if(d<0) {x++,y++,d += d2;} else {x++,d +=d1;} drawpixel(x,y,color); } }
-
∗ ∗ B r e s e n h a m **\bold{Bresenham} ∗∗Bresenham算法**
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMSu60hN-1622816376852)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%204.png)]
假设每次 x + 1 x+1 x+1, y y y的递增(减)量为 0 0 0或 1 1 1,它取决于实际直线最近光栅网格点的距离,这个距离的最大误差为 0.5 0.5 0.5。
d 0 = 0 , d = d + k d_0=0,d=d+k d0=0,d=d+k,一旦 d ⩾ 0 d\geqslant0 d⩾0,就让 d − 1 d-1 d−1,保证在0到1之间。
算法能否提高到整数加法?
DDA每一步做一次加法;中点画线每一步做一次整数加法。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dm7LMHYG-1622816376860)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%205.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VZdxcSUR-1622816376864)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%206.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5UKehtfA-1622816376868)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%207.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7JsdRm0-1622816376875)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%208.png)]
void Bresenham(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; x = x0; y = y0; for (int i = 0; i <= dx; i++) { drawpixel(x, y, color); // console.warn(x, y); x = x + 1; e = e + k; if (e >= 0) { y++; e = e - 1; } } }
上述算法在计算直线斜率和误差项时用到了小数与除法,可以改用整数以避免除法。由于算法中只用到误差项的符号,因此可做替换: e ′ = 2 ∗ e ∗ d x e'=2*e*dx e′=2∗e∗dx
void IntegerBresenhamLine(int x0, int y0, int x1, int y1, int color) { int x,y,dx,dy,e; dx = x1 -x0; dy = y1 - y0; e = -dx; x = x0; y = y0; for (int i = 0; i <= dx; i++) { drawpixel(x,y,color); x++, e = e + 2 * dy; if(e >= 0) { y++; e = e-2 * dx; } } }
-
中点画圆法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cyKYgbJ1-1622816376878)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/qq_pic_merged_1622815920310.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZALr0tPm-1622816376885)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/qq_pic_merged_1622815938960.jpg)]
显示圆弧上8个对称点的算法如下: void CirPoints(int x,int y,int color) { drawpixel(x,y,color);drawpixel(y,x,color); drawpixel(-x,y,color);drawpixel(y,-x,color); drawpixel(x,-y,color);drawpixel(-y,x,color); drawpixel(-x,-y,color);drawpixel(-y,-x,color); }
MidPointCircle(int r,int color)
{
inx x,y;
float d;
x=;y=r;d=1.25-r;
circliepoints(x,y,color);
while(x<=y)
{
if(d<0) d += 2*x+3;
else
{
d += 2*(x-y)+5;y--;
}
x++;
circlepoints(x,y,color);
}
}
多边形的扫描转换
多边形
表示方法:顶点表示、点阵表示
分类:凸、凹、含内环
-
X-扫描线算法
基本思想是按扫描线顺序计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的像素,即完成填充工作
算法的核心是按X递增顺序排列交点的X坐标序列。由此,可得到X-扫描线算法步骤如下:
-
确定多边形所占有的最大扫描线数,得到多边形顶点的最小和最大y值( y m i n y_{min} ymin和 y m a x y_{max} ymax)
-
从 y = y m i n y=y_{min} y=ymin到 y = y m a x y=y_{max} y=ymax每次用一条扫描线进行填充
-
对一条扫描线的填充过程可分为四个步骤:
a.求交:计算扫描线与多边形各边的交点
b.排序:把所有焦点按递增顺序进行排序
c.交点配对:第一个与第二个;第三个与第四个
d.区间填色:把这些相交区间的像素置成不同于背景色的填充色
当扫描线与多边形顶点相交时,交点的取舍问题(交点的个数应保证为偶数个)
解决方案:
(1) 若共享顶点的两条边分别落在扫描线的两边,交点只算一个
(2) 若共享顶点的两条边在扫描线的同一边,这时交点作为零个或两个检查共享顶点的两条边的另外两个端点的 y y y值,按这两个 y y y值中大于交点y值的个数来决定交点数
关键问题在于求交
-
-
扫描线算法的改进
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cM0ygfRY-1622816376890)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%209.png)]
从三方面加以改进:
-
在处理一 条扫描线时,仅对与它相交的多边形的边(有效边)进行求交运算
-
考虑扫描线的连贯性
即当前扫描线与各边的交点顺序与下一条扫描线与各边的交点顺序很可能相同或非常相似
-
多边形的连贯性
即当某条边与当前扫描线相交时,它很可能也与下一条扫描线相交
避免求交运算→引入特殊的数据结构
-
AET,活性边表
把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点 x x x坐标递增的顺序存放在一个链表中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2xiyiQqZ-1622816376892)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2010.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXU40xWs-1622816376895)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2011.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMt4XacM-1622816376897)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2012.png)]
-
新边表(方便活性边表的建立与更新)
首先构造一个纵向链表,链表的长度为多边形所占有的最大扫描线数,链表的每个结点,称为一个吊桶,对应多边形覆盖的每一条扫描线;AET挂在该扫描线第一次出现的边
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MnO8E81-1622816376899)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2013.png)]
x m i n \red{x_{min}} xmin是较低点的坐标值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S034CKHB-1622816376901)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2014.png)]
每做一次新的扫描线时,要对已有的边进行三个处理
- 是否被去除掉
- 如果不被去除,第二就要对它的数据进行更新。所
谓更新数据就是要更新它的 x x x值,即: x + 1 k x+{1\over{k}} x+k1 - 看有没有新的边进来,新的边在NET里,可以插入排序插
进来。
这个算法过程从来没有求交,这套数据结构使得你不用求交
点!避免了求交运算。扫描线算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5BXFP71n-1622816376903)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2015.png)]
多边形扫描转换算法小结
扫描线法可以实现已知任意多边形域边界的填充。该填充算法是按扫描线的顺序,计算扫描线与待填充区域的相交区间,再用要求的颜色显示这些区间的像素,即完成填充工作
为了提高算法效率:(1)增量的思想
(2)连贯性思想
(3)构建了一套特殊的数据结构缺点:无法实现对未知边界的区域填充
-
-
边缘填充算法
其基本思想是按任意顺序处理多边形的每条边。在处理每条边时,首先求出该边与扫描线的交点,然后将每条扫描线上交点右方的所有像素取补。多边形的所有边处理完毕之后,填充即完成。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RcHi0XtI-1622816376908)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2016.png)]
缺点:每一像素点可能访问多次→栅栏填充
-
栅栏填充算法
栅栏指的是一条过多边形顶点且与扫描线垂直的直线。它
把多边形分为两半。在处理每条边与扫描线的交点时,将
交点与栅栏之间的像素取补 -
边界标志算法
帧缓冲器中对多边形的每条边进行直线扫描转换,亦即对多边形边界所经过的象素打上标志然后再采用和扫描线算法类似的方法将位于多边形内的各个区段着上所需颜色由于边界标志算法不必建立维护边表以及对它进行排序,所以边界标志算法更适合硬件实现,这时它的执行速度比有序边表算法快一至两个数量级。
区域填充算法
区域:已经表示成点阵形式的填充图形,它是像素的集合。
可采用,内点表示(区域内的所有像素着同一颜色)和边界表示(边界点着同一颜色)。
区域填充:区域的一点赋予指定颜色,然后扩展到整个区域的过程。
要求:区域是连通的
-
四连通区域
通过4个方向(上,下,左,右)到达区域内的任意像素
-
八连通区域
通过8个方向(上,下,左,右,左上,左下,右上,右下)到达区域内的任意像素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rq7N7ivA-1622816376912)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2017.png)]
-
区域填充的递归算法
种子填充算法:已知多边形内一点,利用连通性找到区域内的所有像素点
-
内点表示的四连通区域的递归填充算法
//内点表示的四连通区域的递归填充 void FloodFill4(int x, int y, int oldColor, int newColor) { if(getPixel(x, y) == oldColor) { drawpixel(x, y, newColor); FloodFill4(x, y + 1, oldColor, newColor); FloodFill4(x, y - 1, oldColor, newColor); FloodFill4(x - 1, y, oldColor, newColor); FloodFill4(x + 1, y, oldColor, newColor); } }
-
边界表示的四连通区域的递归填充算法
//边界点表示的四连通区域的递归填充 void BoundaryFill4(int x, int y, int boundaryColor, int newColor) { int color = getPixel(x, y); if(color != newColor && color != boundaryColor) { drawpixel(x, y, newColor); BoundaryFill4(x, y + 1, boundaryColor, newColor); BoundaryFill4(x, y - 1, boundaryColor, newColor); BoundaryFill4(x - 1, y, boundaryColor, newColor); BoundaryFill4(x + 1, y, boundaryColor, newColor); } }
种子填充算法的不足之处
(1) 有些像素会入栈多次,降低算法效率;栈结构占空间
(2)递归执行,算法简单,但效率不高。区域内每一像素都引进一次递归,进/出栈,费时费内存
(3) 改进算法,减少递归次数,提高效率 -
-
区域填充的扫描线算法
//内点表示的区域填充扫描线算法 function ScanLineFill4(x, y, oldColor, newColor) { function scan(x, y, oldColor, newColor, d) { let xl, xr; let spanNeedFill;//定义为布尔类型 let pt =newSeed(); let stack = []; pt.x = x; pt.y = y; // console.log(pt.x,pt.y); stack.push(pt);//将前面生成的区段压入堆栈 function dealLine() { while(x <= xr) { spanNeedFill =false; while(arr_rgb(getPixel(x, y)) === oldColor) { spanNeedFill =true; x++; } if(spanNeedFill) { pt.x = x - 1; pt.y = y; stack.push(pt); spanNeedFill =false; } while((arr_rgb(getPixel(x, y)) !== oldColor) && (x <= xr)) { x++; } }//End of while(i <= xr) } while(stack.length !== 0) { pt = stack.pop(); y = pt.y; x = pt.x; while(arr_rgb(getPixel(x, y)) === oldColor) {//向右填充 setPixel(x, y, newColor); x++; } xr = x - 1; x = pt.x - 1; while(arr_rgb(getPixel(x, y)) === oldColor) {//向左填充 setPixel(x, y, newColor); x--; } xl = x + 1; //处理上面一条扫描线 x = xl; y = y + d; dealLine(); //处理下面一条扫描线,代码与处理上面一条扫描线类似 x = xl; y = y - 2; dealLine(); }//End of while(stack.length != 0) } scan(x, y, oldColor, newColor, -1); scan(x, y + 1, oldColor, newColor, 1); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnAUnNlc-1622816376916)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2018.png)]
字符
数字、字母、汉字等符号
- 点阵字符:每个字符由一个位图表示,字位为1表示经过(置为字符颜色),0表示不经过(置为背景色)
- 矢量字符
字符属性
-
字体
-
字高
-
字宽因子
-
字倾斜角
-
对齐
-
字色
-
写方式
裁剪
-
点的裁剪
最简单的裁剪算法是把各种图形扫描转换为点之后,再判断点是否在窗口内
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cNuXV160-1622816376920)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2019.png)]
点的裁剪
对于任意一点 P ( x , y ) P(x,y) P(x,y)若满足下列两对不等式:
{ x l e f t ≥ x ≥ x r i g h t y b o t t o m ≥ y ≥ y t o p \begin{cases} x_{left}\ge{x}\ge{x_{right}} \\ y_{bottom}\ge{y}\ge{y_{top}} \end{cases} {xleft≥x≥xrightybottom≥y≥ytop
则点 P P P在矩形窗口内;否则,点 P P P在矩形窗口外
判断每个点是否在窗口内,太费事,一般不可取 ⟹ \implies ⟹采用直线段的裁剪,因为直线是构成图形的基本要素
-
直线段的裁剪
直线段裁剪算法复杂图形裁剪的基础
直线段和剪裁窗口的可能关系:
- 完全落在窗口内
- 完全落在窗口外
- 与窗口边界相交
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GFJ0GLi-1622816376926)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2020.png)]
是否完全落在裁剪窗口内?
是否完全落在裁剪窗口外?
如果皆否,计算它与一个或多个裁剪边界的交点
常用的裁剪算法:(只能用于矩形窗口)
-
∗ ∗ C o h e n − S u t h e r l a n ∗ ∗ **\bold{Cohen-Sutherlan}** ∗∗Cohen−Sutherlan∗∗
又称编码裁剪算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-quPQQWa5-1622816376930)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2021.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BBkhXNW-1622816376935)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2022.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H73fl9aB-1622816376938)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2023.png)]
每条线段的端点都赋以四位二进制码 D 3 D 2 D 1 D 0 D_3D_2D_1D_0 D3D2D1D0。编码规则如下:
- 若 x < x l e f t x<x_{left} x<xleft,则 D 0 = 1 D_0=1 D0=1,否则, D 0 = 0 D_0=0 D0=0
- 若 x > x r i g h t x>x_{right} x>xright,则 D 1 = 1 D_1=1 D1=1,否则, D 1 = 0 D_1=0 D1=0
- 若 y < y b o t t o m y<y_{bottom} y<ybottom,则 D 2 = 1 D_2=1 D2=1,否则, D 2 = 0 D_2=0 D2=0
- 若 y > y t o p y>y_{top} y>ytop,则 D 3 = 1 D_3=1 D3=1,否则, D 3 = 0 D_3=0 D3=0
窗口及其延长线所构成了9个区域。根据该编码规则:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32k5aoep-1622816376942)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2024.png)]
- D 0 D_0 D0对应窗口左边界
- D 1 D_1 D1对应窗口右边界
- D 2 D_2 D2对应窗口下边界
- D 3 D_3 D3对应窗口上边界
计算端点 P 1 P_1 P1 P 2 P_2 P2的编码 c o d e 1 code_1 code1和 c o d e 2 code_2 code2,然后进行二进制与和二进制或
- c o d e 1 ∣ c o d e 2 = 0 code_1|code_2=0 code1∣code2=0,简取之
- c o d e 1 & c o d e 2 ≠ 0 code_1\&code_2\not=0 code1&code2=0,简弃之
- 若都不成立,则需求出直线段与窗口边界的交点,在交点处把线段一分为二,对剩余两段继续判断1.2.
适合:大部分线段完全可见,大部分线段完全不可见
-
中点分割法
中点分割算法的核心思想是通过二分逼近来确定直线段与窗口的交点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61plUjdn-1622816376946)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2025.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZHitAboi-1622816376949)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2026.png)]
会无限循环二分下去吗?
-
∗ ∗ L i a n g − B a r s k y **\bold{Liang-Barsky} ∗∗Liang−Barsky裁剪算法**
梁友栋裁剪算法,主要思想:
-
用参数方程表示一条线段( 0 ≤ u ≤ 1 0\le{u}\le{1} 0≤u≤1)
y = y 1 + u ( y 2 − y 1 ) = y 1 + △ y ∗ u y=y_1+u(y_2-y_1)=y_1+\bigtriangleup{y}*u y=y1+u(y2−y1)=y1+△y∗u
x = x 1 + u ( x 2 − x 1 ) = x 1 + △ x ∗ u x=x_1+u(x_2-x_1)=x_1+\bigtriangleup{x}*u x=x1+u(x2−x1)=x1+△x∗u
-
把直线段看成是有方向的线段
把窗口的四条边及其延长线分成两类:入边和出边
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OfU44vNL-1622816376953)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2027.png)]
入边∶直线由窗口外向窗口内移动时和窗口边界相交的边(左边界和下边界)
出边∶直线由窗口内向窗口外移动时和窗口边界相交的边(右边界和上边界)
入边有2个交点,出边也有2个交点。再加上直线段的两个端点,一共6个。
如何求出裁剪后线段的起点和终点坐标?即起点和终点的参数值 u u u[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AThfcAUH-1622816376960)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2028.png)]
梁 先 生 的 重 大 发 现 : u 1 = m a x ( 0 , u l , u b ) , u 2 = m i n ( 1 , u t , u r ) \bold{梁先生的重大发现:\red{u_1=max(0,u_l,u_b),u_2=min(1,u_t,u_r)}} 梁先生的重大发现:u1=max(0,ul,ub),u2=min(1,ut,ur)
裁剪问题转换为不等式问题
{ x l e f t ≤ x 1 + △ x ⋅ u ≤ x r i g h t y b o t t o m ≤ y 1 + △ y ⋅ u ≤ y t o p \begin{cases} x_{left}\le{x_1+\bigtriangleup{x}\cdot{u}}\le{x_{right}} \\ y_{bottom}\le{y_1+\bigtriangleup{y}\cdot{u}}\le{y_{top}} \end{cases} {xleft≤x1+△x⋅u≤xrightybottom≤y1+△y⋅u≤ytop
u ⋅ ( − △ x ) ≤ x 1 − x l e f t u\cdot(-\triangle{x})\le{x_1-x_{left}} u⋅(−△x)≤x1−xleft
u ⋅ △ x ≤ x r i g h t − x 1 u\cdot\triangle{x}\le{x_{right}-x_1} u⋅△x≤xright−x1
u ⋅ ( − △ y ) ≤ y 1 − y b o t t o m u\cdot(-\triangle{y})\le{y_1-y_{bottom}} u⋅(−△y)≤y1−ybottom
u ⋅ △ y ≤ y t o p − y 1 u\cdot\triangle{y}\le{y_{top}-y_1} u⋅△y≤ytop−y1p 1 = − △ x , q 1 = x 1 − x l e f t p_1=-\triangle{x},q_1=x_1-x_{left} p1=−△x,q1=x1−xleft
p 2 = △ x , q 2 = x r i g h t − x 1 p_2=\triangle{x},q_2=x_{right}-x_1 p2=△x,q2=xright−x1
p 3 = − △ y , q 3 = y 1 − y b o t t o m p_3=-\triangle{y},q_3=y_1-y_{bottom} p3=−△y,q3=y1−ybottom
p 4 = △ y , q 4 = y t o p − y 1 p_4=\triangle{y},q_4=y_{top}-y_1 p4=△y,q4=ytop−y1⟹ \implies ⟹ u ⋅ p k ≤ q k , 其 中 k = 1 , 2 , 3 , 4 , 对 应 于 左 、 右 、 下 、 上 边 界 \bold{u\cdot{p_k}\le{q_k}},其中k=\red{1,2,3,4},对应于\red{左、右、下、上}边界 u⋅pk≤qk,其中k=1,2,3,4,对应于左、右、下、上边界
如果这个不等式取等号,代表 u ⋅ p k = q k , u = q k p k u\cdot{p_k}=q_k,u={q_k\over{p_k}} u⋅pk=qk,u=pkqk
u 分 别 对 应 直 线 和 窗 口 四 条 边 交 点 处 的 参 数 u分别对应直线和窗口四条边\red{交点}处的\red{参数} u分别对应直线和窗口四条边交点处的参数[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tmoYuYrl-1622816376964)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2029.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2RIRuXsA-1622816376968)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2030.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K8T4TtVy-1622816376979)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2031.png)]
-
例题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-auWTaq5E-1622816376985)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2032.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lttlzeFF-1622816376990)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2033.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CSyVsvhp-1622816376993)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2034.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h0zs8GsC-1622816376998)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2035.png)]
小结
- 直线方程参数化
- 直线段看成有方向的
- 把窗口的四条边分成入边和出边
-
-
反走样
在光栅显示器上显示图形时,直线段或图形边界或多或少会呈现锯齿状,原因时图形信号时连续的,而在光栅显示系统,用来表示图形的基本单位却是一个个离散的像素。这种用离散量来表示连续两引起的失真现象称为走样。
反走样方法
-
采用分辨率更高的显示设备
-
非加权区域采样
根据物体的覆盖率(coverage) 计算像素的颜色。覆盖率是指某个像素区域被物体覆盖的比例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYZhLzFm-1622816377000)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2036.png)]
非加权区域采样方法有两个缺点:
- 象素的亮度与相交区域的面积成正比,而与相交区域落在象素内的位置无关,这仍然会导致锯齿效应
- 直线条上沿理想直线方向的相邻两个象素有时会有较大的灰度差
-
加权区域采样
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yHolsWCd-1622816377002)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2037.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jFjuMBn6-1622816377006)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2038.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wIVeuuq-1622816377009)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2039.png)]
然后求出所有中心落于直线段内的子象素。
最后计算所有这些子象素对原象素亮度贡献之和
消隐
由于投影变换失去了深度信息,往往导致图形的二义性。要消除这种二义性,就必须在绘制时消除被遮挡的不可见的线或面,习惯上称之为消除隐藏线和隐藏面,或简称为消隐
消隐与消隐对象和观察者的位置有关。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SuFE10VS-1622816377012)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2040.png)]
消隐的分类
- 按消隐对象分类
- 线消隐
- 面消隐
- 按消隐空间分类
-
物体空间的消隐算法(线框图的消隐)
光线投射算法、 R o b e r t s \bold{Roberts} Roberts算法
光线投射是求光线与场景的交点,该光线就是所谓的视线(
如视点与像素连成的线)Roberts算法基本步骤:
- 逐个的独立考虑每个物体自身,找出为其自身所遮挡的边和面(自消隐)
- 将每一物体上留下的边再与其它物体逐个的进行比较,以确定是完全可见还是部分或全部遮挡(两两物体消隐);
- 确定由于物体之间的相互贯穿等原因,是否要形成新的显示边等,从而使被显示各物体更接近现实
-
图像空间的消隐算法(围绕屏幕,主流)
以屏幕窗口内的每个像素为处理单元。确定在每一个像素处,场景中的k个物体哪一个距离观察点最近,从而用它的颜色来显示该像素
∗ ∗ Z − B u f f e r **\bold{Z-Buffer} ∗∗Z−Buffer算法、扫描线算法和 W a r n o c k \bold{Warnock} Warnock算法**
-
物体空间和图像空间的消隐算法
在物体空间中预先计算面的可见性优先级,再在图像空间中生成消隐图,如画家算法
**画家算法缺点:**只能处理互不相交的面
-
消除隐藏线
- 对造型的要求
- 坐标变换
- 最基本的运算
- 线消隐算法
消除隐藏面
图像空间的消隐算法
-
画家算法
由远及近地绘制各个面,就相当于画家算法。需要建立深度优先级表。只能处理互不相交的面。
画家算法地深度排序计算量大,而且排序后还需要再检查相邻地面,以确保再深度优先级表中前者在前,后者在后。若遇到多边形相交或多边形循环重叠地情形,还必须分割多边形。为了避免这些复杂地运算 ⟹ \implies ⟹ Z Z Z缓冲区算法
-
Z − B u f f e r \bold{Z-Buffer} Z−Buffer算法
需要有帧缓冲存放每个像素点的颜色值;深度缓存来存放每个像素的深度值。
**优点:**在像素级上以近物取代远物,灵活简单,有利于硬件实现。
**缺点:**占用空间大,没有利用图形的相关性和连续性。
一般认为, Z − B u f f e r Z-Buffer Z−Buffer需要开一个与图像大小相等的缓存数组 Z B ZB ZB,但通过改进,可以只用一个深度缓存变量 z b zb zb。(但仍没有考虑相关性与连续性)
-
PPT
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DhPepuJW-1622816377016)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2041.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8ri1sVw-1622816377018)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2042.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xl25tlwE-1622816377020)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2043.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ELoPzdmb-1622816377022)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2044.png)]
改进算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kEqWbX9N-1622816377026)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2045.png)]
判断点与多边形关系(包含性检测):
-
1)射线法
由被测点P处向y = - oo方向作射线,交点个数是奇数,则被测点在多边形内部;交点个数是偶数,表示在多边形外部
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80LuuqL7-1622816377028)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2046.png)]
若射线正好经过多边形的顶点,则采用“左开右闭”的原则来实现。即:当射线与某条边的顶点相交时,若边在射线的左侧,交点有效,计数;若边在射线的右侧,交点无效,不计数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rY1Ap2xN-1622816377030)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2047.png)]
缺点:计算量大;不稳定
-
2)弧长法
要求多边形时有向多边形。以被测点为圆心作单位圆,将全部有向边向单位圆作径向投影,并计算其在单位圆上的弧长的代数和。(规定逆时针为正,顺时针为负)
- 代数和为 0 0 0,点在多边形外部;
- 代数和为 2 π 2π 2π,点在多边形内部;
- 代数和为 π π π,点在多边形边上;
优点:稳定性高,计算误差对最后的判断没有多大影响
但这个算法效率也不高,问题是算弧长并不容易,因此又派生出一个新的方法─以顶点符号为基础的弧长累加方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZZhRQIYv-1622816377032)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2048.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUvQmzKo-1622816377035)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2049.png)]
同一个象限认为是 0 \red 0 0,跨过一个象限是 π / 2 \red{π/2} π/2,跨过两个象限是 π \red π π。这样当要计算代数和的时候,就不要去投影了,只要根据点所在的象限一下子就判断出多少度,这样
几乎没有什么计算量,只有一些简单的判断,效率非常高
值得注意的是,当边的终点 P i + 1 P_{i+1} Pi+1在起点 P i P_i Pi的相对象限时,弧长变化可能增加或减少 π \red π π。设 ( x i , y i ) (x_i,y_i) (xi,yi)和 ( x i + 1 , y i + 1 ) (x_{i+1},y_{i+1}) (xi+1,yi+1)分别为边的起点和终点的坐标。
计算 f = y i + 1 x i − x i + 1 y i f=y_{i+1}x_i-x_{i+1}y_i f=yi+1xi−xi+1yi:
若 f = 0 f=0 f=0,则边穿过坐标原点
若 f > 0 f>0 f>0,则弧长代数和增加 π π π
若 f = 0 f=0 f=0,则弧长代数和减少 π π π
设多边形 P k P_k Pk的平面方程为 a x + b y + c z + d = 0 ax+by+cz+d=0 ax+by+cz+d=0
若 c ≠ 0 c\not=0 c=0,则把 ( i , j ) (i,j) (i,j)代入方程,就可得深度值 d e p t h = − a i + b j + d c depth=-{{ai+bj+d}\over{c}} depth=−cai+bj+d
若 c = 0 c=0 c=0,则说明多边形 P k P_k Pk的法向与 z z z轴垂直,在 x o y xoy xoy面上的投影为一条直线,在 Z − B u f f e r Z-Buffer Z−Buffer 消隐算法中可以不考虑这种多边形
-
-
区间扫描算法(消隐算法中最快的)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HWU4UOTn-1622816377037)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2050.png)]
像素计算改为逐段计算
如何实现这个算法?
首先要有投影多边形,然后去求交点,然后交点进行排序
- 小区间上没有任何多边形,用背景色显示
- 小区间上只有一个多边形,显示该多边形的颜色
- 小区间上存在两个及以上多边形,必须通过深度测试判断哪个多边形可见
利用增量算法简化求交
排序的结果就分成了一个个区间,然后在每个区间找当中的一个像素(i,j),在( i,j)处计算每个相关面的z值,对相关深度值z进行比较,其中最大的一个就表示是可见的。整个这段区间就画这个z值最大面的颜色
-
Warnock消隐算法(区域子分割算法)
经典,分而治之,利用了堆栈的数据结构
把物体投影到全屏幕窗口上,然后递归分割窗口,直到窗口内目标足够简单,可以显示为止什么是足够简单:
-
窗口仅包含一个多边形
-
窗口与多边形相交,且窗口内无其他多边形
-
窗口为一个多边形所包围
-
窗口与一个多边形分离
-
如何判断?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u1Ty4TNW-1622816377039)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2051.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dvriY33C-1622816377041)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2052.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLHgOr2X-1622816377043)(2%E5%85%89%E6%A0%85%E5%9B%BE%E5%BD%A2%E5%AD%A6%20159e45ea112842e98ce1ad494d7a0088/Untitled%2053.png)]
窗口有多个多边形投影面,如何显示?
算法步骤:
- 如果窗口内没有物体则按背景色显示
- 若窗口内只有一个面,则把该面显示出来
- 否则,窗口内含有两个以上的面,则把窗口等分成四个子窗口。对每个小窗口再做上述同样的处理。这样反复地进行下去
-
标签:E5%,图形学,E6%,85%,ChapterTwo,BE%,光栅,防盗链,图片 来源: https://blog.csdn.net/Leesnwen/article/details/117574271