如何生成种子二维白噪声
How to Generate Seeded 2D White Noise
我正在尝试编写一个函数,以便 f(x, y, seed)
return 在 0.0 和 1.0 之间浮动。 x
和 y
是两个浮点数,而 seed
是一个整数。结果应该看起来像一个随机数,但使用相同的参数将始终 return 相同的结果。我打算将其用于地形生成(使用 Perlin 噪声),但效果应该是可以从给定的种子中创建白噪声(x 和 y 参数对应于图像中的位置)。
我已经研究过使用散列函数来实现这一点,但我遇到的所有散列函数要么不接受浮点数,要么不产生统一的结果(因此 0.0 和 1.0 之间的每个数字都是同样可能的), 显示出明显的模式, 或者结果对于紧密坐标变化不大)
取决于您希望实现的分布,但是例如对于已知图像大小的均匀分布,您可以这样做:
width = 100
from random import random
def f(x, y, seed):
rng = random(seed)
rng.jumpahead(x * width + y)
return rng.random()
或者,如果您有可用的像素序号索引而不是 x 和 y,则不需要网格大小:
from random import random
def f(n, seed):
rng = random(seed)
rng.jumpahead(n)
return rng.random()
又看了几个小时后,我发现了这个:https://groups.google.com/forum/#!msg/proceduralcontent/AuvxuA1xqmE/T8t88r2rfUcJ
特别是,我使用了 Adam Smith 的答案来制作这个:
def rot(x, b):
return((x<<b) ^ (x >> (32 - b)))
def pcghash(x, y, seed):
for l in range(0, 3):
x = rot(x^0xcafebabe + y^0xfaceb00c + seed^0xba5eba11, 23)
x = rot(x^0xdeadbeef + y^0x8badf00d + seed^0x5ca1ab1e, 5)
x = rot(x^0xca11ab1e + y^0xfacefeed + seed^0xdeadc0de, 17)
return(x^y^seed)
def noise(x, y, seed):
return(float('0.' + str(pcghash(x, y, seed))[-10:]))
这需要坐标和一个种子,returns 一个在 0.0 和 1.0 之间均匀分布的数字(小数点后 10 位)。我对此并不完全满意,因为所有参数都必须是整数,有很多未使用的生成位,而且我确信 noise()
函数中的代码可以改进得更快,但这符合我的目的。
编辑:可以在此处 (https://www.shadertoy.com/view/4djSRW) 的 hash12() 函数中找到一个更好的函数:
float hash12(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3
}
这是在 GLSL 中实现的,但在其他语言中应该很容易实现。此外,虽然这是一个 2 维到 1 维的哈希函数,但链接的 Shadertoy 着色器上提供了其他函数。
我正在尝试编写一个函数,以便 f(x, y, seed)
return 在 0.0 和 1.0 之间浮动。 x
和 y
是两个浮点数,而 seed
是一个整数。结果应该看起来像一个随机数,但使用相同的参数将始终 return 相同的结果。我打算将其用于地形生成(使用 Perlin 噪声),但效果应该是可以从给定的种子中创建白噪声(x 和 y 参数对应于图像中的位置)。
我已经研究过使用散列函数来实现这一点,但我遇到的所有散列函数要么不接受浮点数,要么不产生统一的结果(因此 0.0 和 1.0 之间的每个数字都是同样可能的), 显示出明显的模式, 或者结果对于紧密坐标变化不大)
取决于您希望实现的分布,但是例如对于已知图像大小的均匀分布,您可以这样做:
width = 100
from random import random
def f(x, y, seed):
rng = random(seed)
rng.jumpahead(x * width + y)
return rng.random()
或者,如果您有可用的像素序号索引而不是 x 和 y,则不需要网格大小:
from random import random
def f(n, seed):
rng = random(seed)
rng.jumpahead(n)
return rng.random()
又看了几个小时后,我发现了这个:https://groups.google.com/forum/#!msg/proceduralcontent/AuvxuA1xqmE/T8t88r2rfUcJ
特别是,我使用了 Adam Smith 的答案来制作这个:
def rot(x, b):
return((x<<b) ^ (x >> (32 - b)))
def pcghash(x, y, seed):
for l in range(0, 3):
x = rot(x^0xcafebabe + y^0xfaceb00c + seed^0xba5eba11, 23)
x = rot(x^0xdeadbeef + y^0x8badf00d + seed^0x5ca1ab1e, 5)
x = rot(x^0xca11ab1e + y^0xfacefeed + seed^0xdeadc0de, 17)
return(x^y^seed)
def noise(x, y, seed):
return(float('0.' + str(pcghash(x, y, seed))[-10:]))
这需要坐标和一个种子,returns 一个在 0.0 和 1.0 之间均匀分布的数字(小数点后 10 位)。我对此并不完全满意,因为所有参数都必须是整数,有很多未使用的生成位,而且我确信 noise()
函数中的代码可以改进得更快,但这符合我的目的。
编辑:可以在此处 (https://www.shadertoy.com/view/4djSRW) 的 hash12() 函数中找到一个更好的函数:
float hash12(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3
}
这是在 GLSL 中实现的,但在其他语言中应该很容易实现。此外,虽然这是一个 2 维到 1 维的哈希函数,但链接的 Shadertoy 着色器上提供了其他函数。