计算机图形学 - 可见表面检测
当我们查看包含非透明物体和表面的图片时,我们无法看到那些位于更靠近眼睛的物体后面的物体。为了获得逼真的屏幕图像,我们必须移除这些隐藏的表面。这些表面的识别和移除称为隐藏面问题。
有两种方法可以解决隐藏面问题:物体空间方法和图像空间方法。物体空间方法在物理坐标系中实现,而图像空间方法在屏幕坐标系中实现。
当我们想要在二维屏幕上显示一个三维物体时,我们需要识别从选择的观察位置可见的屏幕部分。
深度缓存(Z 缓存)方法
该方法由卡特莫尔开发。它是一种图像空间方法。其基本思想是测试每个表面的 Z 深度以确定最近(可见)的表面。
在这种方法中,每个表面都单独处理,一次处理一个像素位置,跨越整个表面。比较像素的深度值,最近(最小的 z)表面决定在帧缓存中显示的颜色。
它在多边形表面上应用非常有效。表面可以以任何顺序处理。为了覆盖远离观察者的多边形,使用两个缓冲区,名为帧缓存和深度缓存。
深度缓存用于存储 (x, y) 位置的深度值,因为表面正在处理 (0 ≤ 深度 ≤ 1)。
帧缓存用于存储每个位置 (x, y) 的颜色值的强度值。
z 坐标通常归一化到 [0, 1] 范围。z 坐标的 0 值表示后裁剪平面,z 坐标的 1 值表示前裁剪平面。
算法
步骤 1 - 设置缓冲区值 -
Depthbuffer (x, y) = 0
Framebuffer (x, y) = 背景颜色
步骤 2 - 处理每个多边形(一次一个)
对于多边形的每个投影 (x, y) 像素位置,计算深度 z。
如果 Z > depthbuffer (x, y)
计算表面颜色,
设置 depthbuffer (x, y) = z,
framebuffer (x, y) = surfacecolor (x, y)
优点
- 易于实现。
- 如果在硬件中实现,则可以减少速度问题。
- 它一次处理一个对象。
缺点
- 需要大量的内存。
- 这是一个耗时的过程。
扫描线方法
这是一种识别可见表面的图像空间方法。此方法仅对单个扫描线具有深度信息。为了需要一行深度值,我们必须在处理下一条扫描线之前,同时对与给定扫描线相交的所有多边形进行分组和处理。为此,维护两个重要的表:边表和多边形表。
边表 - 它包含场景中每条线的坐标端点、每条线的反斜率以及指向多边形表的指针,以将边连接到表面。
多边形表 - 它包含平面系数、表面材料属性、其他表面数据,并且可能是指向边表的指针。
为了便于搜索与给定扫描线相交的表面,形成了一个活动的边列表。活动列表仅存储与扫描线相交的边,并按 x 递增的顺序排列。此外,为每个表面设置一个标志,以指示扫描线上某个位置是在表面内部还是外部。
从左到右处理每条扫描线上的像素位置。在与表面的左侧交点处,表面标志打开;在右侧交点处,标志关闭。您只需要在多条表面在某个扫描线位置的标志都打开时执行深度计算。
区域细分方法
区域细分方法通过定位表示单个表面一部分的查看区域来利用优势。将总查看区域细分为越来越小的矩形,直到每个小区域都是单个可见表面的一部分的投影或根本没有表面为止。
继续此过程,直到细分很容易被分析为属于单个表面,或者直到它们被缩减到单个像素的大小。一种简单的方法是在每个步骤中将区域依次分成四个相等的部分。表面与指定区域边界可能存在四种可能的关系。
包围表面 - 完全包围该区域的表面。
重叠表面 - 部分在区域内部,部分在区域外部的表面。
内部表面 - 完全在区域内部的表面。
外部表面 - 完全在区域外部的表面。
确定区域内表面可见性的测试可以用这四种分类来表示。如果以下条件之一为真,则无需进一步细分指定区域 -
- 所有表面相对于该区域都是外部表面。
- 该区域中只有一个内部、重叠或包围表面。
- 包围表面遮挡了区域边界内的所有其他表面。
背面检测
一种快速简单的物体空间方法,用于识别多面体的背面,是基于“内部-外部”测试。如果点 (x, y, z) 在具有平面参数 A、B、C 和 D 的多边形表面“内部”,则当内部点沿着视线到表面时,多边形必须是背面(我们位于该面的内部,无法从我们的观察位置看到它的正面)。
我们可以通过考虑多边形表面的法向量N来简化此测试,该法向量具有笛卡尔分量 (A, B, C)。
一般来说,如果 V 是从眼睛(或“相机”)位置到观察方向的向量,则如果该多边形是背面
V.N > 0
此外,如果对象描述转换为投影坐标,并且您的观察方向平行于观察 z 轴,则 -
V = (0, 0, Vz) 以及 V.N = VZC
因此,我们只需要考虑法向量N的分量 C 的符号。
在观察方向沿负 $Z_{V}$ 轴的右手观察系统中,如果 C < 0,则多边形是背面。此外,我们无法看到法向量 z 分量 C = 0 的任何面,因为您的观察方向朝向该多边形。因此,一般来说,如果其法向量的 z 分量值为 -,我们可以将任何多边形标记为背面
C <= 0
类似的方法可用于采用左手观察系统的包中。在这些包中,平面参数 A、B、C 和 D 可以根据以顺时针方向指定的多边形顶点坐标计算(与右手系统中使用的逆时针方向不同)。
此外,背面具有指向远离观察位置的法向量,当观察方向沿正 $Z_{v}$ 轴时,由 C >= 0 识别。通过检查定义对象的不同平面的参数 C,我们可以立即识别所有背面。
A 缓存方法
A 缓存方法是深度缓存方法的扩展。A 缓存方法是 Lucasfilm Studios 为渲染系统 Renders Everything You Ever Saw (REYES) 开发的一种可见性检测方法。
A 缓存扩展了深度缓存方法以允许透明度。A 缓存中的关键数据结构是累积缓存。
A 缓存中的每个位置有两个字段 -
深度字段 - 它存储一个正数或负数实数
强度字段 - 它存储表面强度信息或指针值
如果深度 >= 0,则存储在该位置的数字是与相应像素区域重叠的单个表面的深度。然后,强度字段存储该点表面颜色的 RGB 分量以及像素覆盖率的百分比。
如果深度 < 0,则表示多个表面对像素强度的贡献。然后,强度字段存储指向表面数据链接列表的指针。A 缓存中的表面缓冲区包括 -
- RGB 强度分量
- 不透明度参数
- 深度
- 区域覆盖率百分比
- 表面标识符
该算法的执行方式与深度缓存算法相同。深度和不透明度值用于确定像素的最终颜色。
深度排序方法
深度排序方法同时使用图像空间和物体空间操作。深度排序方法执行两个基本功能 -
首先,按深度递减的顺序对表面进行排序。
其次,按顺序扫描转换表面,从深度最大的表面开始。
多边形表面的扫描转换在图像空间中执行。这种解决隐藏面问题的方法通常称为画家算法。下图显示了深度排序的效果 -
该算法首先按深度进行排序。例如,多边形的初始“深度”估计可以取为多边形任何顶点的最近 z 值。
让我们取列表末尾的多边形 P。考虑所有其 z 范围与 P 重叠的多边形 Q。在绘制 P 之前,我们进行以下测试。如果任何以下测试为正,则我们可以假设可以在 Q 之前绘制 P。
- x 范围是否不重叠?
- y 范围是否不重叠?
- P 是否完全位于 Q 平面的另一侧,远离视点?
- Q 是否完全位于 P 平面的同一侧,靠近视点?
- 多边形的投影是否不重叠?
如果所有测试都失败,则使用另一个平面的平面分割 P 或 Q。将新的切割多边形插入深度顺序中,并继续该过程。理论上,此分区可能会生成 O(n2) 个单独的多边形,但在实践中,多边形的数量要少得多。
二叉空间划分 (BSP) 树
二叉空间分割用于计算可见性。要构建BSP树,应从多边形开始并标记所有边。一次处理一条边,扩展每条边使其将平面分成两部分。将第一条边作为树的根节点放置。根据后续边是在内部还是外部添加它们。跨越已在树中的边的扩展的边被分成两部分,并将这两部分都添加到树中。
从上图中,首先取A作为根节点。
列出图(a)中的所有节点。
将所有位于根节点A前面的节点放在节点A的左侧,并将所有位于根节点A后面的节点放在右侧,如图(b)所示。
首先处理所有前面的节点,然后处理后面的节点。
如图(c)所示,我们将首先处理节点B。由于节点B前面没有任何节点,因此我们放置了NIL。但是,节点B后面有节点C,因此节点C将位于节点B的右侧。
对节点D重复相同的过程。