单位球面上的均匀随机(Monte-Carlo)分布

时间:2009-12-03 16:17:43

标签: 3d random montecarlo

我需要澄清算法,为我的宠物光线追踪器生成随机值 我从一个点发射光线。我有这些光线分布的问题:我需要分布均匀,但它不是......

我现在面临的问题是,在我对结果空间的扭曲之后,最初的均匀分布是不均匀的。

例如,如果是极坐标系,我会生成r和t角。分布不均匀且不均匀:靠近每个极点的空间比靠近赤道的结果密度大得多。原因很清楚:我将均匀分布的点从圆柱空间转换为球形。而且我扭曲了结果。同样的问题是如果我规范化立方体中随机生成的点。

我现在的想法是这样的:我想创建一个四面体,对其顶点进行标准化,将每个面(三角形)与中间的点分开,对其进行标准化并递归重复,直到我有足够的点。然后我稍微“扭曲”这些点。然后我再次将它们标准化。而已。

据我所知,这种方法本身并不是纯粹的数学蒙特卡罗方法,因为除了最后一步之外,我不会在任何步骤中使用随机分布。我不喜欢这种复杂性的解决方案。

任何人都可以建议更简单但仍然

  • 随机
  • 均匀
  • 简单

谢谢!

修改
我需要一个快速的方法,而不仅仅是正确的方法。这就是我问蒙特卡罗的原因。提供的答案是正确的,但不是很快。四面体的方法很快,但不是很“随机”=>不正确。
我真的需要更合适的东西。

5 个答案:

答案 0 :(得分:10)

Here's一种算法,允许您生成随机分布在单位球上的点。

答案 1 :(得分:5)

这是我过去使用的Java实现:

public static double[] randomPointOnSphere(Random rnd)
{
    double x, y, z, d2;
    do {
        x = rnd.nextGaussian();
        y = rnd.nextGaussian();
        z = rnd.nextGaussian();
        d2 = x*x + y*y + z*z;
    } while (d2 <= Double.MIN_NORMAL);
    double s = Math.sqrt(1.0 / d2);
    return new double[] {x*s, y*s, z*s};
}

答案 2 :(得分:4)

你真的需要在球体上随机分布或均匀分布吗?

然后我会建议ZCW角度,它们在整个球体上均匀分布并快速计算。 其他方法是TheSydneyOperaHouse(SOPHE)和Repulsion。 (搜索repulsion.c) 排斥方法非常好但很慢:它在一个球体上迭代地均匀分布点。幸运的是,它必须只进行一次。

这用于晶体学和核磁共振,因为对于粉末模式,使用均匀分布与随机分布相比更快(您需要更少的点)。

Here是ZCW的Python实现。

这些论文中的更多细节:

答案 3 :(得分:2)

除非你只是光线追踪琐碎的场景,你的渲染时间真的会被样本采摘时间所主导吗?如果没有,它可能不值得优化,尽管值得阅读和理解其他答案中给出的统一抽样技术。

此外,您的样本无需非常随机即可对您正在采样的任何函数进行良好估计。您可能希望使用quasirandom数字序列进行调查,例如Halton sequence。你的四面体细分理念还不错。对于大多数场景来说,它应该会产生分布均匀的点,而且应该比均匀的伪随机样本更好,但在某些情况下可能会导致可怕的伪像。

无论如何,你应该咨询ompf.org上的论坛。那边有一些超级铁杆光线的书呆子。

答案 4 :(得分:1)

对于球形截面,在phi(极角)和cos(theta)(对于θ方位角)均匀地生成角度。

在伪代码中:

phi = phi_low_limit        + rand()*(phi_high_limit       - phi_low_limit)
ct = cos(theta_high_limit) + rand()*(cos(theta_low_limit) - cos(theta_high_limit))
// The order is inverted here because cos heads down for increasing theta
theta = arccos(ct)

这是规则的一个特例,它反转Jacobian并在那些坐标的空间内均匀生成。

注意:请注意,我使用的是David Norman系列的phi和theta的相反约定。

另请注意:这实际上不是最快的方法,而是说明一般原则的方法。