gpt4 book ai didi

java - 柏林噪声的输出范围

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:43:33 25 4
gpt4 key购买 nike

我正在研究一些针对相干噪声的各种实现(我知道有一些库,但这主要是出于我自己的启迪和好奇心)以及如何使用它,我对原始版本有一个问题Perlin 噪声。

根据 this frequently linked Math FAQ , 输出范围将在 -1 之间和 1 ,但我不明白该值如何进入该范围内。

据我了解,该算法基本上是这样的:每个网格点都有一个长度为 1 的相关随机梯度 vector 。 .然后,对于每个点,对于所有四个周围的网格点,您计算随机梯度和从该网格点出发的 vector 的点积。然后,您使用奇特的缓动曲线和线性插值将其降低到一个值。

但是,这是我的问题:这些点积偶尔会超出范围 [-1, 1] ,并且由于您最终在点积之间进行了线性插值,这是否意味着最终值有时会超出 [-1, 1] 的范围? ?

例如,假设其中一个随机 vector 是 (sqrt(2)/2, sqrt(2)/2) (长度为 1)和 (0.8, 0.8) (在单位正方形中),你得到的结果大约是 1.131 .如果在线性插值中使用该值,则生成的值完全有可能大于 1。 .事实上,在我直接实现的情况下,这种情况经常发生。

我是不是漏掉了什么?

作为引用,这是我的 Java 代码。 Vec是一个简单的类来进行简单的二维 vector 运算,fade()是缓和曲线,lerp()是线性插值,gradient(x, y)为您提供该网格点的渐变 Vec . gridSize变量以像素为单位给出网格的大小(它的类型为 double):

public double getPoint(int x, int y) {
Vec p = new Vec(x / gridSize, y / gridSize);
Vec d = new Vec(Math.floor(p.x), Math.floor(p.y));


int x0 = (int)d.x,
y0 = (int)d.x;


double d00 = gradient(x0 , y0 ).dot(p.sub(x0 , y0 )),
d01 = gradient(x0 , y0 + 1).dot(p.sub(x0 , y0 + 1)),
d10 = gradient(x0 + 1, y0 ).dot(p.sub(x0 + 1, y0 )),
d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1));

double fadeX = fade(p.x - d.x),
fadeY = fade(p.y - d.y);

double i1 = lerp(fadeX, d00, d10),
i2 = lerp(fadeX, d01, d11);

return lerp(fadeY, i1, i2);
}

编辑:这里是生成随机梯度的代码:

double theta = gen.nextDouble() * 2 * Math.PI; 
gradients[i] = new Vec(Math.cos(theta), Math.sin(theta));

在哪里genjava.util.Random .

最佳答案

你有 y0 = (int)d.x;,但你的意思是 d.y。这肯定会影响您的输出范围,这也是您看到如此大范围超出范围的值的原因。


也就是说,柏林噪声的输出范围不是实际上是[-1, 1]。虽然我自己不太确定数学(我一定是变老了),this rather lengthy discussion得出实际范围是 [-sqrt(n)/2, sqrt(n)/2],其中 n 是维数(在您的例子中是 2)。因此,您的 2D Perlin 噪声函数的输出范围应为 [-0.707, 0.707]。这在某种程度上与 d 和插值参数都是 p 的函数这一事实有关。如果通读该讨论,您可能会找到所需的准确解释(特别是 post #7 )。

我正在使用以下程序测试您的实现(我从您的示例中拼凑而成,所以请原谅 gridCellsgridSize 的奇怪使用):

import java.util.Random;


public class Perlin {

static final int gridSize = 200;
static final int gridCells = 20;
static final Vec[][] gradients = new Vec[gridCells + 1][gridCells + 1];

static void initializeGradient () {
Random rand = new Random();
for (int r = 0; r < gridCells + 1; ++ r) {
for (int c = 0; c < gridCells + 1; ++ c) {
double theta = rand.nextFloat() * Math.PI;
gradients[c][r] = new Vec(Math.cos(theta), Math.sin(theta));
}
}
}

static class Vec {
double x;
double y;
Vec (double x, double y) { this.x = x; this.y = y; }
double dot (Vec v) { return x * v.x + y * v.y; }
Vec sub (double x, double y) { return new Vec(this.x - x, this.y - y); }
}

static double fade (double v) {
// easing doesn't matter for range sample test.
// v = 3 * v * v - 2 * v * v * v;
return v;
}

static double lerp (double p, double a, double b) {
return (b - a) * p + a;
}

static Vec gradient (int c, int r) {
return gradients[c][r];
}

// your function, with y0 fixed. note my gridSize is not a double like yours.
public static double getPoint(int x, int y) {

Vec p = new Vec(x / (double)gridSize, y / (double)gridSize);
Vec d = new Vec(Math.floor(p.x), Math.floor(p.y));

int x0 = (int)d.x,
y0 = (int)d.y;

double d00 = gradient(x0 , y0 ).dot(p.sub(x0 , y0 )),
d01 = gradient(x0 , y0 + 1).dot(p.sub(x0 , y0 + 1)),
d10 = gradient(x0 + 1, y0 ).dot(p.sub(x0 + 1, y0 )),
d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1));

double fadeX = fade(p.x - d.x),
fadeY = fade(p.y - d.y);

double i1 = lerp(fadeX, d00, d10),
i2 = lerp(fadeX, d01, d11);

return lerp(fadeY, i1, i2);

}

public static void main (String[] args) {

// loop forever, regenerating gradients and resampling for range.
while (true) {

initializeGradient();

double minz = 0, maxz = 0;

for (int x = 0; x < gridSize * gridCells; ++ x) {
for (int y = 0; y < gridSize * gridCells; ++ y) {
double z = getPoint(x, y);
if (z < minz)
minz = z;
else if (z > maxz)
maxz = z;
}
}

System.out.println(minz + " " + maxz);

}

}

}

我看到的值在 [-0.707, 0.707] 的理论范围内,尽管我通常看到的值介于 -0.6 和 0.6 之间;这可能只是值分布和低采样率的结果。

关于java - 柏林噪声的输出范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18261982/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com