计算机图形学复习4

计算机图形学复习0
计算机图形学复习1
计算机图形学复习2
计算机图形学复习3
上次更新到填充算法,具体还有几个题没给出结果。
1.若用扫描线填充法将顶点为P0,P1,P2,P3,P4,P5,P6的多边形填充,如图。请写出其边分类表ET及y=8时的活化链表。在这里插入图片描述
2.按左上右下的顺序,用简单种子四向填充算法(出栈时填充颜色),分析当S1为种子时,图2区域的填充过程。
在这里插入图片描述
上面这两个题,我发现一些错误,之前没有上传答案,我进行了一个讲解,录制的视频上传到了bili:
这里查看讲解
这次更新主要讲述图形的裁剪算法。

裁剪算法

二维图形的裁剪包括以下内容:
在这里插入图片描述
什么是裁剪呢?就像拍照一样,你把眼中的景色裁剪到相机的小框框里。
基本的术语概念:
窗口(Clipping Window):需要显示的场景区域;
视区(Viewport):指显示设备上用来显示图形的区域,在设备(屏幕)坐标系内定义, 是所看到景的范围
裁剪(Clipping):从场景中确定位于窗口内的图形。
在这里插入图片描述
就是屏幕范围有限,需要进行图形处理:
在这里插入图片描述

裁剪的意义:
为了描述图形对象,我们必须存储它的全部信息,但有时为了达到分区描述或重点描述某一部分的目的,往往将要描述的部分置于一个窗口内,而将窗口外的部分“剪掉”,这个处理过程叫做裁剪,裁剪在计算机图形处理中具有十分重要的意义。
裁剪就是将指定窗口作为图形边界,将窗口内的图形保留,而窗口外的图形则被舍弃

裁剪处理过程
    1、图元在窗口内外的判别; 
    2、图形元素与窗口的求交。

点的裁剪

点就是判断在不在窗口范围内就欧克了。
窗口:y=yt,y=yb,x=xl,x=xr(四四方方的一个窗口)
点P(x,y)
判断点是否在窗口内的方法
在这里插入图片描述

直线裁剪

本次内容主要介绍直线的裁剪。

Cohen-Sutherland裁剪算法(编码裁剪)

对于一条直线,可能出现在窗口的情况如下:
在这里插入图片描述
对于每条线段算法分成三种情况处理:
第一种:若线段完全在窗口内,则显示该线段称“完全可见”,需要“取”之; 如AB
第二种:若明显在窗口外,称“完全不可见”.则丢弃该线段。如EF
第三种:若线段不满足“取”或 “弃”的条件,则在交点处把线段分为两段. 其中一段完全在窗口外,可弃之. 然后对另一段重复上述处理。如CD

也就是说只要能判断直线与窗口的位置关系,就能进行处理。
编码算法的原理是将窗口所在分为9个区域,对区域进行编码:
由窗口四条边所在直线把二维平面分成9个区域,每个区域赋予一个四位编码,CtCbCrCl,上下左右
在这里插入图片描述

在这里插入图片描述
比如:给出一条线段AB的端点编码。
A:1001,B:0010
在这里插入图片描述
若P1P2完全在窗口内, code1=0,且code2=0,则“取”;
若P1P2明显在窗口外code1&code2≠0,则“弃” ;
在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。
对于有的线段,部分在窗口内的线段需要求交(如,线段CD)
求交前先测试与窗口哪条边所在直线有交?
规则:判断端点编码中各位的值CtCbCrCl
如:CD,C:0000 D:1000
Ct位等于1,与上边相交

分别对应:上、下、右和左边
端点码位值等于1,说明线段与对应窗口边相交
次序:上、下、右和左边
以交点为界,丢弃外侧线段,
     以交点为新端点判断另一线段,
     重复上述过程

下面举例一下就明白了:
在这里插入图片描述

AB:与窗口左边相交,求交点H,  
    AH和BH显然不可见

EF:与窗口上边交点I,弃EI
   与窗口下边交点K,弃KF
   与窗口右边交点J,弃KJ
   保留IJ

CD:与窗口上边交点L, 弃CL
    与窗口下边交点O, 弃OD
    与窗口右边交点M, 弃LM
    与窗口左边交点N, 弃NO
    保留MN

最多求交次数为4
Cohen—SutherLand直线裁剪算法 
直线和窗口的关系可以分为如下三类: 
 1) 整条直线在窗口之内,此时,不需裁剪,显现整条直线。
 2) 整条直线在窗口之外,此时,不需裁剪,不显现整条直线。 
 3) 局部直线在窗口之内,局部直线在窗口之外,此时,必要求出直线与窗框之交点,并将窗口外的直线局部剪裁掉,显现窗口内的局部。 

如何对其进行实现:
编码 + 判断 + 求交


int encode(float x, float y)  //编码 #点在窗口如何编码
{
    int c=0;
    if (x<XL)  c=1 ;
    else if (x>XR)  c=2 ;
    if (y<YB)  c=c+4 ;
    else if (y>YT)  c=c+8 ;
    return c ;
}
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
encode(float x, float y,int *code)  //编码
{
    int c=0;
    if (x<XL)  c=c|LEFT ;
    else if (x>XR)  c=c|RIGHT ;
    if (y<YB)  c=c|BOTTOM ;
    else if (y>YT)  c=c|TOP ;
    *code = c;
    return;
}
C_S_Line_Clip(x1,y1,x2,y2,XL,XR,YB,YT)
{	
   int code1,code2,code;
   encode(x1,y1,&code1);   //(x1,y1)编码
   encode(x2,y2,&code2); //(x2,y2)编码
   while(code1<>0||code2<>0) //当线段完全可见,则结束
   {   if(code1&code2<>0)  return; //线段在窗口外,弃之
        code = code1;  //从(x1,y1)点开始
        if(code1==0) code= code2;  //从(x2,y2)开始
        //线段与窗口边求交计算代码 
        {//计算线段P1(x1,y1)P2(x2,y2)与窗口边界的交点if(LEFT&code !=0)  //
    {x=XL; y=y1+(y2-y1)*(XL-x1)/(x2-x1);}
else if(RIGHT&code !=0)
          {x=XR; y=y1+(y2-y1)*(XR-x1)/(x2-x1);}
        else if(BOTTOM&code !=0)
                    {y=YB; x=x1+(x2-x1)*(YB-y1)/(y2-y1);}
                else if(TOP & code !=0)
                     {y=YT; x=x1+(x2-x1)*(YT-y1)/(y2-y1);}

}
        if (code==code1){x1=x;y1=y;encode(x,y,code1)}
        else{x2=x;y2=y;encode(x,y,code2)} //交点(x,y) }
    Displayline(x1,y1,x2,y2); //最终裁剪后的可见线段
    return;
}

算法的优点:

1) 将不需剪裁的直线舍弃。法则是:若是一条直线的两头在同一区域,则该直线不需裁剪,
不然,该直线为可能要剪裁的直线。 
2) 对可能要剪裁的直线缩小了与之求交的边框范畴。法则是:若是直线的一个端点在上(下、左、右)域,
则此直线与上边框求交,然后移除上边框以上的局部。该法则对直线的另一端点也实用。

算法的缺点:

1) 虽然将不需剪裁的直线舍弃。但仍有一些在窗口外的直线不能被判断出来。 
2) 有一些直线不需要4次求交运算。 

算法的不足:
在这里插入图片描述
第一,当code1&code2≠0,能判断出直线段显然在窗口之外. 然而这个条件。并没有包含所有的在窗口之外的直线段,比如: code1=0001,code2=0100,如图 中直线段P3P4,此时, code1&code2=0,但直线段也是完全在窗口之外.这就意味着这类型的直线必须计算与窗口的边线求交,其实是一种无意义操作;
第二,在第三种情种下,当code 码中同时有两位不等于0 时,求交运算的次数多达四次. 如图2中直线P1P2 与窗口的四条边的交点分别为A、B、C、D。而实际上,直线只与窗口的两条边相交,另外两个交点发生在边的延长线上。

中点分割法

编码算法需要多次求交,而且还有无意义求交的情况。
有人提出了中点分割法,无需求交,用中点逼近。
在这里插入图片描述

从P0点出发找出距P0最近的可见点A
从P1点出发找出距P1最近的可见点B
AB为可见部分

中点法

求离P0最近的可见点
在这里插入图片描述

(1)取中点Pm = (P0+P1) / 2
(2)如 P0 Pm 不是显然不可见,且 P0 P1 在
     窗口中有可见部分,则距P0最近的可
     见点一定落在  P0 Pm 上,所以用P0 Pm 代替 P0 P1 ;否则用 Pm P1 代替 P0 P1 
(3)再对新的P0 P1重复(1)(2),直到长度小于给定的控制常数ε为止.

求离P1最近的可见点类似求P0的可见点
算法的流程框图如下:
在这里插入图片描述
中点分割法是Cohen-Sutherland算法的特例,是它的改进。
算法特点
适合硬件实现
适合并行计算

梁友栋-Barsky算法

梁友栋这个人必须吹一波,来张图摩拜大佬,大佬醉心研究,不是抛头露面的主,图我只找到这种。
在这里插入图片描述

写入图形学教科书的唯一中国人的算法
梁有栋教授的贡献
Liang-Barsky算法
几何连续理论
从几何学与纤维缠绕理论到基因工程

算法思想:
在这里插入图片描述

设要裁剪的线段是P0P1。 P0P1和窗口边界交于A,B,C,D四点.
算法的基本思想是从A,B和P0三点中找出最靠近P1的点,图中要找的点是B;
从C,D和P1中找出最靠近P0的点.图中要找的点是C点。那么BC就是P0P1线段上的可见部分。

线段的参数表示

x=x0+t△x
y=y0+t△y
其中,△x=x1-x0 , △y=y1-y0

窗口边界的四条边分为两类:始边和 终边。
在这里插入图片描述
在这里插入图片描述

求出P0P1和两条始边的交点的参数t0’和t0 “令
在这里插入图片描述
则t0 就是图中A、B和P0三点中最靠近P1的点的参数。
求出P0P1和两条终边的交点的参数 t1 ’ ,t1 “ ,令
在这里插入图片描述
则t1就是图中C、D和P1三点中最靠近P0的点的参数。

当t1>t0时,参数t∈[t0, t1]的线段就是P0P1的可见部分;
当t0>t1时,整个直线段为不可见。
在这里插入图片描述
利用参数进行了转化,问题变成了如何快速求解直线与窗口四条边的交点对应参数t。
x = x0 + Δx · t
y = y0 + Δy · t
该参数方程与左边界即x=xL的交点为: xL = x0 + Δx · tL
即tL=(xL- x0)/ Δx = (xL- x0)/(x1-x0)
为了统一表示,令

   QL = -Δx       DL = x0 - xL
   QR = Δx        DR = xR – x0
   QB = -Δy       DB = y0 - yB 
   QT = Δy        DT = yT – y0    
   tL=DL/QL
同理可得参数方程与其它边的交点: 
       ti = Di/Qi, i= L,R,B,T

   QL = -Δx       DL = x0 - xL
   QR = Δx        DR = xR – x0
   QB = -Δy       DB = y0 - yB 
   QT = Δy        DT = yT – y0 
参数方程与其它边的交点, ti = Di/Qi, i= L,R,B,T

当Qi<0时,ti必是P0P1和始边的交点的参数;
当Qi>0时,ti必是P0P1和终边的交点的参数;
当Qi=0? 则直线一定与窗口的边平行或垂直

在这里插入图片描述

当Qi=0时, 若Di<0,则P0P1是完全不可见的,如图中AB和CD(左、下、左、右四种),
当Qi=0,而相应的 Di ≥0 时, 如图中的EF,与GH(两种)
举个栗子:
XL=0,XR=140,YB=0,YT=100,P0(-62,19).P1(204,166)
在这里插入图片描述
在这里插入图片描述
算法code:

L_B_lineClip(P1,P2,tmin,tmax,visible)
float P1[2],P2[2],*tmin,*tmax;int *visible;
{
    int *visible = False;  //False=0,表示不可见
    float tl=0.0, tu=1.0;  //t∈[0,1]
    float dx=p2[0]-p1[0];dy=p2[1]-p1[1];
    if(notreject(-dx,x0-xL,&tl,&tu))
        if(notreject(+dx, xR-x0,&tl,&tu))
           if(notreject(-dy,y0-yB,&tl,&tu))
               if(notreject(+dy, yT-y0,&tl,&tu))
              { *visible = True; *tmin=tl;*tmax=tu; 
                  x1=x0+tmin*dx; y1=y0+tmin*dy;
                  x2=x0+tmax*dx; y2=y0+tmax*dy;
                  line(x1,y1,x2,y2);
              }
}
int notreject(Q,D,tl,tu)
{
    float t;  int accept = True;
    if (Q<0)  //分母即Qi小于0,求与始边的交点
    { t= D/Q;
       if(t>*tu) accept=False;  //线段p1p2全不可见
       else if(t>*tl) *tl=t;  //取"进入"点的最大参数值   
    }
    else if(Q>0) //分母即Qi大于0,求与终边的交点
           {   t= D/Q;
               if(t<*tl) accept=False;  //线段p1p2全不可见
               else if(t<*tu) *tl=t;  //取"离开" 点的最小参数值
           }
          else if(D<0) accept=False; // Qi=0, Di<0,不可见
    return(accept);
}

直线裁剪算法的比较

Cohen-sutherland算法与中点算法在区码测试阶段能与位运算的方式高效率进行, 因而当大多数的线段能够简单的舍取时, 效率较好;中点算法可并行处理,进一步提高算法的效率。
Liang-Barsky该方法是以直线的参数方程为基础进行设计的。是一种只能应用于平行于坐标轴的矩形窗口,因而效率更高。
梁友栋和Barsky比Cohen-Sutherland算法速度更快,它把二维裁剪问题化成两次一维裁剪问题,直线裁剪算法转化为解一组不等式的问题。
对于这三种算法我做了一个简单的视频描述:
三种直线裁剪算法的比较

多边形裁剪算法

多边形边界是直线段的组合,那么能否利用线段裁剪算法?貌似可以?,实际不行。
在这里插入图片描述
在这里插入图片描述
不能用线段裁剪方法
在这里插入图片描述
原因在于:多边形的边界不再封闭,需要用窗口边界的恰当部分来封闭它
在这里插入图片描述
裁剪结果多边形的边由裁剪多边形(窗口的一部分)和主多边形的边(边的一部分)构成

Sutherland-Hodgman算法

S-H算法基本思想
将多边形关于矩形窗口的裁剪分解为多边形关于窗口四边所在直线的裁剪.
在这里插入图片描述

步骤多边形由顶点表示:V1V2…Vn,按一定(左上右下) 次序依次裁剪;与左边所在直线裁剪的结果是上边的输入,依次类推
输出为顶点序列,必然包含了窗口的一部分和主多边形的边的一部分.
也称逐边裁剪算法

裁剪线裁剪

输入输出:顶点序列V0V1V2 ….
多边形与窗口每条边裁剪
裁剪线:窗口边以及其延长线
在这里插入图片描述

内侧空间与外侧空间
包含裁剪窗口的半空间为内侧空间,否则为外侧空间

多边形与窗口裁剪线的裁剪

依据多边形的边SP与半空间的关系

情况1:同在内侧,裁剪后输出P
情况2:S 在内侧,P 在外侧,裁剪后输出交点 i
情况3:同在外侧,裁剪后不输出
情况4:S 在外侧, P 在内侧,裁剪后输出交点 i 和 P

在这里插入图片描述
算法

将顶点序列P1P2…Pn作为输入
依次对窗口的每条裁剪线作下列处理
	输入顶点序列
	依次顶点序列中相邻顶点构成的边PiPi+1进行裁剪处理
	输出顶点序列(下条裁剪线的输入)

举个栗子:
在这里插入图片描述

:输入  P1P2P3P4P5P6P7P8
    输出  I1P2P3P4P5P6P7P8I2
    
上:输入   I1P2P3P4P5P6P7P8I2 
    输出   P2I3I4P4P5P6P7P8I2I1
    
右:输入   P2I3I4P4P5P6P7P8I2I1
    输出   I3I4P4I5I6P6P7P8I2I1P2
    
下:输入   I3I4P4I5I6P6P7P8I2I1P2
    输出   I4P4I5I6I7I8P8I2I1P2I3
注意:
(1)交点是边与裁剪线的交点
(2)边的顶点是有序的
优缺点

优点

裁剪算法采用流水线方式,算法简单
被裁剪多边形可以是任意凸多边形或凹多边形
裁剪窗口不局限于矩形,可以是任意凸多边形

缺点

要求裁剪窗口是一个凸多边形区域
对裁剪后形成两个或多个分离的小多边形可能产生多余的边

在这里插入图片描述

Weiler-Atherton多边形裁剪算法

在这里插入图片描述
算法的基本思想:
假设被裁剪多边形P1和裁剪窗口P2的顶点序列都按顺时针方向排列
沿多边形的一条边走动,其右边为多边形的内部
算法从P1的任一顶点出发,沿着它的边向下处理,当P1与P2相交时(交点为I):
在这里插入图片描述
算法从P1的任一顶点出发,沿着它的边向下处理,当P1与P2相交时(交点为I):
(1)若P1的边是进入P2,则继续沿P1的边,往下处理,同时输出该线段;
(2)若P1的边是从P2中出来,则从此交点I开始,沿着窗口边框向右检测P2的边,即用P2的有效边框裁剪P1的边,找到P1和P2最靠近交点I的新交点,同时输出由I到S之间窗口边上的线段。
(3)返回交点I,再沿着P1处理各条边,直到处理完P1的每一条边,回到起点为止.

字符裁剪

基于字符串

整个字符串完全落在窗口之内时显示,否则不显示
字符串的矩形包围盒测试
在这里插入图片描述

基于字符

一个字符完全落在窗口之内时显示,否则不显示
字符的矩形包围盒测试
在这里插入图片描述

基于构成字符的最小元素

点阵字符:点裁剪
矢量字符:线裁剪

在这里插入图片描述
采用笔画/象素精度进行裁剪时,将笔划分解成直线段对窗口作裁剪,处理方法同上。
栗子:
在这里插入图片描述
在这里插入图片描述
多边形裁剪算法和字符裁剪算法我做了一个简单的哔哩视频:
多边形裁剪算法和字符裁剪算法

三维图形裁剪

三维图形必须经过投影变换才能在计算机屏幕上显示出来。为了避免对根本不在投影窗口内的物体做投影变换,减少计算量,通常直接在三维窗口进行裁剪。
若为平行投影,可取长方体作为三维裁剪窗口。
若为透视投影,可取四棱台作作为三维裁剪窗口。

三维Cohen-Suther Land算法

在这里插入图片描述
将二维Cohen-sutherland直线裁剪算法推广到三维平行投影裁剪算法中,对空间任一点P(x,y,z),按所处位置赋予6位二进制代码
在这里插入图片描述
对于空间任意一条直线段P1(x1,y1,z1)、 P2(x2,y2,z2)的两个端点进行编码code1、code2
(1)若code1与code2均为0,则在窗口空间内,取之;
(2)若code1&code2<>0, 则在窗口空间外,弃之;
(3)若不属于前两种,由它可能与窗口相交,此时需计算出线段与窗口表面的交点,并将线段分段后继续处理,直到余下的线段符合前两种情况止。

最后分享一些习题:

1
【填空题】
有一个窗口,XL=2,XR=10,YB=1,YT=8,一直线段P1P2,P(1,3),P2(15,10).1:P1、P2的区域编码分别是(           ),(         )。
问2:直线与窗口的位置属于哪一种类型(             )?判断依据是(                   )?
问3:直线与窗口的(                 )边相交? 判断依据是(                 )?

正确答案:
问1:​000110102:第三种,即与窗口相交。依据:code1不等于0,code2不等于0,且code1&code2=03: 上、左、右,依据: code1=0001 说明与左边相交,code2=1010,说明与上边和右边相交 。

liang-basky直线裁剪窗口可以是任意凸多边形。
正确答案:X 只能应用于平行于坐标轴的矩形窗口


在多边形的逐边裁剪法中,对于某条多边形的边(方向为从端点S到端点P)与某条裁剪线(窗口的某一边)的比较结果共有以下四种情况,分别需输出一些顶点.请问哪种情况下输出的顶点是错误的?    (      )
A、S和P均在可见的一侧,则输出S和P
B、S和P均在不可见的一侧,则输出0个顶点
C、S在可见一侧,P在不可见一侧,则输出线段SP与裁剪线的交点
D、S在不可见的一侧,P在可见的一侧,则输出线段SP与裁剪线的交点和P
正确答案:A 裁剪后输出P

中点分割裁剪法的算法思想是什么?
答:直线记为P0P1,从P0点出发找出距P0最近的可见点,记为A;从P1点出发找出距P1最近的可见点,记为B,则AB为可见部分。

二维Cohen-Sutherland裁剪算法:待裁剪直线P1P2如 图所示。
(1)给出直线P1P2端点的区域编码(4分)
(2)判断直线与窗口位置关系,判断依据?(4分)
(3)如需要裁剪,给出直线的裁剪过程(4分)
(4)写出区域编码的实现函数(4分)

在这里插入图片描述

1)Code1= 1001,code2=01102)第三种情况,即直线与窗口相交。因为code1与code2均不等于0,且code1&code2=03)裁剪过程
第一步:根据code1=1001,判断出直线与上边、左边相交;根据code2=0110,判断出直线与下边、右边相交。
第二步:约定求交次序为左上右下,则先求出交点A,舍弃P1A;将AP2继续,求出B,舍弃AB;依次类推,得到可见线段CB。
(4)区域编码函数:
int encode(float x, float y)
{
    int c=0;
    if (x<XL)  c=1 ;
    else if (x>XR)  c=2 ;
    if (y<YB)  c=c+4 ;
    else if (y>YT)  c=c+8 ;
    return c ;
}

今天的分享就到这里,喜欢的小伙伴可以关注哦。

©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页