zoukankan      html  css  js  c++  java
  • 再谈光子映射

        在前一篇文章中提到了光子映射算法具有高效,扩展性好,能轻易捕捉到各种光照效果(比如Monte Carlo ray tracing不易捕捉到的SDS路径),但是它也存在很多问题,比如它本身是一个有偏的算法,boundary bias和topological bias通常能造成肉眼可见的artifact,这主要表现为灰暗的墙角,错误的颜色辉映以及漏光等现象。   

        针对这一问题,Havran等人在05年提出了以搜集光子射线代替搜集光子本身来解决boundary bias,该方法在采样点切平面上创建一个圆形区域,经过此区域的photon ray将被搜集到,但是为了高效地进行photon ray gathering,需要建立复杂的数据结构比如ray map。紧接着,在07年由Herzog等人提出了photon ray splatting以代替photon ray gathering,该方法将整个光子映射算法流程倒了过来,即先进行eye tracing,再进行photon tracing。在eye tracing过程中,我们像raytrace那样对视平面每个像素点发射射线,在击中漫反射表面后将交点信息存放起来(若击中镜面则需存储后继射线的交点信息),一般用kd-tree作为数据结构;第二步photon tracing中,从光源每发射光子后,每击中一个物体表面,就查询之前建立好的eye sample kd-tree以确定对哪些屏幕像素点产生颜色值贡献。在Herzog的算法中光源每次发射的是一个带宽度的光子,如下图:

    因而当光子击中场景时,会对一定范围内的eye sample点产生颜色值贡献,下图显示了标准光子映射(左),photon ray gathering(中),photon ray splatting(右)算法中光子搜集方式的不同:

    可见,从eye sample(绿点)附近经过的photon ray都被搜集到了,而击中背面的photon ray则可以利用一个可见性判别剔除掉,这样就有效地解决了boundary bias和topological bias的问题。但是它仍然不能解决proximity bias,这种由于密度估计范围r的不趋于零而存在的一种偏差,要解决这一问题,就必须想办法将光子数量扩大到无穷大,以便将r减小,但是如何存储同时怎么多光子呢?实际上,借用photon ray splatting中倒转光子映射算法流程的思想,可以破除光子映射中内存的限制,原因很简单,因为屏幕像素有限,所以要存下eye sample到内存是很轻松的事情,那么光子图根本就不需要存储,这样要多少光子就可以发射多少光子。

        08年,由Hachisuka等人提出了渐进式光子映射(Progressive Photon Mapping),通过第一步将eye sample组织成一个kd-tree结构,而后一轮轮地发射光子,每一轮将r减小一次,每一轮渲染一张图片。随着轮数的增多,光子数量越来越多,r的值越来越小,最终结果也越来越好,这样PPM算法也使得光子映射能生成任意精准度的图片,只要时间允许。由于倒转了PM算法的步骤顺序,PPM算法的光子搜集方法又从KNN变回到了直方图估计,这是因为每一轮中估计半径r一定是一个定值,虽然KNN估计在光子密度稀少处能更好地降低噪声,但是由于PPM算法本身已经没有了光子数量的限制,所以这点劣势很容易以大量的光子数量扳回。有了PPM,我们甚至可以不需要final gathering,因为final gathering本身也极其耗时,且不能消除偏差,还没有PPM算法自然简洁。但是该算法也远非没有问题。由于预先存储了eye sample,所以PPM无法很好地完成分布式光线跟踪里可以完成的任务,如果是像反走样这样简单的活还可以依靠在eye sample kd-tree中存下每个像素点的所有超采样点来完成的话,那么要模拟反射模糊,景深,运动模糊就更麻烦了。

        09年,还是Hachisuka,在PPM算法稍作改进,提出了SPPM(Stochastic Progressive Photon Mapping),该算法与PPM不同之处在于,在每一轮光子发射完毕后重新进行一次eye tracing,并且每次eye tracing都带上一个随机的扰动,让每次构建的eye sample kd-tree中的数据都不一样,下图展示了这两个算法的区别:

    这样做使得SPPM效率上略低于PPM,但是换来的是更加健壮和灵活,实际上SPPM在处理gloss反射的时候效果远好于PPM。看到这里,我们可能会想,既然可以一轮轮地发射光子,那不倒转整个PM算法流程也可以实现,即每次发射一定数量的光子,存起来,用完了再删掉,再发射另外一拨光子。这确实是可行的,11年Claude Knaus等人就证明了这种方式和PPM算法具有同样的鲁棒性,由于和标准PM算法的极其相似,所以之前在标准PM算法中可用的扩展,这里也全部可用,这样这种方法也很容易处理烟雾等介质的渲染。

        至此,可以看出,光子映射算法中的两个pass,代表了正向跟踪和逆向跟踪两种思想,就像之前的提到过的Light tracing和raytracing一样,两个方向相互对称,而它们每个都具有另一个所没有的优点,bidirectional pathtracing连接了正向与逆向两个路径,达到了比pathtracing高很多的效率,photon mapping同样利用了正向与逆向两个方向的信息,不仅如此,它还重用了信息(光子图),所以一般情况下能比bidirectional pathtracing收敛更快。

        从古老的正向跟踪算法Monte Carlo Light Tracing中,可以看到正向跟踪普遍存在的问题,当场景空间很大,但是能被视点看到的部分却很小的时候,会有大量的采样点对最终图像额颜色值贡献很小甚至毫无贡献。PM算法中同样存在这一问题,当场景中光子分布很糟糕的时候(只有少部分光子能到达视点的可见范围)该算法的收敛速度会变得非常之慢。受到Metropolis light transport的启发,Fan Shaohua等人于05年将Metropolis准则引入了PM算法中的photon tracing中,使主要靠间接光照明的场景能达到更快的收敛速度;11年,Chen jiating等人在SPPM基础上加入Metropolis准则,同样提高了SPPM在这类场景的收敛速率。

        最后贴上是几张由PPM渲染的图片,由于没有了光子数量的限制,最终结果会比普通PM得到的结果更好:

  • 相关阅读:
    leetcode 309. Best Time to Buy and Sell Stock with Cooldown
    leetcode 714. Best Time to Buy and Sell Stock with Transaction Fee
    leetcode 32. Longest Valid Parentheses
    leetcode 224. Basic Calculator
    leetcode 540. Single Element in a Sorted Array
    leetcode 109. Convert Sorted List to Binary Search Tree
    leetcode 3. Longest Substring Without Repeating Characters
    leetcode 84. Largest Rectangle in Histogram
    leetcode 338. Counting Bits
    git教程之回到过去,版本对比
  • 原文地址:https://www.cnblogs.com/starfallen/p/3091823.html
Copyright © 2011-2022 走看看