如何在三维空间中生成随机点

How do I generate random points in 3D space?

本文关键字:随机 三维空间      更新时间:2023-10-16

我遇到的最大问题是我没有足够的词汇来描述我想要的东西,所以如果没有其他帮助,我将不胜感激。

据我所知,Perlin噪波可以为三维空间中的一个点提供一个随机值,此外,任何附近的点都将具有相似的值。我在一个程序中工作,当随机值超过某个阈值时,生成漂浮在空间中的3D斑点。这很好,因为我可以选择任何点,并且不必担心之前计算了哪些点,就可以确定其值(如果我愿意,可以线程生成blob)。

我现在想做一些类似的事情,除了,如果随机值超过某个阈值,我想改变斑点上那个点的颜色。然而,我希望这是随机的,与它的邻居无关(不像Perlin噪音)。

我在寻找什么样的算法来实现这一点?

关键标准:

  1. 该函数将三维矢量作为参数
  2. 这些值在点与点之间完全无关
  3. 顺序检查点不会影响函数的结果
  4. 如果将相同的点传递给该函数,则该函数将返回相同的结果

结果

因此,我决定使用一种类似于Kahler的方法,并进行一些非常小的调整。我不想使用重复实例化甚至只是重复播种随机数生成器所使用的所有重定向和操作。我最终复制了UE4 RandomStream类中使用的随机数生成器,并使其符合我的需求。我确信这个生成器并不是他们一个人的,因为使用的数字似乎出现在其他地方,但我就是在那里找到的。

float WhiteNoise::GetNoise3D(const FVector& vector) const
{
    int32 s1 = seed;
    int32 s2 = ((s1 + FMath::TruncToInt(vector.X)) * 196314165) + 907633515;
    int32 s3 = ((s2 + FMath::TruncToInt(vector.Y)) * 196314165) + 907633515;
    int32 s4 = ((s3 + FMath::TruncToInt(vector.Z)) * 196314165) + 907633515;
    const float tmp = 1.0f;
    float result;
    *(int32*)&result = (*(int32*)&tmp & 0xff800000) | (s4 & 0x007fffff);
     return FMath::Fractional(result);
}

上面的代码存在一些明显的问题。一个是数字不是很随机,另一个是导致粒度问题的截断。在我的情况下,这两个都是完全可以接受的,所以这相当好。

如果每次传入相同的参数时函数都返回相同的数字,则它不是随机函数。要在不保存每个点的确切结果的情况下获得明显随机的模式,可以使用种子取决于位置的随机生成器。

类似的东西

value_t get_value(coord_t x, coord_t  y, coord_t z)
{
    seed_t seed = some_equation(x,y,z);
    return generate_random_with_seed(seed);
}

C++现在有了<random>库,您必须调整方程才能得到令人满意的结果。每次种子重复时,它们都会重复,每次调用都有明显的随机模式。一种可能的种子生成器是将所有可能的离散可能性传播到种子的类型上,因为相等的种子意味着相等的结果。

(因此256x256x256网格可以使用种子(x*256*256 + y*256 + z)

这个策略实际上将一个有序集映射到一个明显无序的集。输出将通过种子上的随机生成器操作与位置相关。

由于对唯一种子的要求可能会变得非常繁琐,您还可以通过将卷拆分到较小的卷上来获得可重复的结果,每个卷由N个点组成,并且整个块共享相同的唯一种子,因此第i个元素的随机值是随机生成器使用块种子运行的第i次。

这将把唯一种子的需求减少N倍,但将平均检索操作增加(N-1)/2倍。

不久前,我已经尝试了几个<random>发行版,这里有一些代码显示了~graphical~输出(注释是葡萄牙语,但代码很简单)。

你可能会想要一个统一的随机变量作为阈值,这里有一个关于uniformintdistribution的在线参考。

采用与Kahler上面的优秀答案略有不同的方法,我想知道您是否只是简单地搜索一种更改数字空间的方法。

在这种情况下,可以说随机数存在于一维数值空间中。即可以使用从0向上和向下的整数值。

随机生成的32位整数必须介于0和4294967295之间,即您有4294967296个可能的唯一数字。然而,如果你在二维空间(如我们所说的"网格")中"消耗"这个随机数,那么你的网格大小将是4294967296的第二个根,也就是65536。这意味着你有65536乘65536个可能的"插槽",可以随机为0或1(但随机数分布将完全匹配该网格)。

如果在三维空间中使用随机整数,则面对4294967296的第3个根,即ca1625。Ie.网格大小约为1625x1625x1625个插槽(也可以说是"单元格")。

正如你在这里看到的,1625并不多,其含义是:如果你碰巧为XYZ位置使用32位浮点来维持一个空间(也许是一个空间游戏?你没有提到),那么你使用96位来寻址空间,或者更糟的是,如果使用双精度寻址,则使用192位来寻址,而你只在32位空间中生成随机数。这意味着在数字空间之间的映射中将存在重复或粗糙("坏粒度")。很难准确预测你将如何经历这种情况。然而,您将只有1625个可能的x位置。

(尽管如此,将随机数从一维空间更改为三维空间是可能的。事实上,这很简单。生成数字,获取它的布尔表示(二进制,位)。然后简单地取前11个比特,并从中构造一个整数;将其用于位置.x。然后对接下来的11位执行同样的操作,并用于位置y.。z位置只得到10位。。。嗯-哦好吧:-)。)

使用种子与此无关。种子使随机生成具有可重复性,根据Kahlers的描述,这仍然是完全可能的。

现在来看潜在的问题:

  • 如果你将这些东西"隔离"到blob(使用内部3D位置寻址,从中继承种子),那么你会担心你的随机生成将在一个blob到另一个blob之间重复。所有斑点都将获得相同的外观。

  • 另一方面,如果你对你的种子使用全局的、巨大的坐标寻址,那么你可能会在单个斑点中的随机数中获得糟糕的粒度(例如,沿着一个方向只有1625个可能的位置)。

很难说,但你最终可能会得到视觉上不令人满意的结果。我建议一次生成的不是一个随机数,而是3,每个方向一个。你仍然可以确定它是否命中(你的"阈值"),但只需使用单个随机数的三元组进行检查,并对每个种子使用你的世界(全球)定位系统。