Java 如何提高柏林噪声分布的标准差

Java 如何提高柏林噪声分布的标准差,java,normal-distribution,perlin-noise,Java,Normal Distribution,Perlin Noise,我一直遵循柏林噪音指南: 我使用的代码与他描述的完全相同,尽管我的渲染实现不同。然而,当我从这个分布中得到噪声时,我倾向于在0.5范围附近得到很大一部分值,而在条纹上则很少。你可以从一个样本中看到这一点,我在下图中将其转换为一个快速图形。我根据屏幕的宽度缩放了我的噪波函数,并让它在index=noise处的数组每次生成噪波值时递增1。正如你所看到的,这种分布很难是正常的,因为边缘完全消失了。(从技术上讲,它是一个没有标签和条线的直方图) 使这种分布向底部而不是向顶部更宽的最佳方法是什么?我希望

我一直遵循柏林噪音指南:

我使用的代码与他描述的完全相同,尽管我的渲染实现不同。然而,当我从这个分布中得到噪声时,我倾向于在0.5范围附近得到很大一部分值,而在条纹上则很少。你可以从一个样本中看到这一点,我在下图中将其转换为一个快速图形。我根据屏幕的宽度缩放了我的噪波函数,并让它在
index=noise
处的数组每次生成噪波值时递增1。正如你所看到的,这种分布很难是正常的,因为边缘完全消失了。(从技术上讲,它是一个没有标签和条线的直方图)

使这种分布向底部而不是向顶部更宽的最佳方法是什么?我希望大多数值都是高斯分布,但我不能只使用高斯分布的随机数,因为我需要选择彼此接近的值来彼此接近(柏林噪声)

我想一个更好的提问方式是:为什么我的范围的上下四分之一没有噪声值?有没有办法确定一个好的比例因子来扩大图形

下面是我用来获取图像的代码:

/**
 * Simple linear interpolation
 * @param a Start
 * @param b End
 * @param weight weighting
 * @return A linear interpolation between points a and b 
 */
public double lerp(double a, double b, double weight) {
    return a + weight*(b-a);
}

/**
 * Calculates a dot product between a distance vector and a pseudorandom
 * "gradient" vector which gets picked using the hash
 * @param hash
 * @param x distance vector x component
 * @param y distance vector y component
 * @param z distance vector z component (z = 0 for 2D map)
 * @return dot product of <x, y, z> and a pseudorandom gradient vector
 */
public double grad(int hash, double x, double y, double z) {
    switch(hash & 0xF)
    {
        case 0x0: return  x + y;
        case 0x1: return -x + y;
        case 0x2: return  x - y;
        case 0x3: return -x - y;
        case 0x4: return  x + z;
        case 0x5: return -x + z;
        case 0x6: return  x - z;
        case 0x7: return -x - z;
        case 0x8: return  y + z;
        case 0x9: return -y + z;
        case 0xA: return  y - z;
        case 0xB: return -y - z;
        case 0xC: return  y + x;
        case 0xD: return -y + z;
        case 0xE: return  y - x;
        case 0xF: return -y - z;
        default: return 0; // never happens
    }
}

/**
 * A fifth order fade function: 6t^5 - 15t^4 + 10t^3
 * @param t The x-value along the function, t is in [0, 1]
 * @return The y-value for the fade function
 */
public double fade(double t) {
    return t * t * t * (t * (t * 6 - 15) + 10);
}

//repeat is set to 0 so this method is just a regular "increment by 1"
public int inc(int num) {
    num++;
    if(repeat > 0) num %= repeat;
    return num;
}

/**
 * Generates a noise value in the range [0,1].
 * Each coordinate is a given distance from a pseudorandomly picked set of
 * gradient vectors. The vectors are determined by an array of 256 indexes,
 * so the noise pattern inevitably repeats at a scale greater than 255,
 * which is bigger than we should need.
 * @param x
 * @param y
 * @param z
 * @return 
 */
public double perlin(double x, double y, double z) {
    if(repeat > 0) {
        x = x%repeat;
        y = y%repeat;
        z = z%repeat;
    }

    int xi = (int)x & 255;
    int yi = (int)y & 255;
    int zi = (int)z & 255;
    double xf = x-(int)x;
    double yf = y-(int)y;
    double zf = z-(int)z;


    double u = fade(xf);
    double v = fade(yf);
    double w = fade(zf);

    int aaa, aba, aab, abb, baa, bba, bab, bbb;
    aaa = p[p[p[    xi ]+    yi ]+    zi ];
    aba = p[p[p[    xi ]+inc(yi)]+    zi ];
    aab = p[p[p[    xi ]+    yi ]+inc(zi)];
    abb = p[p[p[    xi ]+inc(yi)]+inc(zi)];
    baa = p[p[p[inc(xi)]+    yi ]+    zi ];
    bba = p[p[p[inc(xi)]+inc(yi)]+    zi ];
    bab = p[p[p[inc(xi)]+    yi ]+inc(zi)];
    bbb = p[p[p[inc(xi)]+inc(yi)]+inc(zi)];


    double x1, x2, y1, y2;

    /*
    Box has corners:
    ____
    |ab|
    |cd|
    ----
    Interpolate a-b, then c-d then both of those together, then repeat on the z-1 level
    */
    x1 = lerp(grad (aaa, xf  , yf  , zf),           // The gradient function calculates the dot product between a pseudorandom
              grad (baa, xf-1, yf  , zf),             // gradient vector and the vector from the input coordinate to the 8
              u);                                     // surrounding points in its unit cube.
    x2 = lerp(grad (aba, xf  , yf-1, zf),
              grad (bba, xf-1, yf-1, zf),
              u);
    y1 = lerp(x1, x2, v);

    x1 = lerp(grad (aab, xf  , yf  , zf-1),
              grad (bab, xf-1, yf  , zf-1),
              u);
    x2 = lerp(grad (abb, xf  , yf-1, zf-1),
              grad (bbb, xf-1, yf-1, zf-1),
              u);
    y2 = lerp (x1, x2, v);

    return (lerp (y1, y2, w)+1)/2; //Interpolate everything again and move the range from [-1, 1] to [0, 1]
}

/**
 * Layers levels of noise, each with decreasing amplitudes and persistence
 * @param x
 * @param y
 * @param z
 * @param octaves
 * @param persistence how much each layer impacts the layer below it
 * @return
 */
public double octave(double x, double y, double z, int octaves, double persistence) {
    double total = 0, frequency = 1, amplitude = 1, maxValue = 0;
    for(int i = 0; i < octaves; i++) {
        total += perlin(x * frequency, y * frequency, z * frequency) * amplitude;
        maxValue += amplitude;
        amplitude *= persistence;
        frequency *= 2;
    }

    return total/maxValue;
}
所有从0到255的数字都是按随机顺序排列的


再次重申一下这个问题,该函数生成的数字比例很大,介于0.45和0.55之间,几乎没有超出该范围的数字。我想重新调整函数的比例,以便在这些下限和上限中获得更多的数字。这可能发生在
perlin()
函数的最后一行的某个地方,但我不知道该怎么做。谢谢您的帮助。

我已通过以下方法解决了此问题

首先,在生成噪波值时,我跟踪最小值和最大值

其次,在将噪波值存储到数组中时,我规范化了数据:
(值-最小值)/(最大值-最小值)。这样,我的所有值都在0和1之间,但分布更好。该方程将最小值映射到(min-min)/(max-min)或0,将最大值映射到(max-min)/(max-min)或1,并缩放中间的所有值。

这是您所说的高斯分布的一阶近似值-您希望图像角落中空白的值在哪里?我不知道柏林,但如果你把代码放出来,我们可能会找到bug@gpasch问题是,我认为高斯分布不起作用,因为噪声值不应该是独立随机的,而是随着时间的推移建立在平面上。给我一点时间,我会发布代码。他们的任何视觉作品都显示在你的输出中吗?@Pikalek没有,但我找到了解决这个问题的方法,我在下面发布了答案。
public void enter() {
    eOffsetX = r.nextInt(10000);
    eOffsetY = r.nextInt(10000); //This will "randomize" the seed of the noise
    p = new int[512];
    for(int x = 0; x < 512; x++) {
        p[x] = permutation[x%256]; //Fill twice
    }
    eNoise = new float[(int)(1280/tile)][(int)(800/tile)];
    gauss = new float[1280];
    Arrays.fill(gauss, 0);

    for(int i = 0; i < eNoise.length; i++) {
        for(int j = 0; j < eNoise[0].length; j++) {
            eNoise[i][j] = 1f * 100 * (float) octave(((double)i*zoom+eOffsetX)/1280, ((double)j*zoom+eOffsetY)/800, 0, 7, 0.60);
            gauss[(int)(((eNoise[i][j]/100)-.5)*1280*2.5+640)] += 1f;
        }
    }}
public void render(Graphics g) {
        g.setBackground(Color.white);
        g.setColor(Color.black);
        for(int k = 0; k < 1280; k++) {
            g.fillRect(k, 800-(gauss[k]/10), 5, 5);
        }
}
private static final int[] permutation = { 151,160,137,91,90,15,
    131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
    190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
    88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
    77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
    102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
    135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
    5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
    223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
    129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
    251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
    49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
    138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};