Did*_*diZ 6 java normal-distribution perlin-noise
我正在编写一个基于perlin噪声的地图生成器,并遇到了一个问题:
让我们说我想要30%的水和70%的污垢瓷砖.使用通常的随机生成器没有问题:
tile = rnd.nextFloat() < 0.7f ? DIRT : WATER;
Run Code Online (Sandbox Code Playgroud)
但是perlin噪声是正态分布的(范围从-1到1,意思是0)所以它并不那么容易.
有没有人知道将法线转换为均匀分布的方法或不同的方法我可以从噪声值中获得百分比?
编辑:70%只是一个例子,我希望能够动态使用任何值,最多只有0.1%的精度.
编辑2:我想将perlin噪声转换为均匀分布,而不是正常(它已经是相似的).
这是一个分析解决方案,它不依赖于保留数据,并且是连续的。按照此处描述的方法,我生成了柏林噪声值的直方图,然后通过对直方图求和来近似连续分布函数,因此cdf(x)
cdf(x) = sum(histogram[i] for all i < x)
Run Code Online (Sandbox Code Playgroud)
然后我使用 Wolfram Alpha 来近似cdf(x)五次多项式。这给了我这个功能:
function F(x) { return (((((0.745671 * x + 0.00309887) * x - 1.53841) * x - 0.00343488) * x + 1.29551) * x) + 0.500516;
Run Code Online (Sandbox Code Playgroud)
x^5+0.00309887 x^4-1.53841 x^3-0.00343488 x^2+1.29551 x+0.500516 u = (u + 0.002591009999999949) / 1.0055419999999997; // 交叉 (0,0) 和 (1,1)
F(x) = 0.745671 x^5 + 0.00309887 x^4 - 1.53841 x^3 - 0.00343488 x^2 + 1.29551 x + 0.500516
Run Code Online (Sandbox Code Playgroud)
现在F(perlin.noise2(...))相当接近均匀分布。
这个函数并没有完全通过点(-1,0),(1,1)所以你可以将其更正为
F1(x) = (F(x) + 0.002591009999999949) / 1.0055419999999997
Run Code Online (Sandbox Code Playgroud)
该函数也会偏离 1 附近x = 1和 0 附近 附近x = -1,因此如果这对您很重要,您应该将其限制在 0 和 1 之间。
F2(x) = max(min(F1(x), 1), 0)
Run Code Online (Sandbox Code Playgroud)
(除非有人想要更多细节,否则我会保持这个非常简洁。如果是的话请发表评论。)
我想出的一个解决方案:首先,我生成 100,000,000 个柏林噪声并将它们存储在一个数组中。我对它进行排序,然后我可以将每 10,000 个值作为千分之一的阈值。现在我可以对这些阈值进行硬编码,因此我只有一个包含 1,000 个浮点数的数组用于在运行时查找。
优点:
它真的很快,因为它只是在运行时访问一个数组。
缺点:
如果更改算法,则必须重新生成阈值数组。其次,平均值缩放至大约每千分之 10,使 50% 阈值为 49.5% 或 50.5%(取决于您是否使用 < 或 <= 比较器)。第三,增加了内存占用(每精度 4kb)。您可以通过使用百分比精度或对数精度刻度来降低它。
生成代码:
final PerlinNoiseGenerator perlin = new PerlinNoiseGenerator(new Random().nextInt());
final int size = 10000; //Size gets sqared, so it's actually 100,000,000
final float[] values = new float[size * size];
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++) {
final float value = perlin.noise2(x / 10f, y / 10f);
values[x * size + y] = value;
}
System.out.println("Calculated");
Arrays.sort(values);
System.out.println("Sorted");
final float[] steps = new float[1000];
steps[999] = 1;
for (int i = 0; i < 999; i++)
steps[i] = values[size * size / 1000 * (i + 1)];
System.out.println("Calculated steps");
for (int i = 0; i < 10; i++) {
System.out.println();
for (int j = 0; j < 100; j++)
System.out.print(steps[i * 100 + j] + "f, "); //Output usuable for array initialization
System.out.println();
System.out.println();
}
Run Code Online (Sandbox Code Playgroud)
查找代码:
public final static float[] perlinThresholds = new float[]{}; //Initialize it with the generated thresholds.
public static float getThreshold(float percent) {
return perlinThresholds[(int)(percent * 1000)];
}
public static float getThreshold(int promill) {
return perlinThresholds[promill];
}
X
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1528 次 |
| 最近记录: |