次表面散射(Subsurface Scattering) |
作者:何咏 日期:2009-2-25 点击:1923 |
如需转载本文,请声明作者及出处。 |
次表面散射是光射入非金属材质后再内部发生散射,最后射出物体并进入视野中产生的现象。次表面散射材质是高质量渲染中最复杂的材质之一,一个重要原因在于此表面散射物体内部的任何一点的光照度取决于体内其他点的光照度和材质本身的透光率。抛开材质本身的性质不说,这一特性使得次表面散射的光照方程变成一个复杂的微分方程,求出此方程的准确解是十分困难的,另一方面,材质本身可能具有复杂的各向异性和不均匀密度等性质,因此计算这样的积分变得非常困难。 次表面散射方面的研究,比较好的是Jensen的文章"A Practical Model for Subsurface Light Transport",该文提出了一个较为全面的次表面散射模型,将次表面散射建模成一个双向次表面散射反射分布函数(BSSRDF)。 初看这些文章,很容易不知所云,对于像我这种数学感还没有那么强的人来说,直接理解这些公式有一定难度。现在看来,PBRT(Physics Based Rendering: From Theory to Implementation)确实是一本好书,看完PBRT中关于Volume Integration和Participating Media等方面的讲解后(12章和16.7节),终于明白了其中的道理,并且反过来理解了Jesen等人的Paper。 不过我实现的依然只是PBRT中所讲到的Single Scattering,这只是模拟了0阶(自发光)和1阶(来自光源的直接照明贡献)所产生的散射效果,不过在大部分情况下已经比较接近完整模型。 这里用比较浅的语言讲一下大致的做法。首先,看一看原始的体光照方程:
看起来很复杂,不过这个方程没有任何实际意义。它无非是说,对于散射物体内部的任何一点x,在该点的沿着ω方向散射光强微分等于x处的散射光强乘以灭绝因子σt(一个反应散射物体透光度的系数,系数越大越不透明),再加上该点附近无限小区域内各个方向上的点能量与该方向上的相位函数的乘积再乘以这一点的散射系数,外加该点处ω方向的入射光强。 式子中间的积分,表达的是散射体中各个相邻点的能量的传播关系,而Q则是直接因为外部的光照产生的。因此Q描述的实际上是一阶的散射(即没有通过任何中间点的散射),所对应的光路是光源-->体衰减-->x点-->接收点。 通过对式子各个部分细化描述后迭代,可以求出逼近真实的解。 大部分情况下,我们面对的都是光在均匀各向同性介质中的散射,例如塑料、肥皂、翡翠、大理石、各种饮料甚至人的皮肤等,基本上都属于此类。均匀,指的是物体内部密度均匀,因此各种波长的光在散射体内部的任何位置发生散射的概率相同;各向同性,指的是介质在任何方向上的散射强度都相同。 在这样的假设下,就可以大大地简化计算过程。如果只考虑一阶散射(来自光源的直接光照)的话,计算变得非常简洁。首先,不再计算中间的积分,并且Q(x,ω)可以表示为: 此处,p是相位函数,Lri是ω'方向上经过散射体衰减后到达x点的光照度。 由于我们假定散射体各项同性,因此各方向上的光照产生的散射贡献相同,因此相位函数p变为一个常数,由于积分的计算要求p是单位化的,因此p=1/(4*Pi)。 这样一来,假设现在光线追踪器追踪一条光线碰到了散射物体的表面上的P点。要计算P点的最终颜色。先像往常一样计算P点的光照,然后计算P点的散射项,计算完后将两者相加。 要计算P点的散射项,需要确定当前光线在散射体内穿过了多长的距离。这只需要沿着该点继续向前追踪,直到找到光线离开物体的点,通过两个交点的参数可以确定光线穿越物体的厚度。我们要计算的是散射体内沿着光线方向上的每一个点的散射光。由于点越深,由于光线在物体内部的衰减作用,该点对最终结果的贡献越少。在均匀各向同性介质内,光强随距离衰减的关系是: σt是材质的灭绝因子(Extinction)。灭绝因子越大,衰减越厉害,越不容易透光。 散射体内每一点的散射光强已由Q(x,w)给出,该式中的积分应该如何算呢。如果我们只考虑直接光照的影响,那么简单地将各个光源在改点的亮度累加起来就得到了该点的散射光强。所以Q(x,w)即是: 于是P点的最终散射项计算公式就变成了: 就是沿着光线方向上每一点计算Q(x,w)。式子中的积分变量x是当前积分微元到P点的距离。d是光线在散射体内的长度。 这个积分已经非常简洁,可以使用Monto Carlo方法计算这个积分。要注意的是式中Ld的值并不是光源的亮度,而是光源的亮度经过散射体衰减后到达x点的亮度。这个亮度的计算可以由x点沿着到光源的方向发射一条射线,求出这条射线与散射体表面的交点,进而可以求出光源到达x点经过了多厚的散射体,然后将这个厚度带到Tr中算出衰减乘到光源的亮度上。 另外一方面,如果要考虑物体本身的自发光,只要在积分中增加自发光项,使最终积分变成: 这基本上可以说是次表面散射一个非常大的简化了,但是效果却很好。 以下是我的实现,至于实现的时候遇到的很多具体问题,这里就不说了,都是小问题和工程性问题。 图一: 图2: 有次表面散射和无次表面散射的对比: 效果非常明显。 而另一个效果,称为体积光照(Volumetric Lighting,即丁达尔现象)的渲染,可以归结为对体积雾的渲染。渲染时,将光束建模为次表面散射物体,不同的是当光散射出物体后继续追踪,然后将最终颜色混合起来。以下是体积光照的效果图。 |