半透物体的实时渲染是一件让游戏开发者很头疼的事情,如下图所吐槽。需要排序,一旦出现geometry交叉的情况,半透计算还必出错。
这几天从理论到实践地研究了下所谓的OIT技术,对半透问题有了一定的了解,现作个记录。
最简单的OIT方法是Nvidia 2001年的那篇老paper(“Interactive order-independent transparency ”)介绍的depth-peeling。真的是很简单的方法,因为连我都看得懂!核心算法如下:
看得出来,每个半透物体需要多个pass渲染,每个pass剥离一层最近深度,同时该方法需要2个depth buffer的协作。如果用D3D或opengl来实践的话,必然比较麻烦,你会发现原paper一共10页,大部分是在讲怎么用opengl的trick来表达出算法。所以我在自己的soft renderer中进行了实践,事实证明真是简单的一逼,软渲就是灵活自由,绝对是预研的正确选择。
下面是实践的过程。测试场景是2个半透的双面的交叉的teapot~
-
Solid View
这是非半透渲染方式,提供遮挡关系供半透渲染时参考。可以得出我们期望的正确结果是,左边圈中部分应该是绿里透红,右边圈中部分应该是红里透绿。。
-
Normal Transparency
这是普通的半透渲染。可以看到,绿茶壶的茶柄是绿里透红,看上去像是该部分在红茶壶的前面,这是不正确的。
-
OIT with 4 layers
这是4层depth peeling的结果。注意观察绿茶壶的茶柄部分是红里透绿,像是处在红茶壶的内部,这才是正确的。
ps:唉,我的软渲光栅化还是有问题,那些点线。。暂时解决不了,真头疼,不要在意那些细节。。
再看个例子,sponza场景的花坛,它整体是一个模型。
下图左边是max中实时渲染的,右边是render出来的,不管是ray trace还是depth peel,肯定是准确的。
下面是我软渲中的对比(考眼力,看轮廓,一致的才对):
接下来有空研究下那个什么per-pixel linked list OIT和DXSDK sample中的硬件实现方式。