图形学数学基础之Hammersley采样

来源:互联网 发布:腾讯上班知乎 编辑:程序博客网 时间:2024/06/07 00:41

作者:i_dovelemon
日期:2017/08/02
来源:CSDN
主题:hammersley,binary

引言

在图形学里面,用到了很多的采样算法。特别当你在写一个光线追踪器的时候,会使用大量的采样算法来对BRDF,光源等进行采样。这些采样操作,一般是先通过创建一个具有均匀分布的2D随机点集合,然后通过变换,将这些2D随机点变换到具体的采样数据上去,如BRDF的方向等等。关于这部分变换和相应的原理,后面会有相应的章节来讲解,今天我们先来了解一个在实现PBR中,经常被使用到的均匀分布的2D随机采样方式–Hammersley采样。

Hammersley采样

Hammersley采样,听上去好像很深奥的样子,实际上是一个十分简单的操作。

我们知道,在计算机里面大量使用了二进制来表示数据,如下表所示的一些十进制与二进制的对应关系:

十进制 二进制 1 1 2 10 3 11 4 100


而Hammersley采样就是利用计算机使用二进制表示的特性,来构造均匀分布的2D随机采样点。它是通过对一个二进制数进行Radical Inverse方法,来构造出一个值来实现的。它的过程如下表:

十进制 二进制 Radical Inverse 值 1 1 .1 = 1 * 1/2 0.5 2 10 .01 = 0 * 1/2 + 1 * 1/4 0.25 3 11 .11 = 1 * 1/2 + 1 * 1/4 0.75 4 100 .001 = 0 * 1/2 + 0 * 1/4 + 1 * 1/8 0.125


从上表可以看到,Radical Inverse方法,就是简单的将给定的十进制数的二进制表示方法,反过来放在小数点之后,构造一个在[0,1]之间的值。

在明白了Radical Inverse方法之后,我们就可以构造hammersley的2D随机分布的采样点集合,如下所示:

pi=(xi,yi)=(i/N,ϕ(i))

其中N表示的是一共有多少个采样点,ϕ(i)就是对i进行Radical Inverse之后的值。

在我的raytracer项目中,使用了hammersley采样,有相关的代码可供参考,如下所示:

class HammersleySampler(Sampler):    def __init__(self):        super().__init__(Sampler.MULTIJITTERED)    def radicalInverseBase2(self, v):        x = 0.0        f = 0.5        v = int(v)        while v != 0:            x += f * (v & 1)            v = math.floor(v / 2)            f *= 0.5        return x    def genSamplersInUnitSqure(self, num):        self.samplers = []        for i in range(num):            x = i * 1.0 / num            y = self.radicalInverseBase2(i)            self.samplers.append(Vector2(x, y))

同时该raytracer的测试例子,能够得到如下一张图,显示了hammersley是均匀分布的:

![hammersley采样分布](http://img.blog.csdn.net/20170802235723900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaV9kb3ZlbGVtb24=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
为了方便,这里同时给出GLSL的代码,便于大家参考:
float RadicalInverse(uint bits) {    bits = (bits << 16u) | (bits >> 16u);    bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);    bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);    bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);    bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);    return float(bits) * 2.3283064365386963e-10f;}vec2 Hammersley(uint i, uint N) {    return vec2(float(i) / float(N), RadicalInverse(i));}

总结

图形学的世界非常的奇妙,采样的理论非常美丽,后面会陆陆续续和大家介绍更多的相关内容。

参考文献

[1] Ray Tracing From Ground Up