前言
如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。
文章目录
第四章 消隐
4.1 消隐概述
4.1.1 消隐定义
-
消隐
- 如果把可见和不可见的线都画出来,会对视觉造成多义性。
- 要消除二义性,就必须在绘制时消除被遮挡的不可见的线或面,即消除隐藏线和隐藏面,简称消隐。
4.1.2 消隐分类
- 按消隐对象分类
- 线消隐
- 消隐对象是物体上的边,消除的是物体上不可见的边。
- 面消隐
- 消隐对象是物体上的面,消除的是物体上不可见的面,通常做真实感图形消隐时用面消隐。
- 线消隐
- 按消隐空间分类
- 物体空间的消隐算法
- 以场景中的物体为处理单元。假设场景中有 k 个物体,将其中一个物体与其余 k-1 个物体逐一比较,仅显示它可见表明以达到消隐的目的。
- 此类算法常用于线框图的消隐。
- Roberts 算法、光线投射法
- 图像空间的消隐算法
- 消隐算法的主流。
- Z-buffer 算法
- 扫描线算法
- Warnock 消隐算法
- 物体空间的消隐算法
4.2 物体空间的消隐算法
4.2.1 Roberts 算法
- 算法步骤
- 逐个的独立考虑每个物体自身,找出为其自身所遮挡的边和面 (自消隐)
- 将每一物体上留下的边再与其它物体逐个的进行比较,以确定是完全可见还是部分或全部遮挡 (两两物体消隐)
- 确定由于物体之间的相互贯穿等原因,是否要形成新的显示边等,从而使被显示各物体更接近现实。
- 算法特点
- 数学处理严谨,计算量甚大。算法要求所有被显示的物体都是凸的,对于凹体要先分割成多个凸体的组合。
4.2.2 光线投射法
- 定义
- 光线投射是求光线与场景的交点,该光线就是所谓的视线 (如视点与像素连成的线)
- 特点
- 一条视线与场景中的物体可能有许多交点,求出这些交点后需要排序,在前面的才能被看到。人的眼睛可以一目了然,但计算机做需要大量的运算。
4.3 Z 缓冲区算法 (Z-Buffer)
4.3.1 Z-Buffer 算法概述
-
算法介绍
- 该算法由 Edwin Catmull 独立开发,能够跟踪屏幕上每个像素深度的算法。
- 该算法有帧缓冲器和深度缓冲器。
- i n t e n s i t y ( x , y ) intensity \ (x,y) intensity (x,y) —— 属性数组 (帧缓冲器),存储图像空间每个可见像素的光强或颜色
- d e p t h ( x , y ) depth\ (x,y) depth (x,y) —— 深度数组 (z-buffer),存放图像空间每个可见像素的 z 坐标
-
深度
- 以 x o y xoy xoy 面为投影面, z z z 轴为观察方向。
- 过屏幕上任意像素点 ( x , y ) (x,y) (x,y) 作平行于 z z z 轴的射线 R R R,与物体表面相交于 p 1 p_1 p1 和 p 2 p_2 p2 点。
- p 1 p_1 p1 和 p 2 p_2 p2 点的 z z z 值称为该点的深度值。
-
算法思想
-
先将 Z Z Z 缓冲器中各单元的初始值置为最小值。当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值 (保存在该像素所对应的 Z Z Z 缓冲器的单元中)
-
如果大于原来的 Z Z 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 算法的优点
- Z-Buffer 算法比较简单,也很直观。
- 在像素级上以近物取代远物。与物体在屏幕上的出现顺序是无关紧要的,有利于硬件实现。
-
Z-Buffer 算法的缺点
- 占用空间大
- 没有利用图形的相关性与连续性 (严重缺陷)
- 该算法是在像素级上的消隐算法 (很大缺陷)
4.3.2 Z-Buffer 算法改进
-
算法改进
-
只用一个深度缓存变量 z b zb zb 代替与图像大小相等的缓存数组,节省了空间。
-
z-Buffer算法 () { 帧缓存全置为背景色 for( 屏幕上的每个象素(i,j) ) { 深度缓存变量zb置最小值 MinValue; for(多面体上的每个多边形Pk) { if(象素点(i,j)在pk的投影多边形之内) { //如何查看一点是否在多边形中 计算Pk在(i,j)处的深度值depth; //如何计算深度值 if(depth大于zb) { zb = depth; indexp = k; (记录多边形的序号) } } } if(zb != MinValue) 计算多边形 P 在交点 (i,j) 处的光照颜色并显示 } }
-
-
计算 P k P_k Pk 在点 ( i , j ) (i,j) (i,j) 处的深度
- 多边形 P k P_k Pk 的平面方程为 a x + b y + c z + d = 0 ax+by+cz+d=0 ax+by+cz+d=0, d e p t h = − a i + b j + d c depth=-\frac{ai+bj+d}{c} depth=−cai+bj+d
-
计算一点是否在多边形中
-
射线法
-
核心:由被测点 P P P 处向 $y=-inf $ 方向作射线,交点个数是奇数,则被测点在多边形内部;交点个数是偶数表示在多边形外部。
-
若射线正好经过多边形的顶点,则采用 “左开右闭” 的原则来实现。即:当射线与某条边的顶点相交时,若边在射线的左侧,交点有效,计数;若边在射线的右侧,交点无效,不计数。
-
-
缺点:计算量大、不稳定 (浮点误差)
-
-
弧长法
- 核心:以 p p p 点为圆心,作单位圆,把边投影到单位圆上,对应一段段弧长,规定逆时针为正,顺时针为负,计算弧长代数和。
- 代数和为 0,点在多边形外部;代数和为 2π,点在多边形内部;代数和为 π,点在多边形边上。
-
以顶点符号为基础的弧长累加方法
-
核心: p p p 是被测点,按照弧长法, p p p 点的代数和为 2π。不要计算角度,做一个规定来取代原来的弧长计算。
-
在边上与内部均为 2π,外部为0。
-
-
( 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) 弧长变化 象限变化 ( + + ) (+ \ +) (+ +) ( + + ) (+ \ +) (+ +) 0 1 → 1 1\rightarrow1 1→1 ( + + ) (+ \ +) (+ +) ( − + ) ( - \ +) (− +) π/2 1 → 2 1\rightarrow2 1→2 ( + + ) (+ \ +) (+ +) ( − − ) ( - \ -) (− −) π 1 → 3 1\rightarrow3 1→3 ( + + ) (+ \ +) (+ +) $( + \ - ) $ -π/2 1 → 4 1\rightarrow4 1→4 ( − + ) (- \ +) (− +) ( + + ) (+ \ +) (+ +) -π/2 2 → 1 2\rightarrow1 2→1 $ (- \ +)$ ( − + ) ( - \ +) (− +) 0 $ 2\rightarrow2$ $ (- \ +)$ ( − − ) ( - \ -) (− −) π/2 2 → 3 2\rightarrow3 2→3 $ ( - \ +)$ $( + \ - ) $ π 2 → 4 2\rightarrow4 2→4 $ ( - \ -)$ ( + + ) (+ \ +) (+ +) -π 3 → 1 3\rightarrow1 3→1 $ ( - \ - ) $ ( − + ) ( - \ +) (− +) -π/2 $ 3\rightarrow2$ ( − − ) (- \ -) (− −) ( − − ) ( - \ -) (− −) 0 $ 3\rightarrow3$ $ ( - \ -)$ $( + \ - ) $ π/2 3 → 4 3\rightarrow4 3→4 $(+ \ - ) $ ( + + ) (+ \ +) (+ +) π/2 4 → 1 4\rightarrow1 4→1 $(+ \ - ) $ ( − + ) ( - \ +) (− +) -π $ 4\rightarrow2$ $(+ \ - ) $ ( − − ) ( - \ -) (− −) -π/2 $ 4\rightarrow3$ $(+ \ - ) $ $( + \ - ) $ 0 $ 4\rightarrow4$
-
-
4.4 区间扫描线算法
-
算法概述
- 考虑Z-Buffer没有利用图形的相关性和连续性的缺陷,该算法放弃了Z-Buffer的思想(一个像素可能被多个多边形覆盖,即一个像素要多次判别,效率极低),是消隐算法中最快的算法之一。
-
算法过程
-
把扫描线和多边形的这些交点都求出来,对每个区间,只判一个像素的颜色,那么整个区间都是该颜色
-
像素计算 -> 逐段计算,效率大大提高。
-
-
确定小区间的颜色:
- 小区间无任何多边形,如[a4, a5],用背景色显示
- 小区间仅有一多边形,如[a1, a2],显示该多边形颜色
- 小区间存在两个以上多边形,如[a6, a7],用深度检测
-
-
算法实现问题
- 如何求交点
- 利用增量算法简化求交
- 每段区间上要求 z 值最大的面,如何得知区间与哪些多边形相关
- 利用区间扫描转换算法中的 AET 与 NET 得知
- 如何求交点
4.5 Warnock消隐算法
-
算法概述
- 区域子分割算法,发明人 Warnock (Adobe创始人),图像空间中非常经典的算法,其重要性不体现在其效率,而是体现在分治思想和堆栈数据结构的运用。
-
算法思想
- 把物体投影到全屏幕窗口
- 递归分割窗口,直到窗口内目标足够简单(可以显示)
- 若窗口分割至像素级别,仍有两个以上的面,则不必再分割。取窗口内最近的可见面颜色或所有可见面平均颜色即可。
-
如何判断窗口内图形足够简单
-
四种简单窗口图形
-
窗口中仅包含一个多边形
-
窗口与一个多边形相交,且窗口内无其它多边形 —— 直线方程作为判别函数
-
窗口为一个多边形所包围
-
窗口与一个多边形相分离
-
-
4.6 光栅扫描算法小结
- 核心思想
- 增量思想
- 通过增量算法可以减少计算量。
- 编码思想
- 符号判别
→
\rightarrow
→ 整数算法
- 尽可能地提高底层算法的效率,底层上提高效率才是真正解决问题。
- 图形连贯性
- 利用连贯性可以大大减少计算量。
- 分而治之
- 把一个复杂对象进行分块,分到足够简单再进行处理。
- 增量思想