光栅图形学算法--消隐算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Silent_F/article/details/76221838

  主要讲述的内容: 消隐的分类,如何消除隐藏线、隐藏面,主要介绍以下几个算法:
* Z缓冲区(Z-Buffer)算法
* 扫描线Z-buffer算法
* 区域子分割算法

消隐

  当我们观察空间任何一个不透明的物体时,只能看到该物体朝向我们的那些表面,其余的表面由于被物体所遮挡我们看不到。

如果把可见和不可见的线都画出来,对视觉会造成多义性

      
如上图中,最左边的图形把所有的线都画出来了,那么就会有两种情况,中间那种和最右边那种,这时就会产生多义性。
要消除二义性,就必须在绘制时消除被遮挡的不可见的线或面,习惯上称作消除隐藏线和隐藏面,简称消隐
要绘制出意义明确、富有真实感的立体图形,首先必须消去形体中的不可见部分,而只在图形中表现可见部分
      
消隐不仅与消隐对象有关,还与观察者的位置有关
      
当观察者在E1时,看到的就是AB,当观察这在E2时,看到的就是BD,可见与不可见只是相对于观察者的位置。

消隐的分类

按消隐对象分类

(1)线消隐
消隐对象时物体上的边,消除的是物体上不可见的边
(2)面消隐
消隐对象是物体上的面,消除的是物体上不可见的面,通常做真实感图形消隐时用面消隐

按消隐空间分类

物体空间的消隐算法

以场景中的物体为处理单元。假设场景中有k 个物体,将其中一个物体与其余k-1个物体逐一比较,仅显示它空间表面以达到消隐的目的。

(场景中的每一个物体)将该物体与场景中的其它物体进行比较,确定其表面的可见部分;显示该物体表面的可见部分;

在物体空间里典型的消隐算法有两个:Roberts算法光线投射法
Roberts算法数学吃力严谨,计算量甚大。算法要求所有被显示的物体都是凸的,对于凹体要先分割成多个凸体的组合
Roberts算法基本步骤:
* 逐个的独立考虑每个物体自身,找出为其自身所遮挡的边和面(自消隐);
* 将每一个物体上留下的边再与其它物体逐个的进行比较,以确定是完全可见还是部分或全部遮挡(两两物体消隐);
* 确定由于物体之间的相互贯穿等原因,是否要形成新的显示边等,从而使被显示各物体更接近现实。

光纤投射是求光纤与场景的交点,该光纤就是所谓的视线(如视点与像素连成的线)
一条视线与场景中的物体可能有许多交点,求出这些交点后需要排序,在前面的才能被看到。人的眼睛可以一目了然,但计算机做需要大量的运算。

图像空间的消隐算法

以屏幕窗口内的每个像素为处理单元。确定在每一个像素处,场景中的k个物体哪一个距离观察点最近,从而用它的颜色来显示该像素。

(窗口中每一个像素)确定距视点最近的物体,以该物体表面的颜色来显示像素;

因为最后看到的图像是在屏幕上的,所以就拿屏幕作为处理对象。针对屏幕上的像素来进行处理,算法的思想是围绕着屏幕的。对屏幕上每个象素进行判断,决定哪个多边形在象素可见。

Z缓冲区(Z-Buffer)算法

  Z缓冲区算法也叫深度缓冲器算法,属于图像空间消隐算法。改算法有帧缓冲器和深度缓冲器。对应两个数组:

intensity(x,y)——属性数组(帧缓冲器)
存储图像空间每个可见像素的光强或颜色
depth(x,y)——深度数组(z-buffer)
存放图像空间每个可见像素的z坐标

      

      
假定xoy面为投影面,z轴为观察方向,过屏幕上任意像素点(x,y)作平行于z轴的射线R,与物体表面相交于p1和p2点,p1和p2点的z值称为该点的深度值。
将最大的z值存入z缓冲器中,显然,p1在p2前面,屏幕上(x,y)这一点将显示p1点的颜色
* 算法思想:* 先将Z缓冲器中各单元的初始值置为最小值。当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值(保存在该像素所对应的Z缓冲器的单元中)
如果大于原来的Z值,说明当前多边形更靠近观察点,用它的颜色替换像素原来的颜色。

Z-Buffer算法的优点

(1)Z-Buffer算法比较简单,也很直观
(2)在象素级上以近物取代远物。与物体在屏幕上的出现顺序是无关紧要的,有利于硬件实现

Z-Buffer算法的缺点

(1)占用空间大
(2)没有利用图形的相关性和连续性,这是z-buffer算法的严重缺陷
(3)该算法是在像素级上的消隐算法

只用一个深度缓存变量zb的改进算法

一般认为,z-buffer算法需要开一个与图象大小相等的缓存数组ZB,实际上,可以改进算法,只用一个深度缓存变量zb
      
关键问题:判断象素点(i,j)是否在pk的投影多边形之内,不是一件容易的事。节省了空间但牺牲了时间。计算机的很多问题就是在时间和空间上找平衡。
另一个问题计算多边形Pk在点(i,j)处的深度。设多边形Pk的平面方程为:
图7

点与多边形的包含性检测:

(1)射线法
      
由被测点P处向y等于负无穷方向作射线,交点个数是奇数,则被测点在多边形内部;交点个数是偶数表示被测点在多边形外部。

若射线正好经过多边形的顶点,则采用“左开右边”的原则来实现。即:当射线与某条边的顶点相交时,若边在射线的左侧,交点有效。计数;若边在射线的右侧,交点无效,不计数。
用射线法来判断一个点是否在多边形内的弊端
a、计算量大
b、不稳定
(2)弧长法
      
以p点为圆心,作单位圆,把边投影到单位圆上,对应一段段弧长,规定逆时针为正,顺时针为负,计算弧长代数和。
代数和为0,点在多边形外部
代数和为2pi,点在多边形内部
代数和为pi,点在多边形上

这个算法为什么是稳定的?假如算出来后代数和不是0,而是0.2或0.1,那么基本上可以断定这个点在外部,可以认为是计算误差引起的,实际上是0。

但这个算法效率也不高,问题是算弧长并不容易,因此又派生出一个新的方法——以顶点符号为基础的弧长累加方法。

以顶点符合为基础的弧长累加方法

      
P是被测点,按照弧长法,p点的代数和为2pi,不要计算角度,做一个规定来取代原来的弧长计算。
      
同一个象限认为是0,跨过一个象限是pi/2,跨过二个象限是pi。这样当药计算代数和的时候,就不要去投影了,只要根据点所在的象限一下了就判断出多少度,这样几乎没有什么计算量,只有一些简单的判断,效率非常高。

Z-buffer算法是非常经典和重要的,在图形加速卡和固件里都有。只用一个深度缓存变量zb的改进算法虽然减少了空间,但仍然没考虑相关性和连贯性。

区间扫描线算法

图12
有三个区间,分别为不同的颜色。一根红色的扫描线,扫描线的交点把这条扫描线分成了若干个区间,每个区间上必然是同样一种颜色
对于有重合的区间,如a6a7这个区间,要么显示F2的颜色,要显示F3的颜色,不会出现颜色的跳跃
如果把扫描线和多边形的这些交点都求出来,对每个区间只要判断一个像素的要画什么颜色,那么整个区间的颜色都解决了,这就是区间扫描线算法的主要思想
算法的优点: 将象素计算改为逐段计算,效率大大提高!
算法的实现
首先要有多边形,然后求交点,然后交点进行排序
排序的结果就分成了一个个区间,然后在每个区间找当中的一个像素(i,j),在(i,j)处计算每个相关面的Z值,对相关深度值z进行比较,其中最大的一个就表示是可见的。整个这段区间就画这个z值最大面的颜色。

小区间颜色的确定
(1)小区间上没有任何多边形,如[a4,a5],用背景色显示
(2)小区间只有一个多边形,如[a1,a2],显示该多边形的颜色
(3)小区间上存在两个或两个以上的多边,比如[a6,a7],必须通过深度测试判断哪个多边形可见

Warnock算法

Warnock算法是图形空间中非常经典的一个算法
Warnock算法的重要性不在于它的效率比别的算法高,而在于采用了分而治之的思想,利用了堆栈的数据结构。
把物体投影到全屏幕窗口上,然后递归分割窗口,知道窗口内目标足够简单,可以显示为止。

什么情况下,画面足够简单可以立即显示?
(1)窗口中仅包含一个多边形
(2)窗口与一个多边形相交,且窗口内无其它多边形
(3)窗口为一个多边形多包围
(4)窗口与一个多边形相分离

如何判别一个多边形和窗口是分离的?
      
当满足下列条件是,多边形和窗口分离:
Xmin>xR or xmax>xL
ymin>yT or ymax>yB

如何判断一个多边形在窗口内?
      
当满足下列条件时,多边形被窗口包含:
Xmin>=xL & xmax<=xR
ymin>=yB & ymax<=yT
      
多边形与窗口相交的判别,可以采用直线方程作为判别函数来判定一个多边形是否与窗口相交

窗口有多个多边形投影面,如何显示?
Warnock算法的重要性不在于它的效率比别的算法高,而在于采用了分而治之的思想,利用了堆栈的数据结构
把物体投影到全屏幕窗口上,然后递归分割窗口,知道窗口内目标足够简单,可以显示为止

算法步骤

      
(1)如果窗口内没有物体则按背景色显示
(2)若窗口内只有一个面,则把该面显示出来
      
(3)窗口内含有两个以上的面,则把窗口等分为四个子窗口。对每个小窗口再做上述同样的处理。这样反复进行下去
把四个子窗口压在一个堆栈里(先进后出)

最近发现在markdown不会编辑数学公式,所以有些地方采用了截图

猜你喜欢

转载自blog.csdn.net/Silent_F/article/details/76221838