【问题标题】:Best way to add seed to Perlin noise?将种子添加到 Perlin 噪声的最佳方法?
【发布时间】:2011-08-27 08:50:12
【问题描述】:

我正在尝试在 C++ 中实现 2D Perlin 噪声生成,我发现一些实现根本不使用种子(hereherehere)。其他实现采用种子值来根据噪声值获得不同的噪声。

但是我发现example code 将种子值添加到计算每个八度音阶的噪声值的函数参数中(请参阅链接代码中的 PerlinNoise::Total())。另一个使用3D种子函数,将固定的种子值作为z值(刚才找不到例子)。其他文章建议使用其他噪声函数。

所以我的问题是,为 Perlin 噪声生成添加种子值的最佳方法是什么。给定相同的种子值,应该生成相同的噪声值。如果解决方案是使用自定义噪声函数,我会很感兴趣是否可以使用 Boost.Random(或 C++11 的标准 C++ 库类)来实现它。

编辑:用“最佳”方式回答我的意思:什么是给我 Perlin 噪音的最佳方式,就像它应该工作一样,例如梯度噪声函数。

【问题讨论】:

  • 所引用的来源都不是真正的 Perlin Noise 的实现。真正的交易可以找到here
  • 您所说的“最佳”是什么意思?最快、最少内存、最有趣的噪音等等......我使用了 libnoise (libnoise.sourceforge.net),它有多种噪音类型和种子值。
  • 谷歌搜索单纯噪声。 Simplex Noise 函数看起来很像 Perlin,并且具有一些比 Perlin Noise 更可取的属性。随机性在查找表中,您可以在生成它时播种。
  • 如果 boost random 允许您生成伪随机数,我不明白为什么不这样做。重要的是对于一组值,我们每次返回的值总是相同的,否则它是完全随机的,它将不起作用。我做了一个小的 perlin 噪声演示,我生成了随机数(使用其他一些工具)并动态创建了 2d 数组(因为我在 2d 中工作),对于一个位置,我设置了一个随机值(随机),如果该位置尚未初始化。
  • 我从原始的 Ken Perlin 代码中破解了一个种子 Perlin,并进行了一些小的调整:stackoverflow.com/questions/7213469/…

标签: c++ perlin-noise random-seed


【解决方案1】:

由于没有人会写出来自 cmets 的答案,我正在尝试自己。正确时请点赞,错误时评论:)

有几个实现和示例代码(尝试)实现 Perlin 噪声。首先是 Ken Perlin 本人的Improved Noise reference implementation

案例 1:改进的噪声参考实现

noise 函数取三个 double 值并输出一个值。当使用 x 和 y 生成 2D 位图并保持 z 不变时,就会得到众所周知的 Perlin 噪声模式。当 z 在 0.0 和 1.0 之间变化时,噪声云似乎“变化”缓慢。因此,设置 z 的播种方法,例如z = 10.0 * seed,可用于“播种”。

另一种设置噪声函数的方法是:如果你总是得到 [0.0; 范围内的噪声; 64.0[ 对于 x 和 y,可以通过在调用噪声函数时向 x、y 或两者添加偏移量来播种噪声:noise(x + 64.0*seed, y + 64.0*seed)。

案例 2:教程风格的 Perlin 噪声代码

然后有一个 implementation 的 Perlin 噪声(在许多其他 Perlin 噪声教程中改编和使用)具有这样的基本噪声函数(伪代码):

function Noise2(integer x, integer y)
    n = x + y * 57
    n = (n<<13) ^ n;
    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589)
       & 7fffffff) / 1073741824.0);    
end function

我的主要怀疑来自神奇的数字以及这些页面作者的信任,即公式会导致均匀分布的噪声。其他作者在此公式的某处添加了种子值。

为这种类型的 Perlin 噪声实现添加种子的解决方案是编写一个函数,该函数为给定的 x 和 y 值均匀分布输出值(当然,通过为相同的 x 和 y 值返回相同的值) .这个函数可以用 Boost.Random 编写(代码未测试):

double Noise2(int x, int y)
{
   uint32_t seeds[3] = { uint32_t(x), uint32_t(y), seed };
   boost::mt19937 rng(seeds, seeds+3);
   boost::uniform_real<> dist(0.0, 1.0);
   boost::variate_generator<boost::mt19937&, boost::uniform_real<> >
      die(rng, dist);
   return die();
}

随机数生成器有一些 ctors,其中一个采用 uint32_t 的范围来确定 RNG 的初始状态。

还有一些库可以生成相干噪声,例如 libnoise,在这里可能会有所帮助。

单纯形噪声

我没有询问 Simplex 噪声,但我发现的 implementation (from Stefan Gustavson) 使用了类似的技术(一些预先计算的表),如 Ken Perlin 的参考实现,并且可以像上面的案例 1 一样被植入。评论者 Robinson 在生成查找表时提到了播种,但我不知道这会如何工作。

【讨论】:

  • Perlin 改进实现的排列表并不是什么特别的魔法。在我看来,这是一个播种的好地方:只需通过将数字从 1 改组到 256 来生成您自己的排列表。这就是 @Robinson 在 OP cmets 中谈论的内容。
  • @JamesClark:256 还是 255?在this implementation [1, 255] 中使用了。
  • 好点,但看起来那个 _perm 中有一个 0,所以 [0,255]。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 2011-10-21
  • 2014-02-15
  • 2020-06-06
  • 2011-09-20
  • 2019-08-21
  • 2021-06-30
相关资源
最近更新 更多