Adaptive Transparency

    最近看到一篇OIT的文章,文章里介绍了一种新方法实现OIT,文章可以在这里找到http://software.intel.com/en-us/articles/adaptive-transparency/

http://software.intel.com/en-us/articles/adaptive-transparency-hpg-2011。文章内介绍的方法把经典alpha blending的递归混合公式拆开,避开back to front的渲染限制,从而实现OIT

    首先回顾一下经典alpha blending公式:

C0 = α0c0

Cn = αncn + (1 - αn)Cn-1

其中,α代表该颜色的覆盖程度,取值[0,1],0代表全透明,1代表完全不透明。从公式可以看出,alpha blending就是用前景颜色按覆盖程度与背景颜色混合。所以,要得到合理的结果,背景颜色的存在是必要的,这也是back to front渲染限制的由来。

    记得MS在推广D3D11的时候,也提到使用compute shader达成OIT,其具体做法是:1.任意顺序渲染,把每个fragment(包括颜色和深度)记录到一个链表内(per pixel linked list);2.对每个像素对应的链表进行back to front的排序,使用alpha blending公式生成最终结果。

    Adaptive Transparency没有使用经典alpha blending公式,其理论如下:如果屏幕上某个像素由多个透明物体渲染混合而成,例如f由透明物体A,B,C渲染而得到(假设,C最远,A最近),那么f可以理解为:

f = Aca + Bcb +Ccc

其中cx代表物体X对像素f颜色的贡献值,取值[0,1]。并且,这里ca+cb+cc = 1。从上面的公式可以看出,无论物体的渲染顺序如何,都不会对最终像素的颜色产生任何影响,因为合成公式只是一个简单的加法运算。所以,现在的焦点就落在如果确定cx

    物体对最终像素颜色的贡献值cx可以理解为两部分:1,物体X本身的颜色的覆盖程度,即物体X的alpha值;2,物体X到视点之间的透明度,因为物体X到视点之间,可能还有其他透明物体,这些透明物体会阻隔物体X到视点的光线,从而削弱物体X对最终像素颜色的贡献。例如上面例子cc = αc(1 - αb)(1 - αa)。再观察,物体X本身的颜色的覆盖程度是固定不变的,而另一部分则会根据与视点的距离(即深度,z值)的变化而变化,那么这部分可以用一个关于z的函数表示:vis(z)。vis(z)是一个分段函数,上述例子里,vis(z)可能像这样:

所以,第i个物体对最终像素颜色分量可以表达为:coloriαivis(zi),那么,最终像素的颜色就是

 n

 coloriαivis(zi)              (1)

i=0

n表示最终像素由多少个透明物体混合而成。

    以上是理论,下面是实际操作步骤:

1任意顺序渲染,把每个fragment(包括颜色和深度)记录到一个链表内(per pixel linked list);

2,执行步骤1的同时,建立(维护或者更新)vis(z)函数,这个函数是每屏幕像素对应一个,当插入一个新fragment的时候,需要查找并更新这个fragment之后的透明度。另外,出于性能考虑,vis(z)的分段被限制在一定范围之内,例如16段,如果超出分段范围,就要对vis(z)进行压缩,剔除影响最小的分段;

3,执行一个screen space的pass,用公式(1)从per pixel linked list和vis(z)中拾取相应内容并合成最终像素。

    最后,这篇文章是思维模式创新的代表。解决问题时不要被传统思维禁锢。另外,这里提示一下,示例程序内Shaders/A-Buffer/FragmentList.hlsl就是per pixel linked list的实现,Shaders/AOIT/AOIT.hlsl是步骤2的实现,Shaders/AOIT/AOIT_Resolve.hlsl是步骤3的实现。

原文地址:https://www.cnblogs.com/rickerliang/p/3078027.html