PBRT学习笔记:在单位圆内部均匀采样

在一个单位圆内部均匀采样,即在单位圆内部随机取一个采样点,而每个采样点被取到的概率都是1/Pi。这个问题看似非常简单,但是可能要比想象中复杂一点。这里的采样我们从canonical uniform variable开始,即我们只能够生成从0到1的随机数,而其分布是均匀分布的。
首先,最容易想到的方法就是rejection method。在单位圆的外部做一个Bounding Box,紧紧的包住这个单位圆。然后用两个随机点分别在两个轴向上取点,从而均匀的随机提取正方形内部的一个点。然后进行简单的测试,当这个点与圆的中心距离大于1的时候,我们按照刚才做法重新生成一个随机点,直到其在圆的内部为止。那么这个点就是我们想要的点了,而且是完全均匀分布的。
这种方法是rejection sampling method的一种,最大的优点在于简单,易于实现。但是在效率方面,这种方法会有很大弊端。我们在选取到最终结果之前,很可能需要生成很多随机点,当随机数生成算法代价足够大的时候,这种方法的效率是不高的。从面积的比率来看,随机点被接受和拒绝的比例为Pi/(4-Pi)。
那么,有没有更合适的方法呢?
还有一种叫做inverse sampling method的方法可以被应用,这种方法的要求可能多一些,需要函数是可积的,并且CDF是可逆的。好在这个例子里面,我们可以把问题变简单一些。
除了上述想法,最直观的想法就是用极坐标系来生成随机点。我们假设有两个从0到1的随机数,a,b。那么,我们另:
      r = a
      theta = b * 2 * Pi
上述随机点显然可以布满整个圆,但是并不是均匀分布的。简单证明如下,如果上述算法可以均匀生成随机点,那么我们假设r0为0到1之间的一个固定数值。由于r=a,而theta不影响点到圆心的距离,所以点在以r0为半径的圆内部的概率为P(a < r0) = r0。而从面积角度讲,点在以r0为半径的圆内部的概率应该是该面积与单位圆的面积比例,即r0*r0。由于r0在0和1之间,显然r0!=r0*r0。所以我们的假设是不成立的,即上述算法不是均匀分布的。
实际上,通过inverse sampling method,我们可以计算出正确的生成算法,即
      r = sqrt( a )
      theta = b * 2 * Pi
上述算法就是满足要求的了,即可以在圆的内部均匀分布了。而且不想rejection method,这回我们只需要生成两个随机数而已,效率有了一定的提升。
表面上来看,该方法似乎很完美,但是这种变换的局部性保持的很差,所以很多应用中效果都不好。例如下图:
image左边是原始随机数(a,b)生成的坐标系(我们假设有这样的坐标系),右边是经过了上述变换后的均匀采样,我们发现图片中的F已经完全走样了,基本上看不出来了。而且更糟糕的是,这种连续不是双向的。即在(a,b)的坐标系中,如果两点连续,那么投影到圆后的两个点同样是连续的。而反过来就不一定成立了。
所以,是否有更好的方法呢?
Peter Shirley很早就有一篇文章A Low Distortion Map Between Disk and Square,介绍了一种更好的根据均匀分布的随机采样,可以用来采样圆。
这个方法也不难理解,它把一个正方形通过一些简单的数学变换压缩成了一个圆的形状。变换如下:
     r = a
     theta = Pi * b / ( 4 * a )
可以想象,通过上诉变换,我们可以把正方形压缩成圆的形状
image这种变换的好处在于,它可以保持局部性以及双向的邻接性质。我们再看看上面的F在这种变换下,变成了什么形状:
image虽然有了一定的扭曲,但是我们还可以清晰的看到里面的F形状,而且要比第二种变换清晰很多。
这种变换被作者称之为Concentric Map。那么最后的问题出现了,这种变换后,采样还是均匀分布么?
对于这个问题而言,我们只需要找到p(a,b)与p(r,theta)之间的关系就好了,而这两者的关系是不难计算的:
    p(a,b) = 0.25
    p(u,v) = p(a,b) / |J_T|
其中
    u = a * cos( Pi * b / ( 4 * a ) )
    v = a * sin( Pi * b / ( 4 * a ) )
J_T为Jacobian行列式,通过计算我们得到
    image 所以p(u,v) = 0.25 / ( Pi / 4 ) = 1 / Pi,即在圆内部每一点被采样到的概率都为1/Pi,所以上述变换为均匀分布。

没有更多推荐了,返回首页