在刚才叙述的算 法中,我们用渲染场景的方式来正确渲染 fog volume 的后表面,这里我们可以利用同样的 技巧来正确渲染 fog volume 的前表面,算法描述如下: 1、 清空缓冲区。 2、 渲染场景到后台缓冲区 A, 用每个 pixel 的 w 值代替该 pixel 的 alpha 值。 激活深度测试。 3、 用相同的编码方式渲染 fog volume 的背面到缓冲区 A。 4、 渲染场景到后台缓冲区 B(或者在第三步之前拷贝 A 中的值) 。 5、 渲染 fog volume 的前表面。因为打开了深度测试,所以物体位于 fog volume 之后的点被 fog volume 上的点替代。 6、 用 B 减去 A 得到的值作为雾的浓度值进行后续处理。 相机在 fog volume 中的情况: 我们前面讨论的都是相机在 fog volume 外的情况,如果相机移动到 fog volume 内部, 这时的情形是什么样的呢?由于相机在 fog volume 内部,这导致 fog volume 的前表面被剔 除,上述算法的第五步失效(因为 fog volume 的前表面已经被剔除) 。最后渲染的结果是不 正确的,场景中有的地方有雾,有的地方本该有点雾的现在一点雾也没有。 解决这个问题的方法也很简单。前面算法的第四步是因为物体部分处于雾中而添加的。 当相机处于雾体中的时候,所有的物体都处于雾中,所以第四步可以完全跳过。 下面是渲染凸多面体雾的一个通常的算法: 1、 清空缓冲区。 2、 渲染场景到后台缓冲区 A,用每个 pixel 的 w 值代替 alpha 值,激活深度测试。 3、 渲染 fog volume 的背面到缓冲区 A。 4、 如果相机在 fog volume 体外,则渲染场景到后台缓冲区 B 中(或者在第三步之前从 A 中拷贝) ,否则,跳过这一步。 5、 渲染 fog volume 的前面到缓冲区 B 中, 如果第四步执行了, fog volume 的前表面将代 则 替物体处于 fog volume 后面的点,如果第四步没有执行,则这一步的执行效果被忽略, 因为 fog volume 的前表面已经被剔除。 6、 用 B 减去 A 得到的值作为雾的浓度值进行后续处理。 进一步的优化: 4 前面所述的是一些基本的雾模型。 有很多种方法可以进一步优化。 讨论最多的应该是如何提 高精度。现阶段的硬件的 alpha 管道只有 8 位,这限制了某些应用,如铺满整个地面的一大 片雾。解决方法之一就是本文开始提到的纹理雾。用 1D 的纹理模拟 fog table,每个纹元可 以包含更高的精度。这种方法受到纹理大小的限制。当精度的问题解决后,我们就可以在现 有 8bit 的机器上渲染凹多面体雾。第一种方法是把凹多面体分割成一系列的凸多面体进行 渲染,第二种方法是累加进入的点去减出去的点。后一种方法由于受限于 pixel shader 而很 难实现。 下面进一步阐述如何在 8bit 的 alpha 管道上获得更高的精度进行凹多面体的渲染。 凹多面体的处理: 在凸多面体的情况下计算进出 fog volume 的距离是非常简单的,但是对于凹多面体就 不行了,因为一束光线有可能进出 fog volume 两次以上。解决方法如下图所示: 图四:(B1-A1) + (B2-A2) = (B2+B1)-(A2+A1) 从上图可以直观的看出, 这相当于把一个凹多面体分割成了一系列凸多面体, 然后进行 相加。8bit 的精度是不够的,每增加一位的精度可以增加一次加减法运算,可以实现更复杂 的雾体。 在这里,凹多面体有一个前提限制。它必须是连续的、方向性的体,即不允许这个体中 有孔(洞) 。换句话说,一束光线进入体 n 次,出来也是 n 次。 获得更高的精度: 现在的 32 位机,每个管道实际上只有 8 位。并且只有在 alpha blending unit 中,雾的深 度才可以累加。