与DirectX,OpenGL等图形渲染管线一样,pbrt中也使用了材质的概念,它的底层是BRDF和BTDF,它的核心作用是确定物体表面在某光线照射下所呈现的颜色。实现这一功能需要完成两个方面的工作,第一个工作是给出物体表面的反射特性和透射特性;第二个工作是讲该光线经过这一物体表面后所表现的颜色计算出来。大部分图形引擎或图形API都把这两个工作整合的到一个模块中。但在pbrt中,考虑可能需要针对第二项工作开发不同的解决方案,因而pbrt中把这两项工作放置于不同的模块中。
由于物体的材质同时涉及BRDF和BTDF,两者形式类似,使用方式类似,因而作者引入一个新类BSDF,双向散射分布函数,同时包含BRDF和BTDF。pbrt的开发者认为,在一次渲染中,使用的brdf和btdf数量有限,所以对存储他们指针的数组取了一个数据规模的上限。开发者这样做,我猜测是要避免动态内存分配出现。这样做也是合理的,不过要根据场景的复杂程度,设置不同的数据规模上限。由于BRDF和BTDF一般都是在局部坐标系中定义的,且以xy为表面,以z轴正方向为法线方向,所以还需要构建光线方向在世界坐标系和局部坐标系间相互转换的变换矩阵。另外还需要注意的一点是,为了实现更为丰富的效果,比如凹凸贴图,在使用材质时涉及几何法线方向和着色法线方向,两个法线方向可能并不重合。在实际计算BRDF和BTDF时,使用的是着色法线。这样一来,再带来更丰富的效果的同时,也会带来在一些情况下该显示的反射光线未显示或不该显示的反射光线显示出来的问题。解决这一问题的方法是首先按几何法线确定是否应该显示反射光线,如果是再按着色法线计算BRDF。
考虑了上述一些特殊问题后,就可以实现材质的接口了。材质的接口的功能就是返回表面某处的BRDF和BTDF,供后续光照计算使用。当然,它还涉及了一些存储空间管理功能。此外,它只是一个接口,还需要针对不同的材质进行具体化。
(1)MatteMaterial.这种材质完全是基于Oren-Nayar模型实现的漫反射材质。它引入了两个变量,一个是漫反射系数,一个是表面粗糙度。当表面粗糙度系数减小至0后,它就成为Lambertian材质。事实上Oren-Nayar模型本身也具有这一特性。
(2)PlasticMaterial。这种材质实现了漫反射和光泽散射的合成效果。它一共使用了三个参数,其中两个参数分别表示漫反射和光泽散射的强弱,另一个参数被称之为粗糙度参数,用于表明高光范围的大小,粗糙度参数越大,高光范围越大。这里的光泽散射在一定程度上可以视作镜面反射了。按pbrt开发者的描述,这种材质虽然和上一章的菲涅尔入射模型都是实现的都是漫反射和镜面反射的组合,但两者的模型不同,效果也有差异。
(3)混合材质。存储两种不同的材质,并根据某种算法对两种材质进行缩放后求和,作为最终返回材质。
(4)其他材质:测算材质(各向同性的规则采样和不规则采样数据);Glass(按菲涅尔公式实现镜面反射和透视分配);Metal(基于导体的菲涅尔方程);Mirror(全镜面反射);Substrate(菲涅尔入射模型);SubSurface和KdSubSurface(BSSRDF);Translucent(漫反射、光泽镜面、透视);Uber(高度参数化的混合材质)。