hyde
路人甲
路人甲
  • 注册日期2003-09-24
  • 发帖数555
  • QQ
  • 铜币1457枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:1182回复:0

3D图形编程指南7续 - 建模

楼主#
更多 发布于:2004-04-27 14:10
将公共项提到括号外面,就减少了乘法运算的数量。但是,对于每一个点,仍然有三次乘法运算。Casteljau发明了一种有效的加速方法。一个Bézier曲线可以被分成两个子曲线,如下图所示:


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image670.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.11 通过细分迭代建立一个三次曲线</B></FONT></TD></TR></TABLE>
  在图6.11中,点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image671.gif">是<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image672.gif">、<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image673.gif">间连线的中点,同样<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image674.gif">是<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image675.gif">的中点。点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image676.gif">是线段<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image677.gif">的中点。这样,<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image678.gif">就在原先的曲线上,将曲线分割为两个部分,点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image679.gif">控制第一部分,点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image680.gif">控制第二部分。
  正如我们所看到的,这样的分割过程只是一个简单的寻找线段中点的过程。这一过程有一个除以2的操作,可以通过位移操作来实现。通过这样的迭代过程,可以得到任意多的曲线上的点。(见程序清单6.1)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image681.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>表6.1 用细分迭代的方法找到Bézier曲线上的点</B></FONT></TD></TR></TABLE><B>
</B>  三维空间中的三次曲线与平面空间中的曲线的表达方法是一样的。不同点就在于三维空间中的曲线有三个坐标分量。尽管曲线有时也是比较重要的图元,但对于实体模型来说,我们更关心表面片。双三次面片可以用一系列的三次曲线来进行表示。每一个面片由16个控制量。在每一个截面上,面片本身都是一个三次曲线。面片的表达公式如下:


<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image682.gif"></TD></TR></TABLE>
注意,公式中包含了两个参数:<I>s</I>和<I>t</I>,因此名为“双三次曲面片(bicubic patch)”。在这个公式中,[<I>M</I>]是一个4x4的矩阵(<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image683.gif">是它的转置矩阵,<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image684.gif">),[<I>G</I>]是一个4x4的几何矩阵,它包含了面片的控制量。尽管面片的表达式也可以由许多的形式,但我们在实际程序中最关心的还是Bézier形式,它包含了所有的16个控制量。这样,上面公式中的[<I>M</I>]实际上就是一个Bézier基矩阵,[<I>G</I>]就是包含了16个控制量的矩阵。图6.12描绘了一个由两个Bézier面片建立的模型,图6.13显示了一个Bézier面片控制点的线框。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image685.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.12 由两个双三次面片建立的物体</B></FONT></TD></TR></TABLE>
  拥有了面片的解析式之后,我们就可以在从屏幕到世界的处理过程中来使用这个图元了。与所讨论的图元其它形式一样,上面得到的面片公式还可以与光线投射公式一同来使用。
  如果我们使用从世界到屏幕方法,那么找到属于面片的点将会十分重要。这一过程也极其简单明了。我们使用下面的方法:对于一个参数<I>s</I>,找到面片上属于四个曲线的点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image686.gif">。具体来说,从<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image687.gif">找到<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image688.gif">,从<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image689.gif">找到<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image690.gif">,以此类推。(见图6.14)这样,公式就变成:


<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image691.gif"></TD></TR></TABLE>
  上面的公式意味着点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image686.gif">实际上就是一个3-D三次曲线的控制点,对于参数<I>t</I>。我们可以进一步由参数<I>t</I>来得到面片上的点。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image692.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.13 一个双三次面片和它的控制网格</B></FONT></TD></TR></TABLE>
  通过变化两个参数,我们就可以得到任意多的属于面片的点。(见图6.14)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image693.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.14 属于面片的点的计算</B></FONT></TD></TR></TABLE>
  为了加快这一步骤的处理速度,我们可以使用在Bézier曲线的情形中讨论过的细分方法。
  尽管我们可以在这一阶段得到许多属于面片的点,但是我们仍然不知道如何来对它进行光栅化处理。也许你会感到十分惊讶,我们通常用平面多边形来对双三次曲面的光栅化处理来进行逼近。我们找到一个属于面片的点的空间离散的格子,然后使用这个格子建立一个多边形的网格。接着就可以使用多边形光栅化管道来进行光栅化处理了。
  这种方法有一点矛盾。毕竟,我们使用双三次曲面的首要动机就是要避免使用平面多边形来对表面进行逼近。但不幸的是,我们经常被迫使用多边形来进行逼近,这主要是由于直接对曲面进行光栅化处理是非常复杂的,当然也要考虑到我们经常使用的各种工具和可用的管道。通常,我们已经具有了一个多边形处理管道,有时它们还是通过硬件来执行的。
  虽然我们通常都是在从世界到屏幕的视处理过程中的最后阶段才使用多边形来对双三次曲面进行渲染,但是这些图元至少留下来两大好处。双三次曲面在建模时是非常适合的,一个是因为它操作的简便性,另一个是因为它的存储量比较小。另外,在视处理过程中,我们可以对控制点使用旋转、缩放和平移,并且只在透视变换和光栅化处理时再使用多边形网格。
  让我们再仔细讨论一下最后阶段。我们可以对控制点进行变换的原因是因为组成面片的曲线是可以用公式表示的:

<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image694.gif"></TD></TR></TABLE>
  写成另外的形式如下:


<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image695.gif"></TD></TR></TABLE>
  式中,<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image696.gif">是一些标量值,


<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image697.gif"></TD></TR></TABLE>
  我们用矩阵[<I>T</I>]来表示坐标变换,就得到下面的形式:


<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>

<TR align=middle>
<TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image698.gif"></TD></TR></TABLE>
  这个最后的表达式也就是说:我们不用关心执行了什么,不管是在执行了对控制点的仿射变换之后计算三次曲线上的点,还是在计算了曲线上的点之后对它们进行变换。无论如何这种方法对透视变换并不适用。原因就是在透视变换中,(x/z,y/z)不是线性的。这也就是我们使用曲线的最基本的动机。但是,曲线和面片处理起来的计算量是很大的。
  知道了如何来表现和渲染表面面片和曲线段,我们面临着一个问题:如何将单独的小片组合成复杂的表面和曲线。在使用多边形模型的情况下,相邻的多边形共用顶点和边,这样就形成了连续的表面。我们对双三次曲面和三次曲线使用类似的方法。当我们要将两个双三次面片连接起来时,可以有不同的连接方法。当连节点处的切线方向(不是大小)一致时,两个Hermite曲线实现了几何连续。如果切线的大小也相同的话,那么连接状态将会更好。从实际观察的角度来说,更好的连接状态也就意味着更加平滑的过渡。图6.15显示了两个曲线连接的情况:


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image699.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.15 两个曲线的连接</B></FONT></TD></TR></TABLE>
  正如我们所看到的,在对复杂的平滑表面或曲线建模时,要达到正确的连接是很重要的。如果模型是有交互性的,那么连接的精度通常要由建模人员进行定义。另一方面,如果我们用采样的方法来创建合成表面,那么将一系列离散的采样点组合成一个连续的表面将会十分复杂。这时,我们可以考虑使用B样条曲线。这一图元表现了三次曲线的形式,但是实际上,两个相邻的小片共用多个控制点,提供了较高的连续度。(见图6.16)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image700.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.16 用一个B样条来达到连续的效果</B></FONT></TD></TR></TABLE>
  注意,在图6.16中,两个相邻的标着3和4的曲线共用三个控制点<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image701.gif">和<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image702.gif">。同时,与前面介绍的其它曲线形式不同,B样条曲线并不穿过控制点。但是,这种形式经常在最后渲染时变换成多个Bézier曲线的形式,因为要进行较为快速的细分处理和以后的绘制处理。
  一个用双三次曲面进行模拟的实体模型可以用与多边形模型相同的数据结构来进行表示。(见图6.17)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image703.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.17 由双三次曲面组成的模型的数据结构</B></FONT></TD></TR></TABLE>
  这种模型的视处理与多边形模型基本相同。在从世界到屏幕的渲染方法中,首先对控制点进行必要的坐标变换。然后将面片用多边形进行逼近,并使用多边形渲染管道将物体绘制在屏幕上。在从屏幕到世界方法中,要找到射线与双三次面片的交点。由于两个公式都已具备,交点就可以通过方程组的方法来得到。
  对于这种方法,我们还有许多改进和扩展。首先,可以使用一些办法将位于视锥之外的面片抛弃掉。Bézier三次曲线和双三次表面的一个特性 — 也就是所有的控制点都位于曲线或曲面的外侧 — 使得我们也可以将多边形和双三次面片合并同一个模型中。
  在真实生活中,总有一些物体,它们的一部分是曲面而另一部分是平面。尽管双三次曲面也可以表示平面,但是系统开销将会很大。另外,光栅化处理前的多边形网格的构造也可以根据曲率调整者来进行。如果面片都是平面,那只需要很少或者可以不用进行细分,相反,如果弯曲度很高,那么细分的数量也就要求很多。
  总之,使用双三次曲面来进行建模允许我们表现十分复杂的物体。尽管这种方法在运行时有一定的难度,但是渲染过程可以非常有效的来进行。

<B>6.4、地形</B>
  在许多图形程序中,我们都要表现一些户外世界的景物。我们所能描绘的最简单的户外图象,就是一个无限的平面,平面上坐落着许多不同的物体,例如树或者是建筑等。但是,通常的地形并不是一个平面,对于许多战场模拟的程序来说,我们需要找到一些建模的方法来显示与真实世界相似的地形。在这一部分中,我们将主要讨论几种进行地形建模的技术。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><B><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image704.gif"></B></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.18 地形</B></FONT></TD></TR></TABLE>
  当我们考虑一个地形时,经常都会联想到这样的一个表面,如图6.18所示。在前面的章节中,我们已经讨论过一些技术使我们能够使用平面面片或简单的曲面面片来对复杂的表面进行模拟。尽管我们所讨论的普通的方法仍然适用,但是考虑到一些特殊的特性和某些实际存在的情况,我们将更加详细的对地形模拟进行讨论。大多数表现地形的技术都利用了几种属性。一个地形可以被假设为自身不相交的表面,也可以假设它是一个有两个变量的函数(f(x,y))。这就意味着在每一个(x,y)表示的点上, 都有一个值f(x,y)来表示该点的高度。但这在实际生活中却并不适用,因为有时一个点上可能会有两个高度值。(见图6.19)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image705.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.19 真实的地形可能不是一个函数</B></FONT></TD></TR></TABLE>
  从图6.19中可以看到,在一个点上有两个高度值出现。但是,由于大多数情况下的地形都是比较平坦的,所以用函数形式来表示地形也是可以接受的。要考虑所有可能的情况,我们可以用表格的形式来表示地形,也就是将每一个点(x,y)处的高度值列成一个表格,这就是我们所说的高度场(height field)。采样出来的点定一个用来对表面进行逼近的多边形网格。还有一种方法,就是将(x,y)平面分割为一些等边的单元,在每个单元内定义一个双三次面片。这种方法可以用来表示图6.17所显示的情况。但是,这样又会增加额外的计算量,还会对隐面消除等处理带来不便。
  对于预采样问题,我们也要考虑一些问题。首先要考虑的就是存储的难易问题。这时,使用正方形矩阵比较合适。但是这也就是说我们要对采样进行一定的调整,并将表面分割成正方形的单元。这种方法的简单之处就在于它的定义比较方便。缺点是它没有考虑被逼近表面曲率的变化。当曲率较小时,我们应该将采样步长调整得大一些,相反,当曲率较大时,要将步长调的小一些。这种采样的自适应性既保证了表现的精度,又可以节省一些存储空间。(见图6.20)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image706.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.20 地形的等边、自适应采样</B></FONT></TD></TR></TABLE>
  在进行采样时,我们可以使用递归的方法。也就是每一个单元个本身也可以包含一个采样点的数组(见图6.20)。当单元内的表面比较平坦时,我们可以在单元内使用较大步长的采样,而当单元内表面是弯曲的时,就可以使用较小步长来采样。但是这样又会产生一个问题,那就是两个相邻的单元格之间会出现不连续的现象。(见图6.21)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image707.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.21 相邻单元的不连续现象</B></FONT></TD></TR></TABLE>
  为了避免这种情况的发生,我们必须确保只有少数的细分可以执行,并且要保证细分较多的单元格边的点必须能落在相邻的单元上。
  由于我们使用了正方形数组来存放采样的,因此使用正方形单元或是矩形单元就很自然了。但是这样的单元包含了四个顶点,并且它们并不一定要在同一个平面上,因此,也就可能不会定义一个单独的平面多边形。为了避免这一问题的出现,我们将每一个单元格再分割为两个三角形。这样,三个顶点就一定会共面了。(见图6.22)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image708.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.22 将单元格分割为两个三角形</B></FONT></TD></TR></TABLE>
  这些模型的渲染过程与一般的多边形模型的渲染过程基本是一致的。对于规则采样,我们将不会在数据结构中保留平面x和y坐标,只保留高度。知道了采样步骤,我们能很容易地推算出前二者。
  地形的虚拟再现可以模拟实际生活中很大一片区域。但是在实际生活中,我们只能看到我们身边很有限的一个区域。这样在对人造的地形模型进行视处理时,我们就要对靠近观察者的一个小的地形区域进行一些预选择。这种方法对于视处理十分有效并且可以在裁剪处理之前独立来进行。
  预选择完成之后,被选中的多边型网格接着就要进行必要的视处理过程。图6.23显示了一种可能的数据结构。注意,除了存储高度信息之外,我们也要存储一个包含了单元格属性的正方形的结构树组,这些属性包含了纹理映射或者是表面上物体的列表等信息。


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image709.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.23 可能的地形数据结构</B></FONT></TD></TR></TABLE>
  我们已经提到,地形对于战斗模拟程序是非常重要的。因此,对地形模拟做了大量的改进和加速处理。其中一种技术就是对同一个地形进行多次采样,每次采样的步长选择根据观察者位于地面以上的高度不同而有所不同。
  大多数情况下我们使用从世界到屏幕的渲染方法来显示地形。我们所考虑过的一些问题对于这种视处理过程非常适用。但是,对帧速要求较高而交互性较少的地形则使用从屏幕到世界的方法。另外,射线投射方法对于描绘交互性要求较高的地形非常有用,特别是在使用特殊硬件的时候。

<B>6.5、体素模型</B>
  体素模型表示“体积元素(volume element)”,它与表示“图示元素(pictorial element)”的像素比较相似。顾名思义,体素的目的就是要表现体积信息。对于前面讨论的所有模拟实体模型的方法,它们都是很耗费劳动的。我们要花费相当的时间和精力来创建多边形或者是双三次曲面。另一方面,采样的方法也只是得到一些离散的点的信息,并不能得到多边形或者是其它解析的表面信息。
  从这方面来说,体素技术无疑是一种用来取代传统的解析建模的方法。这种方法的思想是通过它们所占有的空间来表现物体或物体的集合。我们可以使用一个矩阵,它里面的每一个单元都模拟一个小的空间体积。它可以做一些标志来表示已经被占用了,这时,矩阵的入口可能有一个值来表示这个区域空间的一些属性,如颜色或是密度等。当单元格式是空的时,它就表示相应的空间没有被占用。
  这种表示方法首先的优点就是它非常简单,并且几乎直接包含了设备(如CATV扫描仪)可以提供给我们的一些数据。在这一领域(如医疗成像和远程传感等)经常使用体素技术。但是,有一个限制条件。空间占用矩阵的表示需要很大的存储空间,并且有时在存储上是很浪费的。假设现在我们用体素来模拟一个房间。那么所有空着的空间仍然会占据大量的空置的完整的单元。
  我们有一个有效的替代空间占用矩阵的方法。实际上,我们可以很简单的对所有空闲的空间做上标记,并且只给那些真正有用的单元分配存储空间 。我们可以使用四叉树(Quad<I> </I>trees)和八叉树(octal trees)来达到上面的目的 。四叉树(按四展开)用于平面程序。它的每个节点都有四个子树。在3-D空间中与四叉树对应的就是八叉树(按八展开),它的每一节点都有8个子树。
  我们先来考虑四叉树。构造一个四叉树一般分为几个步骤。首先,将平面空间分为四个相等的部分。在相应节点上把所有空的部分都标记为0。将完全被占用的部分也要进行标记,例如“2”。然后对标记为“1”的部分进行递归操作,同样分为四个部分。为了避免无限运行下去,当划分的空间足够小时,就可以停止递归操作了。(见图6.24)


<TABLE cellSpacing=0 cellPadding=2 align=center border=0>

<TR align=middle>
<TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/6.1/Image710.gif"></TD></TR>
<TR align=middle>
<TD colSpan=3><FONT color=#cccccc><B>图6.24 用四叉树来表示空间占用</B></FONT></TD></TR></TABLE>
  八叉树也使用相同的方法进行分割。唯一的不同之处就是每次分割都要分为8个部分。
  比较空间占用矩阵和四叉/八叉树方法,当场景空间占用比较稀疏时,后一种方法可以有效的节省存储空间。但是, 这种节省也带来了数据结构的复杂化。使用这种方法不会对渲染过程造成不变,相反,四叉/八叉树还会对它有所帮助。如果我们模拟动态的物体,例如爆炸,这时,物体的一部分会相对于其它部分发生移动,这样,结构树就会变得比灵活了。
  为了显示基于物体的体素,我们既可以使用从屏幕到世界的视处理方法,也可以使用从世界到屏幕的方法。对于前一种方法,我们经常要找到一个体素链,它与一个给定的射线相交。当体素半透明时(也就是许多颜色都表现在一个像素上),这一需要就会表现出来。考虑到每一个体素都是一个立方体的事实,要为占有矩阵与四叉树这两种表度方法提出策略以找出交点并不是一件困难的事。
  如果我们使用从世界到屏幕的方法,每一个体素都是一个立方体,都有6个面,这样,体素物体就可以用一般的多边形管道来显示了。它还需要一定的改进,因为要进行光栅化处理的面的数量已经变得很大。由于一些位于模型内部的体素完全被位于表面的体素遮挡住了,所以我们可以对所有的体素进行定位,并只对表面的体素进行光栅化。还有一种方法就是将体素当作正方形来进行光栅处理,而不管它的方位到底如何。这当然是一种对条件的放宽处理,因为一个立方体并不一定总是投影到一个正方形内,但是,如果我们假设体素足够的小,并且它们的投影可以与屏幕像素的大小进行比较时,这种方法还是可行的。正方形对于矩形屏幕边界来说是很容易进行裁剪处理的,并且也很容易进一步光栅化成一幅图象位图,这样,对于简单的图元,我们就可以加快整个体素化模型的渲染速度。

  <B>小结</B>
<FONT face=楷体_GB2312><FONT><FONT color=#993300>  我们讨论了几种不同的表现和显示虚拟模型的方法。对于不同的应用程序和渲染方法,可以使用不同的数据表示方法。线框模型的外表与真实情况相比有很大的失真,但是它仍然是用于许多情况。多边形逼近是一个很好的渲染方法,但是它不够精确并且不适于用来表现曲面。我们可以使用简单的曲面片来逼近复杂的表面。体素表示法适合于通过采样获得的模型数据,但是它的存储量比较大。
<FONT>  对于拥有多个图元的模型,我们已经假设可以通过单独显示所有图元的方法来进行显示。不幸的是,这种方法忽略了一个事实,那就有些图元可能会被其它图元部分或者是完全遮挡起来。模型的显示必须找到合适的方法来消除隐藏的表面,我们将在接下来的章节中进行介绍。</FONT></FONT></FONT></FONT><FONT face=楷体_GB2312><FONT face=楷体_GB2312><FONT face=楷体_GB2312> </FONT></FONT></FONT>

喜欢0 评分0
夜落了,风静了,我喜欢一本书,一杯茶,一粒摇曳的烛光...
游客

返回顶部