- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我一直在为我想编写的游戏尝试使用 perlin noie generation,但我遇到了一些奇怪的结果。当我让我的代码运行并以灰度绘制结果时,我得到以下图像:
我的代码基于 perlin 噪声的维基百科页面和引用页面之一(下面的链接)。假设基于预先生成的半随机 vector 网格为每个点生成 perlin 噪声点。
public static double[][] generateMap(long seed, int width, int height) {
double[][] map = new double[width][height];
double[][][] grid = generateGrid(seed, (int) (width/10)+1, (int) (height/10)+1);
double max = Double.MIN_VALUE;
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
double p = perlinNoise(((double) i) / 10, ((double) j) / 10, grid);
map[i][j] = p;
max = (max < p) ? p : max;
}
}
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = map[i][j] / max;
}
}
return map;
}
private static double perlinNoise(double x, double y, double[][][] grid) {
int x0 = ((x < 0) ? (int) x-1 : (int) x);
int y0 = ((y < 0) ? (int) y-1 : (int) y);
int x1 = x0 + 1;
int y1 = y0 + 1;
double tx = x - (double)x0;
double ty = y - (double)y0;
double wx = tx*tx*(3-2*tx);
double wy = ty*ty*(3-2*ty);
double l0, l1, ix, iy, p;
l0 = dotGrid(x0, y0, x, y, grid);
l1 = dotGrid(x1, y0, x, y, grid);
ix = cerp(l0, l1, wx);
l0 = dotGrid(x0, y1, x, y, grid);
l1 = dotGrid(x1, y1, x, y, grid);
iy = cerp(l0, l1, wx);
p = cerp(ix, iy, wy);
return p;
}
private static double lerp(double a, double b, double w) {
return (1.0f - w)*a + w*b;
}
private static double cerp(double a, double b, double w) {
double ft = w * 3.1415927;
double f = (1 - Math.cos(ft)) * 0.5;
return a*(1-f) + b*f;
}
private static double dotGrid(int i, int j, double x, double y, double[][][] grid) {
double dx = x - i;
double dy = y - j;
return (dx*grid[i][j][0] + dy*grid[i][j][1]);
}
private static double[][][] generateGrid(long seed, int width, int height) {
Random r = new Random(seed);
double[][][] grid = new double[width][height][2];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
double x = r.nextFloat();
double y = r.nextFloat();
double v = Math.sqrt((x*x) + (y*y));
grid[i][j][0] = x/v;
grid[i][j][1] = y/v;
}
}
return grid;
}
对于那些想要测试我的代码的人,我还将包括我的渲染方法:
private void drawMap(double[][] map, Graphics g) {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
float d = (float) Math.abs(map[i][j]);
d = (d > 1.0f) ? 1.0f : d;
Color c = new Color(d, d, d);
g.setColor(c);
g.fillRect(i, j, 1, 1);
}
}
}
我希望有人能告诉我为什么我的噪音中会有这些奇怪的迷宫般的结构,以及如何摆脱它们。
来源:
http://en.wikipedia.org/wiki/Perlin_noise
http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html
最佳答案
有两个小问题加起来就形成了您所看到的有趣模式。我用 C 语言测试了网格大小为 21x21、输出大小为 200x200 和随机种子为 1234 的东西,但在 Java 中应该同样运行良好。
我的对比原图(因种子不同,但基本和你的一样):
由于您选择了初始随机值,第一个问题出现在 generateGrid()
中。通过使用 nextFloat()
,您可以使用 0 到 1 之间的值,而不是所需的 -1 到 1 范围内的值。解决这个问题很简单:
double x = r.nextFloat()*2.0 - 1.0;
double y = r.nextFloat()*2.0 - 1.0;
并且应该给你类似的东西:
这是一个有趣的模式,在某些情况下可能有用,但不是“正常”的 Perlin 噪声。下一个问题是将 map 值缩放为颜色。您采用的是绝对值,但我相信更好的方法是在 generateMap()
函数中向上移动并重新缩放,例如(未测试):
double max = Double.MIN_VALUE;
double min = Double.MAX_VALUE;
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
double p = perlinNoise(((double) i) / 10, ((double) j) / 10, grid);
map[i][j] = p;
max = (max < p) ? p : max;
min = (min > p) ? p : min;
}
}
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = (map[i][j] - min) / (max - min); //Limit 0 to 1
}
}
这应该将映射值限制为 0-1 的值,这也使您的输出代码更加简单。这会导致更好的 Perlin 噪声输出:
我认为这是“正常”的 Perlin 噪音,至少我看不到任何其他问题,也无法通过测试获得更好的结果。要获得“更好”的噪音,您必须将多个噪音频率加在一起。
我在柏林噪声中看到的图像颜色缩放函数的另一个噪声值是只取 -1.0 为黑色,1.0 为白色,这给你类似的东西:
这与上一个基本相同,但对比度稍差。实际上,如何将噪声值缩放为颜色取决于您。柏林噪声的一个很好的资源是 LibNoise library .它是 C++,但很容易阅读并且有很多资源。
关于java - 柏林噪音发生器的奇怪结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26611906/
我正在尝试在 JS 中设置时区,但无法弄清楚要使用哪个缩写。我尝试了一些,但我可能是这里的问题。 我尝试将 momentjs 与 moment.tz 一起使用。 最佳答案 “欧洲/柏林”就在这里。您可
我已将 ISAPI DLL SOAP 从 Delphi 10 Seattle 迁移到 Delphi 10.1 Berlin Update 2。 迁移后,会引发运行时“抽象异常”。 我注意到“Web.H
为什么我无法解析以下日期? DateTime.parse("2015-03-29 02:35:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
我是一名优秀的程序员,十分优秀!