我正在尝试在单位球面上生成均匀随机点以用于蒙特卡罗光线追踪程序。当我说均匀时,我的意思是这些点在表面积方面是均匀分布的。我的当前方法是计算指向正z轴、底部位于x-y平面的半球面上的均匀随机点。
半球面上的随机点表示漫反射灰色发射体的热辐射发射方向。
我使用以下计算可以获得正确的结果:
注意:dsfmt*会返回0到1之间的随机数。
azimuthal = 2*PI*dsfmt_genrand_close_open(&dsfmtt);
zenith = asin(sqrt(dsfmt_genrand_close_open(&dsfmtt)));
// Calculate the cartesian point
osRay.c._x = sin(zenith)*cos(azimuthal);
osRay.c._y = sin(zenith)*sin(azimuthal);
osRay.c._z = cos(zenith);
然而这种方法非常慢,分析表明它占用了大部分运行时间。因此,我寻找了一些替代方法:
马萨利亚1972年的拒绝方法
do {
x1 = 2.0*dsfmt_genrand_open_open(&dsfmtt)-1.0;
x2 = 2.0*dsfmt_genrand_open_open(&dsfmtt)-1.0;
S = x1*x1 + x2*x2;
} while(S > 1.0f);
osRay.c._x = 2.0*x1*sqrt(1.0-S);
osRay.c._y = 2.0*x2*sqrt(1.0-S);
osRay.c._z = abs(1.0-2.0*S);
解析笛卡尔坐标计算
azimuthal = 2*PI*dsfmt_genrand_close_open(&dsfmtt);
u = 2*dsfmt_genrand_close_open(&dsfmtt) -1;
w = sqrt(1-u*u);
osRay.c._x = w*cos(azimuthal);
osRay.c._y = w*sin(azimuthal);
osRay.c._z = abs(u);
这两种方法比第一种运行速度快几倍,但使用它们时,我得到的结果表明它们并没有在球面上生成均匀随机点,而是产生了偏向赤道的分布。
此外,最后两种方法给出完全相同的最终结果,但我确定它们是不正确的,因为我正在与解析解进行比较。
我查阅的所有参考资料都表明这些方法确实会产生均匀分布,但我没有得到正确的结果。
我的实现中是否存在错误,或者我是否遗漏了第二和第三种方法中的基本思想?
sin(asin(x))
等价于使用可能有符号变化的x
。当您知道cos(z)
时,可以根据等式cos(z)^2 + sin(z)^2 = 1计算sin(z)
。 - quant_dev