为Perlin噪音添加种子的最佳方法?

viv*_*dos 18 c++ perlin-noise random-seed

我正在尝试用C++实现2D Perlin噪声生成,我发现一些实现根本没有使用种子(这里,这里这里).其他实现取种子值以根据噪声值获得不同的噪声.

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

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

编辑:用"最好"的方式回答我的意思:什么是给我Perlin噪音的最佳方式,就像它应该工作一样,例如梯度噪音功能.

viv*_*dos 17

由于没有人会从评论中写出答案,我正在尝试自己.请在我正确的时候投票,否则请评论:)

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

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

噪声函数需要三个双精度值并输出一个值.当使用x和y生成2D位图并保持z恒定时,可以获得众所周知的Perlin噪声模式.当z在0.0和1.0之间变化时,噪声云似乎缓慢地"改变".因此,设置z的播种方法例如z = 10.0 * seed可以用于"播种".

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

案例2:教程样式Perlin噪声代码

然后有一个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
Run Code Online (Sandbox Code Playgroud)

我的主要怀疑来自神奇数字和这些页面的作者的信任,该公式导致均匀分布的噪音.其他作者在此公式中的某处添加了种子值.

为这种类型的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();
}
Run Code Online (Sandbox Code Playgroud)

随机数生成器有一些ctors,其中一个取一系列uint32_t来确定RNG的初始状态.

还有一些库可以产生相干噪声,例如libnoise,这可能会有所帮助.

单纯噪音

我没有问过Simplex噪音,但是我找到的一个实现(来自Stefan Gustavson)使用了类似Ken Perlin的参考实现的类似技术(一些预先计算的表),并且可以像上面的情况1那样播种.评论员Robinson在生成查找表时提到了种子,但我不知道这是怎么回事.

  • Perlin改进实现的排列表不是特殊的魔术.在我看来,这是一个很好的播种地点:只需通过将数字从1改为256来生成自己的排列表.这就是@Robinson在OP评论中所说的内容. (3认同)