之前在图形学中我们学过参与介质(participating media)的实现原理,比如烟雾,这一节我们来实现一个恒定密度的参与介质。
1 恒定密度介质
因为我们之前所有的实现都是基于“表面”的,而参与介质是基于“体积”的,这二者之间还是有很大的不同的,但是一个简单的办法是可以把整个参与介质看作是由表面构成的,但这个表面可以在物体内部,只要在一定范围内的点都算作该物体的表面,所以都可以和光线发生作用。
我们在图形学中学过,光线穿过烟雾会在其内部发生各种散射,我们可以用一个概率模型来描述这种过程,如果一个烟雾的密度越大,那么光线在其中发生散射的几率也就越大,如果光线越稀薄,光线就越有可能直接穿过介质而不发生散射,如下图:
我们认为光线在烟雾中走过 $\Delta L$ 距离发生散射的几率是:
$$
probability = C·\Delta L
$$
其中 $C$ 与介质的密度成正比,于是对于一个随机数就可以用上面的式子计算得到概率,并把这个概率认为是散射发生的距离。如果散射发生的距离大于光线在介质中传播的距离,说明光线没有击中介质,而是直接穿过。
因此一个恒定密度的介质只需要一个密度和边界就可以描述,边界使用另一个物体来确定,相当于该物体形状的烟雾,一个恒定密度的介质类的实现如下:
1 | /* |
上面的实现中我们默认光线一旦出了介质就不会再在介质中弹射了,因此只适用于凸多边形物体,不适用于凹多边形物体。其中控制光线向各个方向等概率散射的材质在 material.h
中定义:
1 | // 各向同性材质 |
2 用烟雾渲染 Cornell Box
我们使用上面实现的介质新建一个 Cornell Box 场景:
1 | // 烟雾Cornell Box场景 |
主函数修改:
1 | int main() { |
得到的效果: