平铺单纯形噪声?

发布于 2024-08-02 18:07:13 字数 146 浏览 5 评论 0 原文

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

I've been interested (as a hobbyist) in pseudo-random noise generation, specifically the Perlin and Simplex algorithms. The advantage to Simplex is speed (especially at higher dimensions), but Perlin can be tiled relatively easily. I was wondering if anyone was aware of a tiling simplex algorithm? Fixed-dimension is fine, generic is better; pseudocode is fine, c/c++ is better.

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

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

发布评论

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

评论(4

流云如水 2024-08-09 18:07:13

看来这个问题已经在这里得到了合理的解决,详细描述了工作解决方案背后的想法此处。对一个长期存在的问题的绝佳答案!

It would seem this question has been reasonably solved here, with a detailed description of the idea behind the working solution here. A fantastic answer to a long-standing problem!

温柔嚣张 2024-08-09 18:07:13

只需像在 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 点,pI2 和 PI2 是按通常方式计算的角点 1 和角点 2 的向量。请注意,在 HLSL 中,标量会在混合运算中自动提升为向量,因此 1.0f 实际上是 (1.0,1.0,1.0)。我刚刚想出了这个平铺的东西,但显然它有效。如果您需要遮蔽一颗大行星或其他东西,但您的卡上只有单精度,那么还有几个步骤。打我吧。

编辑:你再考虑一下就知道了,我认为你不需要改变任何东西。我认为它会自动平铺为 256 个单位。

Just tile your noise the same way you would in Perlin only do it after the skew. You can do this by modifying the part that gets the permutaions to do the mod 256 (or & 255, whatever you are using) after (instead of before) you add to offsets to the get the other corners from the base corner. This is the modified bit of code in 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 is the corner 0 point and pI2 and PI2 are vectors to corner one and corner 2 calculated in the usual way. Note that in HLSL scalars promote to vectors automatically in mixed operatons so for instance 1.0f is actually (1.0,1.0,1.0). I just figured this tiling stuf out but apprently it works. If you need to shade a large planet or some shit but only have single precision on your card there are a few more steps. Hit me up.

Edit: you know after thinking about it some more I don't think you have to change anything. I think it tiles autmatically at 256 units as implemented.

青朷 2024-08-09 18:07:13

即使几年过去了,这个问题仍然是谷歌上最好的结果之一。

在单纯形噪声中,来自直线(或法线)网格的 x 和 y 会发生倾斜,以找到点所在的单纯形(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),这通常不是问题,但取决于您需要该噪音的目的。

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

Even if few years passed, this question is still among best results on Google.

In simplex noise, x and y from a straight (ortonormal) grid get skewed to find the simplex the point is in (a triangle in 2D), so with common tiling techniques (%255 or whatever), it DOES tile, but tiles on skewed coordinates, that is it tiles "diagonally", which is quite useless.

A simple solution I've found is to "un-skew" the result, so that original X and Y are first skewed "to the left", then the algorithm will skew them "to the right", and the final result will be re-aligned to a non skewed grid.

If, for example, your simplex implementation is similar to SimplexNoise.java you can find everywhere on the net, it skews the grid using :

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

You can simply "pre-skew" it in the opposite direction at the entry point of the method:

var G2 = (3.0-Math.sqrt(3.0))/6.0;
var t = (xin+yin)*G2;
xin-=t;
yin-=t;

Unfortunately, it produces a somehow strange-looking effect (that is, it looks a bit skewed :D ), which is not usually a problem, but depends on what you need that noise for.

Since it was a problem for me, I tried applying this "inverse-skewing" only to a couple of octaves, those that weight more in the final output, and instead used interpolation for "lighter" octaves. This solution gave me satisfactory tiling based on simplex Perlin noise, cause interpolation on all octaves would produce too much attenuation on tile borders, and when more octaves are added without artificial skewing the strage-looking effect gets buried under the additional noise.

土豪 2024-08-09 18:07:13

我最近需要平铺单纯形噪声并遇到了这个问题。

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

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() 的方法。

如果性能至关重要或对于更高的维度,这可能不是可行的方法,因为它需要对维度 D 进行 2^D 查找。它还为我产生了朝向图块中心的较低值。

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

I recently needed tiling simplex noise and came across this question.

For tiling noise using any noise function, you can linearly interpolate additional tile samples:

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)

where F() is your noise function. Note that x, y must be coordinates within an individual tile: x in [0, w), y in [0, h). You could use something like tileX = x - Math.Floor(x / w) * w or fmod().

If performance is critical or for higher dimensions, this may not be the way to go because it requires 2^D lookups for dimension D. It also produced lower values toward the centers of tiles for me.

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

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