向 Perlin 噪声添加种子的最佳方法?

发布于 2024-12-01 11:03:18 字数 781 浏览 5 评论 0原文

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

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

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

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

I'm trying to implement 2D Perlin noise generation in C++, and some implementations I found use no seed at all (here, here or here). Other implementations take a seed value to get different noise depending on the noise value.

However I found example code where one added the seed value to the function parameters calculating the noise value for each octave (see PerlinNoise::Total() in the linked code). Another one uses a 3D seed function and uses the fixed seed value as the z value (couldn't find the example just now). Other articles suggest using other noise functions.

So my question would be, what the best way would be to add a seed value to Perlin noise generation is. Given the same seed value, the same noise values should be generated. If the solution would be to have a custom noise function, I would be interested if it could be implemented using Boost.Random (or C++11's Standard C++ Library classes).

Edit: To answer what I mean with "best" way: What's the best way that gives me Perlin noise like it was supposed to work, e.g. a gradient noise function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

牵你的手,一向走下去 2024-12-08 11:03:18

由于没有人会根据评论写出答案,所以我自己尝试一下。当我正确时请点赞,错误时请发表评论:)

有几种实现和示例代码(尝试)实现 Perlin 噪声。首先,有来自 Ken Perlin 本人的改进的噪声参考实现

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

噪声函数采用三个双精度值并输出一个值。当使用 x 和 y 生成 2D 位图并保持 z 恒定时,就会得到众所周知的柏林噪声模式。当 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 噪声代码

然后是 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();
}

随机数生成器有一些因素,其中一个采用一系列 uint32_t 来确定 RNG 的初始状态。

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

单纯形噪声

我没有问单纯形噪声,而是问一个 实现(来自 Stefan) Gustavson) 我发现使用了类似的技术(一些预先计算的表),例如 Ken Perlin 的参考实现,并且可以像上面的情况 1 一样进行播种。评论者罗宾逊提到在生成查找表时进行播种,但我不知道这将如何工作。

Since no one is going to write up an answer from the comments, I'm trying myself. Please upvote when I'm correct, comment when not :)

There are several implementations and example code that (try to) implement Perlin noise. First, there is the Improved Noise reference implementation from Ken Perlin himself.

Case 1: Improved Noise reference implementation

The noise function takes three double values and outputs a value. When generating a 2D bitmap using x and y, and keeping z constant, one gets the well known Perlin noise pattern. When z is varied between 0.0 and 1.0, the noise clouds seem to "change" slowly. So a seeding method that sets z, e.g. z = 10.0 * seed, could work for "seeding".

Another way to seed the noise function would be this: If you always just get noise in a range of [0.0; 64.0[ for x and y, one could seed the noise by adding an offset to x, y or both when calling the noise function: noise(x + 64.0*seed, y + 64.0*seed).

Case 2: Tutorial style Perlin noise code

Then there is an implementation of Perlin noise (adapted and used in many other Perlin noise tutorials) that have a base noise function like this (pseudocode):

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

My main skepticism came from the magic numbers and the trust of the authors of these pages that the formula leads to uniformly distributed noise. Other authors added the seed value somewhere in this formula.

The solution to add a seed to this type of Perlin noise implementation is to write a function that uniformly distributes output values for given x and y values (and by returning the same value for the same x and y values, of course). This function can be written using Boost.Random (code not tested):

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();
}

The random number generator has some ctors, among them one that takes a range of uint32_t's that determine the initial state of the RNG.

There also are libraries that generate coherent noise, such as libnoise, that may be of help here.

Simplex Noise

I didn't ask of Simplex noise, but the one implementation (from Stefan Gustavson) I found uses a similar technique (some precomputed tables) like Ken Perlin's reference implementation, and could be seeded just like case 1 above. Commenter Robinson mentioned seeding when generating the look-up table, but I don't know how that would work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文