Interactive Order-Independent Transparency 论文解析
程序员文章站
2023-12-29 11:43:40
...
透明问题
透明问题是图形学中非常重要且麻烦的问题,我们采用延迟着色的方式就很难实现透明融合的问题。因此有非常多实现透明融合的算法,但主流的大致分为两类:
- 一类为顺序有关的混合算法:即我们先将物体按照从远到近的顺序进行排序,然后这样就可以按照下面的公式来进行融合。
- 另一类为顺序无关的混合算法:排序是一件非常耗时的操作,就算最快的快排也的O(nlogn)的时间复杂度,在我们实时渲染的领域,一帧只有16.6ms的时间,对于大量物体排序算法的时间显然是不可以接受的。因此现在不用排序算法的混合算法是主流。
顺序无关的混合算法
本文应该算是顺序无关算法的开山之作,虽然本文在实际应用中还是非常非常耗时的,但在这篇文章所带来的改进才让我们现在可以实时渲染半透明物体成为了可能。
本文的思路非常简单,只不过实现的时候有点小问题。本文思路就是:采用对一个物体渲染多遍到帧缓存的方式,除了第一遍以外每一遍渲染都需要剔除深度大于或者等于(这个等于很重要)上一遍中的点,而对于第一遍只需要正常的渲染即可,不需要做任何额外的操作。如此一来每一遍都渲染的比下一遍深度更大。
从上面的图可以看出每一遍渲染的深度都不一样。有人可能会问为什么可以这样,其实有个关键问题是我们渲染物体不是实心的物体,对于一个正方体,如果我们剔除掉了正面,那我们就可以直接看到后面。
因此渲染一遍的过程如下所示
- 1:先判断是不是第一遍,如果是则正常渲染。
- 2:如果不是第一遍,则将上一遍帧缓存中的深度信息传入,然后在渲染过程中对于每一个着色点的XY坐标都要将其转化到(0,1)范围中,这非常重要,因为帧缓存是一张和屏幕一样大的纹理而已,而我们渲染的物体的某个着色点改如比较他的深度信息呢,只有将他的XY坐标都转化到(0,1)范围中,这样我们就可以用转化后的坐标作为纹理采样的坐标去帧缓存中的深度贴图中进行采样,如果不这样我们根本不知道这个着色点改与谁进行深度比较。(这非常重要)
vec2 deptc = vec2(gl_FragCoord.x / u_Width, gl_FragCoord.y / u_Height);
- 3:如何我们进行深度比较,如果这一遍的着色点深度大于或者等于了上一遍的深度,就进行剔除(discard)即可。
if(gl_FragCoord.z <= (texture(u_DepthTexture,deptc).r) + Bias)
discard ;
- 4:如此一来我们就可以获得一张比上一遍深度更小的帧缓存了。接下来大家可以渲染完之后再进行融合,那么这样就需要存储所有的帧缓存,这样可能有些耗内存,所以在渲染完一次之后直接就进行混合,这样就只需要两个帧缓存,一个用来存上一遍的,一个用来存本次的,可以减少些内存。不过这都不重要,毕竟现在显存都是8G起步。
Color_ = vec4(texture(u_BlendTexture,v2f_TexCoords).rgb * u_BlendFactor + (1 - u_BlendFactor) * texture(u_ColorTexture,v2f_TexCoords).rgb , 1) ;
这样一遍渲染就完成了,渲染的次数可以由大家自己设置。
可以看到渲染次数增多半透明效果越好。
结果
代码链接 https://github.com/AngelMonica126/GraphicAlgorithm/tree/master/TestCase_005_A