【问题标题】:Perlin Noise in JavaJava 中的 Perlin 噪声
【发布时间】:2011-07-28 17:03:25
【问题描述】:

对于我正在处理的元胞自动机项目,我需要使用不同的算法和技术随机生成二维布尔数组。目前我在应用程序中只有一种类型的随机化 - 循环遍历数组中的每个单元格并生成一个随机双变量,然后如果随机数高于 0.5,那么我将该单元格设置为 true,如果不是则设置为假。

我想研究使用更有趣的算法(例如 Perlin Noise 或类似的算法)生成这些布尔矩阵。如果您知道除了 Perlin Noise 之外的任何其他东西(Minecraft 的世界生成给了我这个想法),那么在地形生成或类似的东西中使用的噪声生成器可能会很好。

唯一的问题是我不知道从哪里开始(有什么想法吗?):)

【问题讨论】:

    标签: java random noise


    【解决方案1】:

    我首先想到的是随机位移分形。它还用于生成地形,比 Perlin Noise 更容易。

    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();
        }
    }
    

    【讨论】:

    • 我改变(屠宰)了你的源以产生噪声图,蓝色是最低的,黄色是最高的。图像上似乎有明显的线条,最明显的是在“中点”,但在较小程度上是每个“子”中点。有什么方法可以减少或消除这些不连续性?如果有人感兴趣,我可以添加更改后的来源。
    • 这个分形很容易编码,但会产生这些行。对其进行了改进,称为菱形方形分形,旨在最大限度地减少这些伪影。
    • 顺便说一句,我认为我的实现也存在问题。该代码将每边中点的高度设置了两次。这导致了不连续性。如果网格初始化为 Float.NaN 并且每个点只通过测试设置一次,我认为输出会有所改善。
    • 谢谢,这正是我想要的。我已经实现了它并产生了一些有趣的结果。此外,对于该技术的这种应用,您提到的行真的无关紧要并且几乎不可见,因为它以如此低的分辨率使用并且只有布尔值而不是整数。效果很好,再次感谢:)
    • @Andrew Thompson 如果你们有兴趣,我在link 有一个非常项目的早期构建
    【解决方案2】:

    我的库代码中有一些 perlin 噪声实现和其他一些噪声生成函数:

    http://code.google.com/p/mikeralib/source/browse/#svn%2Ftrunk%2FMikera%2Fsrc%2Fmain%2Fjava%2Fmikera%2Fmath

    随意探索/使用(代码是开源 GPL,基于 J3D 代码)。

    【讨论】:

    • 我似乎无法从您的 perlin 函数中得到除了负数或正数 0 浮点数之外的任何东西; ` PerlinNoise perlin = new PerlinNoise(409623546); for(float x=0; x
    • @TimothyGroote 试试这个,它对我有用: double grid[][] = new double[width][height]; for(int y = 0; y
    猜你喜欢
    • 2013-10-11
    • 2012-08-22
    • 2020-06-06
    • 2014-02-15
    • 2021-09-04
    • 2011-09-20
    • 2021-06-30
    • 2013-07-23
    • 2020-06-22
    相关资源
    最近更新 更多