水面材质在三维可视化场景中的使用非常广泛。水面材质非常重要的一个光学特性就是反射倒影,有了倒影的加持能使水面更加逼真的渲染出来。本文主要讨论水面材质中倒影的渲染方法。
要有倒影,必须先有水面,第一步要做的就是确定水面所在的平面几何体。以坐标原点到水面垂线段的方向和距离确定唯一的一个反射平面。
图1 平面定义
有了反射平面后,以反射平面为镜像平面确定反射相机的位置,反射相机的方位角(heading)、翻滚角(roll)保持不变,俯仰角(pitch)取反。
图2 构建反射相机
在渲染正常场景之前,用反射相机离屏渲染拍摄出一张反射纹理,由于反射相机相对原始相机位置和朝向都发生了变化,因此拍摄前需要更新视图矩阵。
图3 反射相机拍摄的反射纹理
在片元着色阶段,把 [ -1, 1] 的屏幕坐标转换为 [ 0, 1 ] 的纹理坐标去反射纹理上取值,和原始水面材质的颜色做线性混合就可以看到倒影效果了。
图4 反射纹理作用在原始水面材质上
但是图3和图4有点奇怪,小汽车是被水体淹没了的,为什么我们能从倒影中看到汽车的底盘呢?这显然是不正确的。之所以出现这样的错误是因为反射相机位于水面下方,它会不加删选地拍摄所有位于视锥体范围内的物体。
解决方案是通过 “斜视锥体裁剪” 算法修改反射相机的投影矩阵,以改变近裁剪面的位置,使得近裁剪面为水面,这样水面下方的物体就不会被拍摄到,也就不会出现在倒影中了。
图5 “斜视锥体裁剪”修改近裁剪面
图6 指定水面为近裁剪面拍摄到的反射纹理
图7 正确的水面倒影效果
至此得到了一汪平静的水面,如果能让水面倒影波动起来,效果是不是会更好些! 这很容易做到,在片元着色器里给反射纹理的纹理坐标值一个随时间变化的噪声增量就可以了。
图8 水面倒影的波动效果