【发布时间】:2013-06-29 22:20:59
【问题描述】:
我使用 perlin 噪声来生成 2D 高度图。起初,我手动尝试了一些参数,发现幅度、持久性……适合我的工作。
现在我正在开发程序,我为用户添加了更改地图参数并为自己制作新地图的功能,但现在我看到某些参数(主要是八度音阶和频率)的值不在我以前看到的范围。我认为如果设置 Amplitude = 20,我从中获得的值(高度)将在 [0,20] 或 [-10,10] 或 [-20,20] 范围内,但现在我看到 Amplitude 是不是控制输出范围的唯一参数。
我的问题是: 是否有一个精确的数学公式(振幅、八度、频率和持久性的函数)来计算范围,或者我应该采取大量样本(如 100,000)并检查它们的最小值和最大值来猜测近似范围?
注意:下面的代码是一个 perlin 噪声的实现,stackoverflow 的一个人用 C 编写了它,我将它移植到了 java。
PerlinNoiseParameters.java
public class PerlinNoiseParameters {
public double persistence;
public double frequency;
public double amplitude;
public int octaves;
public int randomseed;
public PerlinNoiseParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
this.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed);
}
public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
this.persistence = persistence;
this.frequency = frequency;
this.amplitude = amplitude;
this.octaves = octaves;
this.randomseed = 2 + randomseed * randomseed;
}
}
PerlinNoiseGenerator.java
public class PerlinNoiseGenerator {
PerlinNoiseParameters parameters;
public PerlinNoiseGenerator() {
}
public PerlinNoiseGenerator(PerlinNoiseParameters parameters) {
this.parameters = parameters;
}
public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
parameters.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed);
}
public void ChangeParameters(PerlinNoiseParameters newParams) {
parameters = newParams;
}
public double get(double x, double y) {
return parameters.amplitude * Total(x, y);
}
private double Total(double i, double j) {
double t = 0.0f;
double _amplitude = 1;
double freq = parameters.frequency;
for (int k = 0; k < parameters.octaves; k++) {
t += GetValue(j * freq + parameters.randomseed, i * freq + parameters.randomseed)
* _amplitude;
_amplitude *= parameters.persistence;
freq *= 2;
}
return t;
}
private double GetValue(double x, double y) {
int Xint = (int) x;
int Yint = (int) y;
double Xfrac = x - Xint;
double Yfrac = y - Yint;
double n01 = Noise(Xint - 1, Yint - 1);
double n02 = Noise(Xint + 1, Yint - 1);
double n03 = Noise(Xint - 1, Yint + 1);
double n04 = Noise(Xint + 1, Yint + 1);
double n05 = Noise(Xint - 1, Yint);
double n06 = Noise(Xint + 1, Yint);
double n07 = Noise(Xint, Yint - 1);
double n08 = Noise(Xint, Yint + 1);
double n09 = Noise(Xint, Yint);
double n12 = Noise(Xint + 2, Yint - 1);
double n14 = Noise(Xint + 2, Yint + 1);
double n16 = Noise(Xint + 2, Yint);
double n23 = Noise(Xint - 1, Yint + 2);
double n24 = Noise(Xint + 1, Yint + 2);
double n28 = Noise(Xint, Yint + 2);
double n34 = Noise(Xint + 2, Yint + 2);
double x0y0 = 0.0625 * (n01 + n02 + n03 + n04) + 0.1250
* (n05 + n06 + n07 + n08) + 0.2500 * n09;
double x1y0 = 0.0625 * (n07 + n12 + n08 + n14) + 0.1250
* (n09 + n16 + n02 + n04) + 0.2500 * n06;
double x0y1 = 0.0625 * (n05 + n06 + n23 + n24) + 0.1250
* (n03 + n04 + n09 + n28) + 0.2500 * n08;
double x1y1 = 0.0625 * (n09 + n16 + n28 + n34) + 0.1250
* (n08 + n14 + n06 + n24) + 0.2500 * n04;
double v1 = Interpolate(x0y0, x1y0, Xfrac);
double v2 = Interpolate(x0y1, x1y1, Xfrac);
double fin = Interpolate(v1, v2, Yfrac);
return fin;
}
private double Interpolate(double x, double y, double a) {
double negA = 1.0 - a;
double negASqr = negA * negA;
double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA);
double aSqr = a * a;
double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a);
return x * fac1 + y * fac2;
}
private double Noise(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff;
return 1.0 - (double) t * 0.931322574615478515625e-9;
}
}
【问题讨论】:
-
值得注意的是,柏林噪声的结果严重偏向于 0,因此即使 [-10,10] 是整个范围,您也只会希望定期看到该范围的中心,例如[-5,5]。我相信,如果您采集的样本数量过多,则范围将始终为 [-amplitude,amplitude]
-
@RichardTingle 所以你建议抽样方法,因为它更真实可用。对吗?
-
好吧,是的,不是的。我在我的程序中设置了一个 simplexNoise 生成器(simplex 噪声是 perlin 噪声的升级),如果我要求 1000 个样本,最小/最大值为 -0.67/0.77,1000000 个样本的最小值/最大值为 -0.83 /0.80,如果我要求 10000000 个样本,它的 -0.84/0.87。
-
所以我的意思是范围不是一个有用的数量,因为给定足够的样本,对于任何八度、频率和持久性,它都趋向于 [-1,1]。它只是它趋向于 [-1,1] 的变化率
-
或者更准确地说,对于任何八度音阶、频率和持久性,它倾向于 [ - 幅度,+ 幅度]
标签: java perlin-noise