平铺式Simplex噪声?

5

作为业余爱好者,我对伪随机噪声生成算法,特别是Perlin和Simplex算法很感兴趣。 Simplex算法的优点在于速度(尤其是在高维情况下),但是Perlin可以相对容易地进行平铺。 我想知道是否有人知道一种可平铺的Simplex算法? 固定维数也可以,通用性更好; 伪代码可以,c / c ++更好。


我之前也有同样的问题。这个链接可能会对你有所帮助。http://www.gamedev.net/community/forums/topic.asp?topic_id=409855 - rayimag
谢谢提供链接;不幸的是,该主题的结论是这些实现仅具有Perlin噪声平铺,而没有Simplex噪声。 - fbrereto
1
我浪费了好几天的时间在瓦片化Simplex噪声上,结果发现它是被专利保护的(美国专利号6867776)!完全浪费了我的时间。不要浪费你的时间,使用“经典噪声”代替。 - user767299
柏林噪声没有被专利保护吗?http://www.wikipatents.com/US-Patent-6867776/standard-for-perlin-noise 以防你不知道,肯尼斯·柏林创建了Simplex噪声来替换他的旧Perlin噪声,因为它更快且具有更少的伪影。 - Jón Trausti Arason
1
这个与编程有关的内容的翻译如下:这个问题在这里也得到了回答,尽管这里的答案也很有趣。 - bobobobo
4个回答

4

只需像在Perlin中一样对噪声进行平铺,只是在偏移后进行。您可以通过修改获取排列的部分来执行mod 256(或& 255,无论您使用哪个)在添加到基角落的偏移量之后(而不是之前)以获得其他角落。以下是HLSL中修改后的代码片段:

uint3 iIdx0 = p0SI % 256;
uint3 iIdx1 = (p0SI + pI1) % 256;
uint3 iIdx2 = (p0SI + pI2) % 256;
uint3 iIdx3 = (p0SI + 1.0f) % 256;
uint iGI0 = gPerm[ iIdx0.x + gPerm[ iIdx0.y + gPerm[ iIdx0.z ] ] ] % 12;
uint iGI1 = gPerm[ iIdx1.x + gPerm[ iIdx1.y + gPerm[ iIdx1.z ] ] ] % 12;
uint iGI2 = gPerm[ iIdx2.x + gPerm[ iIdx2.y + gPerm[ iIdx2.z ] ] ] % 12;
uint iGI3 = gPerm[ iIdx3.x + gPerm[ iIdx3.y + gPerm[ iIdx3.z ] ] ] % 12;

p0SI是第0个角点,p12和pI2是到角点1和角点2的向量,按照通常的方式计算。请注意,在HLSL中,标量在混合操作中自动转换为向量,因此例如1.0f实际上是(1.0,1.0,1.0)。我刚刚想出了这个平铺的东西,但显然它有效。如果您需要对大行星或某些东西进行着色,但只有单精度卡,请告诉我。

编辑:想一想后,我认为您不需要更改任何内容。我认为它在256个单位时已经自动平铺了。


3

似乎这个问题已经被合理地解决了,这里有一个详细的工作解决方案的描述,这里有一个长期存在的问题的绝妙答案!


高维噪声并不具有相同的属性。 - endolith

2
即使几年过去了,这个问题仍然是谷歌搜索结果中最佳的之一。
在 Simplex 噪声中,来自一个直角坐标系的 x 和 y 坐标被扭曲以找到点所在的 Simplex(在 2D 中为三角形)。因此,使用常见的平铺技术(%255 或其他),它确实可以平铺,但是在扭曲的坐标上进行平铺,也就是说它会"对角线"平铺,这是相当无用的。
我发现的一个简单解决方案是"取消扭曲"结果,使原始的 X 和 Y 首先被扭曲"向左",然后算法会将它们扭曲"向右",最终结果将重新对齐到非扭曲网格。
例如,如果您的 Simplex 实现类似于网络上随处可见的 SimplexNoise.java,它会使用以下代码扭曲网格:
var F2 = 0.5*(Math.sqrt(3.0)-1.0);
var s = (xin+yin)*F2; // Hairy factor for 2D
var i = Math.floor(xin+s);
var j = Math.floor(yin+s);

你可以在方法的入口点简单地以相反的方向“预扭曲”它:
var G2 = (3.0-Math.sqrt(3.0))/6.0;
var t = (xin+yin)*G2;
xin-=t;
yin-=t;

很不幸,它产生了一种看起来有些奇怪的效果(也就是,它看起来有点倾斜 :D),这通常不是问题,但取决于你需要这个噪音做什么。

由于这对我来说是个问题,我尝试将这种“反倾斜”仅应用于几个八度音阶,那些在最终输出中权重更大的八度音阶,并使用插值来处理“轻”八度音阶。 这种解决方案为我提供了基于Simplex Perlin噪声的令人满意的平铺效果,因为对所有八度音阶进行插值会在平铺边界上产生太多衰减,并且在添加更多八度音阶而没有人工倾斜时,奇怪的效果会被额外的噪声掩盖。


这是我在任何地方找到的最好的答案。我一直坚持使用Perlin噪声,因为平铺它要容易得多,但关键是斜变换。我相信适当的倾斜是可能的,但我还没有找到任何人能够做到这一点。 - Krupip

1

我最近需要使用平铺的Simplex噪声,并在这个问题中找到了答案。

对于使用任何噪声函数进行平铺噪声,您可以线性插值额外的平铺样本:

Ftileable(x, y) = ( 
       F(x, y) * (w - x) * (h - y) + 
       F(x - w, y) * (x) * (h - y) + 
       F(x - w, y - h) * (x) * (y) + 
       F(x, y - h) * (w - x) * (y)
) / (wh)

其中F()是您的噪声函数。请注意,x、y必须是单个瓷砖内的坐标:x在[0,w)范围内,y在[0,h)范围内。您可以使用类似tileX = x - Math.Floor(x / w) * w或fmod()的东西。

如果性能至关重要或者对于更高维度,这可能不是正确的方法,因为它需要2^D次查找,其中D是维度。对我来说,它还会在瓷砖中心产生较低的值。

摘自: http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html


那是平铺的Perlin噪声,而不是Simplex噪声。 - fbrereto
该链接讨论了Perlin噪声,但并没有明确说明这种方法仅适用于它。我有一个工作的2D实现,可以平铺simplex噪声,但是选择了另一种方法,因为振幅朝着瓷砖中心减小。Gabor噪声似乎能够产生良好的结果,并且不需要采用这种方法进行平铺(http://graphics.cs.kuleuven.be/publications/LLDD09PNSGC/)。 - BenC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接