在球体上均匀生成点

时间:2010-12-03 20:49:24

标签: algorithm

我有兴趣在球体周围产生“均匀”(和非随机)分布的点,就像高尔夫球的凹坑或足球上六边形的顶点一样。有没有明确定义的算法来做到这一点?

注意:我知道这些点并非真正“均匀”地分布在一个球体上,但它们的分布方式使得点的分布看起来与任何直接观察任何点的方向相同 - 这是我感兴趣的是什么。

7 个答案:

答案 0 :(得分:1)

细分八面体并在之后对顶点进行归一化可以得到非常好的结果。 Look here了解更多详情。 Paul Bourke有很多有趣的东西。

这是我在五分钟内编写的一些伪代码C ++代码:

/* Assume 'data' initially holds vertices for eight triangles (an octahedron) */
void GenerateSphere(float radius, std::vector<Vector3f>& data, int accum=10)
{
    assert( !(data.size() % 3) );

    std::vector<Vector3f> newData;

    for(int i=0; i<data.size(); i+=3){
        /* Tesselate each triangle into three new ones */
        Vector3f centerPoint = (data[i] + data[i+1] + data[i+2]) / 3.0f;

        /* triangle 1*/
        newData.push_back(data[i+0]);
        newData.push_back(data[i+1]);
        newData.push_back(centerPoint);
        /* triangle 2*/
        newData.push_back(data[i+1]);
        newData.push_back(data[i+2]);
        newData.push_back(centerPoint);
        /* triangle 3*/
        newData.push_back(centerPoint);
        newData.push_back(data[i+2]);
        newData.push_back(data[i+0]);
    }
    data = newData;
    if(!accum){
        /* We're done. Normalize the vertices,
             multiply by the radius and return. */
        for(int i=0; i<data.size(); ++i){
            data[i].normalize();
            data[i] *= radius;
        }
    } else {
        /* Decrease recursion counter and iterate again */
        GenerateSphere(radius, data, accum-1);
    }
    return;
}

此代码适用于由逆时针三角形构成的任何多面体,但八面体最佳。

答案 1 :(得分:1)

从[0,1]中随机选择你。  2πu是经度。  asin(2v-1)是纬度。 只有两个随机变量,没有拒绝。

顺便说一句,我的链接集合有一个新地址:http://bendwavy.org/sphere.htm

我已将其复制到http://cgafaq.info/wiki/Evenly_distributed_points_on_sphere

答案 2 :(得分:0)

虽然本文讨论了在球体上随机拾取点,但它也是关于从均匀分布中绘制点,同时考虑球体特征。我想这对你的问题仍然是一个不错的读物:

http://mathworld.wolfram.com/SpherePointPicking.html

答案 3 :(得分:0)

取决于您的需求http://iquilezles.untergrund.net/www/articles/patchedsphere/patchedsphere.htm 也可能运作良好。不是完全统一,但计算速度非常快。

答案 4 :(得分:0)

这是一种简单的方法。

  1. 随机抽取单位立方体的样本,[0,1] ^ 3

  2. 测试是否包含在球体中。如果采样点不在单位立方体中包含的直径1范围内,则拒绝,并转到步骤1.

  3. 通过从球体中心向外投射点,将点标准化为球体表面。

  4. 一些样本后,这通常会成功。如果需要,您还可以拒绝接近球体中心的样本,以最大限度地减少舍入误差,并使分布更接近均匀。

答案 5 :(得分:0)

如果你只有一些允许的顶点数,那么上面的细分方法肯定是要走的路。如果你想要一个任意指定数量的顶点,那么我建议:

首先,在球体上随机均匀地分布点。 我在http://elenzil.com/progs/randompoints详细谈论这样做。 我相信我的方法至少与worlfram的方法一样高。

第二,通过将点处理为粒子系统来“放松”分布,其中每个粒子排斥每个其他粒子。这里的困难是确保系统不会变得不稳定,并决定何时停止。我在这里有一个例子:http://elenzil.com/progs/separate不幸的是,这些是我在项目中包含源代码的前几天,因此代码丢失了。

答案 6 :(得分:0)

我曾尝试过以下算法:

  • 从一个正四面体开始,在球体上提交。
  • 选择一个表面最大的三角形(最初它将是4个边中的任何一个)
  • 用3面金字塔替换选定的面,其中第4个点是面中心到球体表面的高程。
  • 重复,直到创建了足够的点数。

只要精度不破坏均匀性,这就有效。 结果点形成类似于geode的数字。

您不需要计算任何曲面,因为每个新三角形都不会超过之前的所有三角形。只需按FIFO顺序处理它们。