Java中的Perlin噪声

10
为了我的细胞自动机项目,我需要使用不同的算法和技术随机生成二维布尔数组。目前应用程序中只有一种类型的随机化 - 循环遍历数组中的每个单元格并生成一个随机双精度变量,然后如果随机数大于0.5,则将该单元格设置为true,否则设置为false。
我想研究使用更有趣的算法(如Perlin噪声或类似算法)来生成这些布尔矩阵。如果您知道用于地形生成或其他用途的噪声生成器,例如除了Perlin噪声之外的其他噪声生成器,那么可能会很好。唯一的问题是我不知道从哪里开始(有任何想法吗?) :)
2个回答

11

我首先想到的是随机位移分形。它也可以用于生成地形,比Perlin噪声更容易。

package so;

import java.util.Random;

public class Noise {
    /** Source of entropy */
    private Random rand_;

    /** Amount of roughness */
    float roughness_;

    /** Plasma fractal grid */
    private float[][] grid_;


    /** Generate a noise source based upon the midpoint displacement fractal.
     * 
     * @param rand The random number generator
     * @param roughness a roughness parameter
     * @param width the width of the grid
     * @param height the height of the grid
     */
    public Noise(Random rand, float roughness, int width, int height) {
        roughness_ = roughness / width;
        grid_ = new float[width][height];
        rand_ = (rand == null) ? new Random() : rand;
    }


    public void initialise() {
        int xh = grid_.length - 1;
        int yh = grid_[0].length - 1;

        // set the corner points
        grid_[0][0] = rand_.nextFloat() - 0.5f;
        grid_[0][yh] = rand_.nextFloat() - 0.5f;
        grid_[xh][0] = rand_.nextFloat() - 0.5f;
        grid_[xh][yh] = rand_.nextFloat() - 0.5f;

        // generate the fractal
        generate(0, 0, xh, yh);
    }


    // Add a suitable amount of random displacement to a point
    private float roughen(float v, int l, int h) {
        return v + roughness_ * (float) (rand_.nextGaussian() * (h - l));
    }


    // generate the fractal
    private void generate(int xl, int yl, int xh, int yh) {
        int xm = (xl + xh) / 2;
        int ym = (yl + yh) / 2;
        if ((xl == xm) && (yl == ym)) return;

        grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]);
        grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]);
        grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]);
        grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]);

        float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh
                + xh);
        grid_[xm][ym] = v;
        grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh);
        grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh);
        grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh);
        grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh);

        generate(xl, yl, xm, ym);
        generate(xm, yl, xh, ym);
        generate(xl, ym, xm, yh);
        generate(xm, ym, xh, yh);
    }


    /**
     * Dump out as a CSV
     */
    public void printAsCSV() {
        for(int i = 0;i < grid_.length;i++) {
            for(int j = 0;j < grid_[0].length;j++) {
                System.out.print(grid_[i][j]);
                System.out.print(",");
            }
            System.out.println();
        }
    }


    /**
     * Convert to a Boolean array
     * @return the boolean array
     */
    public boolean[][] toBooleans() {
        int w = grid_.length;
        int h = grid_[0].length;
        boolean[][] ret = new boolean[w][h];
        for(int i = 0;i < w;i++) {
            for(int j = 0;j < h;j++) {
                ret[i][j] = grid_[i][j] < 0;
            }
        }
        return ret;
    }


    /** For testing */
    public static void main(String[] args) {
        Noise n = new Noise(null, 1.0f, 250, 250);
        n.initialise();
        n.printAsCSV();
    }
}

随机位移分形图 1 随机位移分形图 2 随机位移分形图 3


我修改了(破坏了)你的源代码,以生成噪声图,其中蓝色表示最低值,黄色表示最高值。图像上似乎有明显的线条,尤其是在“中点”处,但在每个“子”中点处也有一定程度的线条。有没有办法减少或消除这些不连续性?如果有人感兴趣,我可以添加修改后的源代码。 - Andrew Thompson
2
这个分形很容易编码,但会产生这些线条。有一个改进版叫做钻石广场分形,据说可以最小化这些伪影。 - Simon G.
顺便说一句,我认为我的实现也存在问题。代码会两次设置每个边中点的高度,这会导致不连续性。如果将网格初始化为Float.NaN,并通过测试仅设置每个点一次,我认为输出将得到改善。 - Simon G.
谢谢,这正是我在寻找的。我已经实现了它,并且产生了一些有趣的结果。此外,对于这种技术的应用,您提到的那些行并不重要,因为它被用于如此低的分辨率,并且只有布尔值而不是整数。效果很好,所以再次感谢 :) - jt78
@Andrew Thompson 如果你们中有人感兴趣,我已经在链接上发布了一个非常早期的项目版本。 - jt78
@SimonG. 为什么你在字段变量名后面加下划线?这是一个好的习惯吗?只是好奇。 - Kartik Chugh

3

我似乎只能从你的Perlin函数中得到负数或正数0浮点数;PerlinNoise perlin = new PerlinNoise(409623546); for(float x=0; x < 100; x++) { for(float y=0; y < 100; y++) { System.out.println(perlin.noise1(y)*100000); } } - Timothy Groote
@TimothyGroote 试一下这个,我用过了: double grid[][] = new double[width][height]; for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { double v = 0; for(int i = 2; i <= 32; i = i * i) { double n = perlin.noise2(i * x / (float) width, i * y / (float) height); v += n / i; } grid[x][y] = v; } } - Ed_le_fou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接