chapter 8:金属
文章翻译
如果我们想让不同的物体有不同的材质,我们有一个设计的决策。我们可以有一个带有很多参数的通用材料,不同的材料类型仅取消其中的一些参数。这不是一个坏的方法,或许我们可以有一个抽象的材料类把行为封装起来,我喜欢后一种方法。在我们程序中,材料类需要做两件事情:
1.产生一束散射光线(或者说它吸入了入射线)
2.如果散射,表明光线需要衰减多少
这是之前建议使用的抽象类:
使用 hit_record 可以避免很多参数,因此我们可以在这里提供我们想要的任何信息,你也可以使用参数来代替,这是个人风格问题。 Hitables 和 materials 需要知道对方存在,因此存在循环引用的问题。在c++中,你只需要告诉编译器指针指向的是类," class material "在 hitable class 中如下所示:
我们所创建的 material 将会告诉我们光线如何与物体表面交互, Hit_record 仅是将一系列参数装进一个结构体的一种方法,因此我们可以作为一个整体传输这些参数。当一束光线击中一个表面(例如一个特殊的球体),当球体在 main() 被创建时,在 hit_record 中的材料指针将会被设置为指向球体所给的材料指针。当 color() 函数惯例得到 hit_record,如果光线发生散射,它可以使用材料指针的成员函数来的到散射后的光线。
对于我们已经有的漫反射案例来讲,它可以总是散射的同时并根据反射系数 R 进行衰减,或者它可以没有衰减的发生散射,但是表面吸收了系数为 1-R 的光线。或许它可以是这些策略的混合,对于漫反射材料,我们可以得到这个简单的类:
注意,我们可以仅以概率 p 的可能性发生散射,并根据系数 albedo/p 进行衰减,看你的选择。
对于表面光滑的金属,光线不会随机的散射,关键的数学是:在一个金属镜面上,光线是如何反射的?在这里,向量数学是我们的朋友:
红色的反射光线的方向是 (v + 2B) ,我们的设计是, N 是一个单位向量,但是 v 可能不是。向量 B 的长度应该是 dot(v,N) ,因为 v 指向内,我们需要一个负号:
金属材料仅使用这个公式进行反射:
我们修改 color 函数来使用这个:
你也需要修改球类来拥有一个材料指针来指向它,并添加一些金属球体:
这会产生:
我们也可以通过在一个小球体中为光线选择一个新的终点来随机反射方向:
球体越大,越会模糊反射方向,这表明添加一个模糊系数,这只是球体的半径(因此零是没有扰动的).需要理解的是 ,对于大球体或放牧光线来说,我们可能会散射在表面下面。我们可以仅让表面吸收那些光线,我们将限制球体的模糊系数最大值为1:
我们可以尝试让金属的模糊系数分别为0.3和1.0:
小结
这里讲了镜面反射和模糊镜面反射,区别是模糊镜面反射有一点偏移,这部分还算好理解