计算机图形学完整笔记(四):消隐

Posted by Lucius on August 17, 2020

第四章 消隐

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 独立开发,能够跟踪屏幕上每个像素深度的算法。

    • 该算法有帧缓冲器和深度缓冲器。

      • $intensity \ (x,y)$ —— 属性数组 (帧缓冲器),存储图像空间每个可见像素的光强或颜色

      • $depth\ (x,y)$ —— 深度数组 (z-buffer),存放图像空间每个可见像素的 z 坐标

  • 深度

    • 以 $xoy$ 面为投影面,$z$ 轴为观察方向。

    • 过屏幕上任意像素点 $(x,y)$ 作平行于 $z$ 轴的射线 $R$,与物体表面相交于 $p_1$ 和 $p_2$ 点。

    • $p_1$ 和 $p_2$ 点的 $z$ 值称为该点的深度值。

  • 算法思想

    • 先将 $Z$ 缓冲器中各单元的初始值置为最小值。当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值 (保存在该像素所对应的 $Z$ 缓冲器的单元中)

    • 如果大于原来的 $Z$ 值,说明当前多边形更靠近观察点,用它的颜色替换像素用来的颜色。

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
      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 算法改进
  • 算法改进

    • 只用一个深度缓存变量 $zb$ 代替与图像大小相等的缓存数组,节省了空间。

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
      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$ 在点 $(i,j)$ 处的深度

    • 多边形 $P_k$ 的平面方程为 $ax+by+cz+d=0$,$depth=-\frac{ai+bj+d}{c}$
  • 计算一点是否在多边形中

    • 射线法

      • 核心:由被测点 $P$ 处向 $y=-inf $ 方向作射线,交点个数是奇数,则被测点在多边形内部;交点个数是偶数表示在多边形外部。

      • 若射线正好经过多边形的顶点,则采用 “左开右闭” 的原则来实现。即:当射线与某条边的顶点相交时,若边在射线的左侧,交点有效,计数;若边在射线的右侧,交点无效,不计数。

      • 缺点:计算量大、不稳定 (浮点误差)
    • 弧长法

      • 核心:以 $p$ 点为圆心,作单位圆,把边投影到单位圆上,对应一段段弧长,规定逆时针为正,顺时针为负,计算弧长代数和。

      • 代数和为 0,点在多边形外部;代数和为 2π,点在多边形内部;代数和为 π,点在多边形边上。

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

      • 核心:$p$ 是被测点,按照弧长法,$p$ 点的代数和为 2π。不要计算角度,做一个规定来取代原来的弧长计算。

      • 在边上与内部均为 2π,外部为0。

      • $(x_i,y_i)$ $(x_{i+1},y_{i+1})$ 弧长变化 象限变化
        $(+ \ +)$ $(+ \ +)$ 0 $1\rightarrow1$
        $(+ \ +)$ $( - \ +)$ π/2 $1\rightarrow2$
        $(+ \ +)$ $( - \ -)$ π $1\rightarrow3$
        $(+ \ +)$ $( + \ - ) $ -π/2 $1\rightarrow4$
        $(- \ +)$ $(+ \ +)$ -π/2 $2\rightarrow1$
        $ (- \ +)$ $( - \ +)$ 0 $ 2\rightarrow2$
        $ (- \ +)$ $( - \ -)$ π/2 $2\rightarrow3$
        $ ( - \ +)$ $( + \ - ) $ π $2\rightarrow4$
        $ ( - \ -)$ $(+ \ +)$ $3\rightarrow1$
        $ ( - \ - ) $ $( - \ +)$ -π/2 $ 3\rightarrow2$
        $(- \ -)$ $( - \ -)$ 0 $ 3\rightarrow3$
        $ ( - \ -)$ $( + \ - ) $ π/2 $3\rightarrow4$
        $(+ \ - ) $ $(+ \ +)$ π/2 $4\rightarrow1$
        $(+ \ - ) $ $( - \ +)$ $ 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$ 整数算法

      • 尽可能地提高底层算法的效率,底层上提高效率才是真正解决问题。
    • 图形连贯性

      • 利用连贯性可以大大减少计算量。
    • 分而治之

      • 把一个复杂对象进行分块,分到足够简单再进行处理。

资料来源