阅读:2182回复:2
3D图形编程指南9续 - 光线
<b>8.3.2 漫反射
</b> 在真实世界中,我们经常见到的光线都是由某些固定的光源发出的,它们总是从某一个方向照射到物体上,而不像我们在讨论环境光时那样不用考虑光线的方向。为了模拟这种情况的反射效果,我们在考虑反射表面属性的同时,还要考虑光源的位置和类型。我们将光源分为点光源、聚光源以及方向光。正是这些光源在真实世界中照亮着各种有材质的物体。漫反射模型就是指物体表面把这些光线均等的反射到各个方向(如图8.8所时)。 <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image551.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.8 漫反射</B></FONT></TD></TR></TABLE> 这一个模型主要是针对粗糙表面而建立的。如上图所示的粗糙表面,表面上每一个小区域内都有大量的朝向各个方向的小的表面,因此它的反射也是朝向任意方向的。这样,在任何方向上反射后的光线的亮度就只依赖于有多少光线照射到表面上。当然,它是光源与表面之间方向的函数。如果表面朝向光源方向,与灯光的方向正交,那么反射的光线亮度是最大的。 <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image552.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.9 漫反射图示</B></FONT></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/8.1/Image553.gif"></TD></TR></TABLE> 从公式我们可以看出,当入射光线与反射表面正交时,反射达到最大值,并随着入射光线与反射面夹角的减小而逐渐减小。同时要注意,当角度大于<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image554.gif">或者小于<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image555.gif">时,此光源的光线没有照射到该表面上,因此也就没有反射。但是如果只从公式来看,我们得到的值将是负值,这是违反物理常识的,因此要将它设为0。 从实际情况来考虑,上面的情况也会导致一个问题。当环境中只有一个直射光源时,那么所有背向它的表面都将是黑暗无光的。但是在实际情况下,总会有一些光线通过多次反射能够到达上述表面。而我们使用的这个漫反射模型只考虑了由光源发出的光线,没有考虑到经过其它表面反射的光线。在实际应用中,我们对上述模型要进行一定的调整,用环境光来模拟多次反射的情况: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image556.gif"></TD></TR></TABLE> 得到修正后的模型称为<I>Bouknight</I>照明模型, 是根据它的发明者来命名的。图8.10显示了使用这个模型来进行渲染所得到的效果: <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image557.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.10 漫反射或Bouknight照明</B></FONT></TD></TR></TABLE> 在使用这个模型时,假设已经知道了表面和光线的属性,但仍然需要有一个方法来计算<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image558.gif">值。在前面的章节中,我们已经认识到了法向量在描述一个平面的方向时的作用。那么现在,让我们用一个单位向量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image559.gif">来表示光源的方向。根据定义,两个矢量的标量积(scalar product)公式如下: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image560.gif"></TD></TR></TABLE> 式中<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image561.gif">和<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image562.gif">是矢量的模。假设上述两个矢量都是单位长度的,那么我们就可以套用上面的公式,用光源方向矢量和需要计算反射光亮度的那一点处的面法向量来计算<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image563.gif">值。这样, Bouknight照明模型就可以用下式来代替 : <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image564.gif"></TD></TR></TABLE> 公式中,根据我们使用的颜色方案的不同,各项可以是标量(非彩色光情况下),或者是三维矢量(RGB颜色模式下)。 在前面几章中,我们已经介绍了法向量的计算方法。但是,直到目前为止,我们还从来没有要求过法向量必须是单位长度的。实际上,在进行背面剔除(back-face culling)或者是建立平面公式时, 矢量的长度是没有特别要求的。但是在进行照明模拟时,我们就需要用到单位长度的矢量。很明显,我们只要用矢量除以它当前的长度就能使它单位化了: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image565.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/8.1/Image566.gif"> <IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image567.gif"></TD></TR></TABLE> 在计算单位矢量的过程中,唯一比较困难的地方就是计算平方根了。它的计算量是比较大的。 有一个快速的计算平方根的方法,称为二分搜索算法(binary search algorithm)。在这个方法中,我们先假设一个结果,然后计算它的平方。如果平方值比我们讨论的值大,那么我们假设的平方根也就要比真实值大。相反,如果平方值比我们讨论的值小,那么我们假设的值也就比真实值小。这样,我们就可以使用二分搜索技术,每次将两个假设值之间的距离减小一半,直到它们的距离小于精度要求时,我们也就得到了满足精度要求的平方根值。尽管这种方法是比较快的,并且只是一些迭代过程,但是它在每一步迭代时仍然要进行平方运算。在许多情况下,空间中物体的坐标值都是整数的,并且在矢量长度的计算过程中,我们也希望结果能是整数的。这样,我们就可以充分利用上述算法中的假设来分析应该设置哪些结果位。 利用上述算法,我们先估计一下结果可能的最高位,然后为最高位假设一个值,并计算它的平方。由于只设置一个位,因此它的值就应该是2的幂,这样,就可以通过移位的方法来进行平方运算。得到平方值之后,如果它比我们讨论的值大,那么这一位就不是最终结果中的位,相反,如果小于讨论值,那么它就是最终结果中的位。接下来设置次高位。由于这一步中的估计值不止一个位,因此不能使用移位的方法来进行平方运算。我们可以用下面的公式来计算平方值: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image568.gif"></TD></TR></TABLE> 如果<I>a</I>是第一步得到的估计值,<I>b</I>是当前位的假设值,那么<I>(a+b)</I>就是当前的假设值。这个新的假设值由三个部分之和组成。第一部分是上一步迭代中的平方值, 后面两部分都是两个2的幂相乘得到的值,这样,这些部分都可以通过移位来进行计算。得到平方值之后,检查这一位是否是结果中的位。然后我们要处理下一步迭代,同样,我们会遇到与上一步一样的情况,我们可以按照相同的方法来处理,这样就能得到这一步的结果。以此类推,直到计算完所有可能的位之后,我们也就得到了平方根的整数近似值。程序清单8.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/8.1/Image569.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>程序清单8.1 按位迭代计算平方根</B></FONT></TD></TR></TABLE> 要注意,在表7.1所列出的代码中我们认为整数占据了32位,因此,我们在估计最高位时,要保证它的平方值不会超过可能的精度。 <B>8.3.3 镜面反射</B> 在真实世界中,不仅要使用漫反射模型,同时还要接触大量镜面反射的情况。通过镜面反射,可以看到物体表面的高光,或者是光源在光亮物体表面上的反射。 <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image570.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.11 镜面反射</B></FONT></TD></TR></TABLE> 用来描述镜面反射的模型需要知道光源和观察者的位置,以及反射表面的朝向。当观察者位于一个合适的角度时,可以看到物体表面上某个地方的高光。当观察者移动时,可能还会看到从表面上其它地方反射的高光。对于大多数的材质来说,镜面反射时,光线的波长不会发生很大变化,因此高光的颜色与光源的颜色仍然是一样的,而不会根据反射表面的颜色发生变化。 通常,描述光亮物体的反射情况是很复杂的。在计算机图形学上,我们一般只使用一种描述镜面反射的模型,<I>Phong</I>照明模型,它是根据其发明者Phong Bui-Tuong来命名的。这一模型适合用来描述不太完美的反射表面的反射情况。当我们接近反射角度观察时,根据这一模型得到的镜面高光与光源的波长成分是一致的。当观察者从镜面反射的方向逐渐离开时,反射光线的亮度也逐渐减小(如图8.12所时)。 <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image571.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.12 镜面反射图示</B></FONT></TD></TR></TABLE> 亮度的减少量大约是<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image572.gif">,<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image573.gif">是一个标量系数,它表示了入射光线反射的百分率。由于反射光线的波长成分与光源的一样,因此对于任何颜色模型来说,这个系数都是标量。公式中的<I>n</I>表示了表面的光亮属性,它的范围可以从1到无穷。不太光滑的表面需要较小的指数,这样反射得到的高光亮度衰减就回大一些,高光也就会暗一些。相反的,一个比较理想的反射面所要求的指数就要很大,这样高光才会比较强烈。 对于非理想反射面来说,它的反射中既有镜面反射成分,也有漫反射成分。这样,就要对Phong照明模型进行一定的修改: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image574.gif"></TD></TR></TABLE> 注意,我们仍然使用了环境光来模拟多次反射得到的效果。下图显示了上面模型的效果: <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image575.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.13 Phong照明</B></FONT></TD></TR></TABLE> 在上面公式中,我们需要计算<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image576.gif">的值。我们可以使用前面提到的标量积的方法来计算它,这里要用到两个单位矢量,一个是表示镜面反射方向的<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image577.gif">,另一个是指向观察者方向的<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image578.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/8.1/Image579.gif"></TD></TR></TABLE> 但是在这个公式中, 还要使用表示反射光线方向的矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image580.gif">。在镜面反射模型的图示(图8.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/8.1/Image581.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.14 镜面反射图示</B></FONT></TD></TR></TABLE> 从图8.14中可以看到, 矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image582.gif">是矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image583.gif">和<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image584.gif">的和。矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image584.gif">又是矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image585.gif">在法线方向上的投影。投影的长度可以用<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image586.gif">来表示,<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image587.gif">可用标量积来进行计算。由于<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image588.gif">和<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image589.gif">都是单位长度的,所以我们可以用<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image590.gif">来表示矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image591.gif">的长度。而<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image591.gif">本身就可以表示为<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image592.gif">。同样,我们用<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image593.gif">来表示矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image594.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/8.1/Image595.gif"></TD></TR></TABLE> 将上式代入Phong照明模型的表达式: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image596.gif"></TD></TR></TABLE> 这个公式的计算量是很大的,特别是式中有大量的矢量点乘。在实际应用时,我们经常用一个不太严格的公式来替代它。当观察方向接近反射方向时我们不再进行测量,而选择在表面的朝向变得能够对观察者产生高光时进行测量,这时,我们就要考虑一个新的夹角,即表面法向量与半程矢量(<I>half-way</I>)<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image597.gif">间的夹角(图8.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/8.1/Image598.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.15 镜面反射的替代公式</B></FONT></TD></TR></TABLE> 矢量<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image597.gif">刚好位于光源方向与指向观察者方向的中间方向上。这样,当它与法向量一致时,反射方向也就与指向观察者的方向一致了,我们就可以观察到镜面高光。这时,我们用下式来表示Phong照明模型: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image599.gif"></TD></TR></TABLE> 使用这个公式,我们可以减少一些计算量,因为计算<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image600.gif">要比计算<IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image601.gif">相对容易一些。还有一种减少计算量的方法,就是假设光源和观察者都位于无穷远处,这样半程矢量就会近似不变。但是,这样对于具有交互性的程序来说并不是一件好事,因为镜面高光将不会按我们设想的那样随着观察者的移动而发生变化。 我们还应注意到,这两个公式是不相等的,它们也都无法描述反射的真实物理过程。但是,既然我们的目的只是要表现出一个足够真实的虚拟场景的话,那我们也就只好接收这样的模型,因为它们的计算量是我们现在的设备所能够接受的。 对于这个模型,还有许多改进的方法。有一些模型加入了一些对非反射现象的考虑。例如可以考虑光源,还有大气衰减等。对于光源来说,由于我们使用的是点光源,因此在各个方向上的辐射能量都是相等的,并且形成了一个球面,这样,随着距离的增加,能量也将会随之衰减,并与距离的平方成反比。对于大气衰减来说也是一样,当光线穿过统一的介质时,有一部分会被吸收掉,因此亮度也会随着距离的增加而减小,并且与距离成反比。我们还可以在公式中考虑光线的传播问题,这对于模拟透明或半透明物体是非常有用的,例如水或者是玻璃。增加所有这些效果对于更加真实的描绘场景无疑是一件好事,但是我们强调一点,那就是各种效果的使用要通过对实际效果的试验比较而不是单纯的分析来决定。 <B>8.4、在屏幕到世界(<I>screen to world</I>)中观察照明</B> 迄今为止,我们只讨论了光源与被照亮物体之间的相互作用。然而在实际生活中,经常会有多个光源与多个反射物体,它们彼此之间以各种方式相互作用和影响。因此,处理整个虚拟场景的光线就要使用全局照明模型。在这一部分中,我们将讨论如何将一个全局照明模型添加到屏幕到世界以及光线投射过程(ray casting)。当我们以屏幕到世界用于计算可见性和照明时,这种算法经常被称为光线跟踪(ray-tracing),以便与仅应用于可见性判断的光线投射方法相区别。 在屏幕到世界中使用照明模型,它的方法是比较一致的。我们可以回想一下,在这种观察方法中,每一个像素将有一束光线投射到屏幕上,这样就可以来表现可见场景了。然后对所有分隔表面进行检查并选择离观察者最近的一个来进行显示,完成可见性的判决。 要增加照明信息,就要确定分隔表面的属性,例如它的法向量、材质等。这些属性与光源属性、位置、亮度等相互结合,向我们提供了应用照明模型的一些信息。在有多个光源时,它们的效果将会相互叠加。在前面的图8.7、8.10和8.13中,我们分别对环境光、Bouknight和Phong等区域照明模型分别使用了光线跟踪算法。 但是上述的区域光照模型只考虑了一个单独的对象和光源之间的关系,没有考虑由于多个物体的存在而产生的效果。例如,一个光源可能不能照射到某个点上,这样,在这个点上就不会产生阴影。同样,有一些物体可能不是由光源所照亮的,而是由一些反射的光线照亮的。 幸运的是,我们把应用于可见性判决的光线跟踪算法进行一些扩展,使它能够处理全局照明的问题。我们要考虑两种效果,第一种是在要进行光线照明模拟的点上检查光源的可见性。我们从这一点到光源投射一束光线,它叫做阴影射线(shadow ray),通过它我们来进行光源的可见性判决。如果这束光线在到达光源之前穿过了几个表面,那就表示光源被遮挡住了,也就不用考虑该光源在这一点的照明问题。下图显示了这一过程: <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image602.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.16 计算阴影</B></FONT></TD></TR></TABLE> <B></B> 要注意,我们要找的是位于光源和该点间的第一个交汇点。因此,在找到第一个交汇点之后,就可以停止检查。还有一点要注意,那就是不要考虑阴影射线位于光源和该点之间以外的部分。我们可以构造一个有方向的矢量来完成上述任务, 这个矢量是光源位置与给定点之间的差分。使用这个射线,位于该点之前的交叉点的参数t的值将会是负的,而位于光源之后的交叉点的t值将会大于1。 增加了对阴影的考虑之后,场景的真实感得到明显的增加。图8.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/8.1/Image603.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.17 考虑阴影的光线跟踪</B></FONT></TD></TR></TABLE> 观察图8.17,我们可以看到,所有的阴影都很明显,刚好划分出了照亮区域和阴影区域。但在许多真实环境中,阴影与照亮区之间都有一个过渡区,这主要是由于真实世界中的光源并不是理想点光源所造成的,它们总有一定的面积。为了更加接近真实环境中的实际阴影效果,在进行计算时不仅要考虑是否能够照射到,还要考虑有多少光线照射到的问题。这样,位于阴影边缘区域的部分就会有一定的过渡效果。 我们已经注意到,一个点的照明不仅要考虑光源的直接照射效果,还要考虑反射光对该点的照明效果。这样,我们在考虑照明模型时就要将直接照明和反射光照明两部分都加入进去: <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0> <TR align=middle> <TD><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image604.gif"></TD></TR></TABLE> 在使用通用的Phong照明模型和特殊的镜面反射时,我们可以使用一种被称为递归光线跟踪(recursive ray-tracing)的方法来找到上述的反射光线对光照模型的影响。在镜面反射情况下,总有一个主要的反射方向。以前,我们通过检查这个方向来判断一个点是否能产生镜面高光。在考虑反射光的情况下,我们还要通过检查这个方向来判断是否还有其他光线能够在这一点产生出镜面高光。这样,通过递归使用光线跟踪算法,我们投射出一个沿着反射光方向的射线,就可以完成反射光线对物体照明的判断。下面的图8.18显示了上述计算阴影以及反射光线的过程。 <TABLE cellSpacing=0 cellPadding=2 align=center border=0> <TR align=middle> <TD colSpan=3><IMG src="mk:@MSITStore:E:\3D图形编程指南.chm::/3D图形编程指南/image/8.1/Image605.gif"></TD></TR> <TR align=middle> <TD colSpan=3><FONT color=#cccccc><B>图8.18 计算阴影和环境反射</B></FONT></TD></TR></TABLE> |
|
|
1楼#
发布于:2004-06-04 20:44
tt
|
|
2楼#
发布于:2004-06-05 11:25
没看到图
|
|
|