改进的 Perlin 噪声的范围是多少?

What is the range of improved Perlin noise?

我正在尝试找出 1、2 和 3 维的改进 Perlin 噪声的理论输出范围。我知道这个问题的现有答案,但它们似乎与我的实际发现不符。

如果 n 是维数,那么根据 [1] it should be [-sqrt(n/4), sqrt(n/4)]. According to [2] (which refers to [3]) 它应该是 [-0.5·sqrt(n), 0.5·sqrt(n)] (这相当于同一件事)。

这意味着范围应约为:

Dimensions Range
1 [-0.5, 0.5]
2 [-0.707, 0.707]
3 [-0.866, 0.866]

然而,当我 运行 以下代码(使用 Ken Perlin 的 own reference implementation 从他的网站改进噪音时),我得到更高的 2 维和 3 维值,即大约:

Dimensions Range
1 [-0.5, 0.5]
2 [-0.891, 0.999]
3 [-0.997, 0.999]

对于不同的排列,我什至有时会得到略微 超过 1.0 的 3 个维度的值,并且由于某些奇怪的原因,二维的边界之一似乎总是大约 0.89 而其他大约是1.00.

我不知道这是由于我的代码中的错误(我不知道这是怎么回事,因为这是 Ken Perlin 自己的代码)还是由于这些讨论不正确或不适用,在这种情况下,我想知道改善 Perlin 噪声的理论范围

你能复制这个吗?结果有误吗,或者您能指出与该结果一致的理论值的讨论吗?

代码:

public class PerlinTest {
    public static void main(String[] args) {
        double lowest1DValue = Double.MAX_VALUE, highest1DValue = -Double.MAX_VALUE;
        double lowest2DValue = Double.MAX_VALUE, highest2DValue = -Double.MAX_VALUE;
        double lowest3DValue = Double.MAX_VALUE, highest3DValue = -Double.MAX_VALUE;
        final Random random = new SecureRandom();
        for (int i = 0; i < 10000000; i++) {
            double value = noise(random.nextDouble() * 256.0, 0.0, 0.0);
            if (value < lowest1DValue) {
                lowest1DValue = value;
            }
            if (value > highest1DValue) {
                highest1DValue = value;
            }
            value = noise(random.nextDouble() * 256.0, random.nextDouble() * 256.0, 0.0);
            if (value < lowest2DValue) {
                lowest2DValue = value;
            }
            if (value > highest2DValue) {
                highest2DValue = value;
            }
            value = noise(random.nextDouble() * 256.0, random.nextDouble() * 256.0, random.nextDouble() * 256.0);
            if (value < lowest3DValue) {
                lowest3DValue = value;
            }
            if (value > highest3DValue) {
                highest3DValue = value;
            }
        }
        System.out.println("Lowest 1D value: " + lowest1DValue);
        System.out.println("Highest 1D value: " + highest1DValue);
        System.out.println("Lowest 2D value: " + lowest2DValue);
        System.out.println("Highest 2D value: " + highest2DValue);
        System.out.println("Lowest 3D value: " + lowest3DValue);
        System.out.println("Highest 3D value: " + highest3DValue);
    }

    static public double noise(double x, double y, double z) {
        int X = (int)Math.floor(x) & 255,                  // FIND UNIT CUBE THAT
            Y = (int)Math.floor(y) & 255,                  // CONTAINS POINT.
            Z = (int)Math.floor(z) & 255;
        x -= Math.floor(x);                                // FIND RELATIVE X,Y,Z
        y -= Math.floor(y);                                // OF POINT IN CUBE.
        z -= Math.floor(z);
        double u = fade(x),                                // COMPUTE FADE CURVES
               v = fade(y),                                // FOR EACH OF X,Y,Z.
               w = fade(z);
        int A = p[X  ]+Y, AA = p[A]+Z, AB = p[A+1]+Z,      // HASH COORDINATES OF
            B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;      // THE 8 CUBE CORNERS,

        return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ),  // AND ADD
                                       grad(p[BA  ], x-1, y  , z   )), // BLENDED
                               lerp(u, grad(p[AB  ], x  , y-1, z   ),  // RESULTS
                                       grad(p[BB  ], x-1, y-1, z   ))),// FROM  8
                       lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ),  // CORNERS
                                       grad(p[BA+1], x-1, y  , z-1 )), // OF CUBE
                               lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
                                       grad(p[BB+1], x-1, y-1, z-1 ))));
    }
    static double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); }
    static double lerp(double t, double a, double b) { return a + t * (b - a); }
    static double grad(int hash, double x, double y, double z) {
        int h = hash & 15;                      // CONVERT LO 4 BITS OF HASH CODE
        double u = h<8 ? x : y,                 // INTO 12 GRADIENT DIRECTIONS.
               v = h<4 ? y : h==12||h==14 ? x : z;
        return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
    }
    static final int p[] = new int[512], 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
    };
    static { for (int i=0; i < 256 ; i++) p[256+i] = p[i] = permutation[i]; }
}

Ken 没有使用单位向量。正如 [1] 所说,我强调:

Third, there are many different ways to select the random vectors at the grid cell corners. In Improved Perlin noise, instead of selecting any random vector, one of 12 vectors pointing to the edges of a cube are used instead. Here, I will talk strictly about a continuous range of angles since it is easier – however, the range of value of an implementation of Perlin noise using a restricted set of vectors will never be larger. Finally, the script in this repository assumes the vectors are of unit length. If they not, the range of value should be scaled according to the maximum vector length. Note that the vectors in Improved Perlin noise are not unit length.

对于Ken的改进噪声,最大矢量长度在一维为1,在二维为√2,因此理论边界在一维为[−0.5, 0.5],在二维为[−1, 1]。我不知道您为什么看不到 2D 的完整范围;如果你打乱排列我打赌你有时会。

对于3D,最大向量长度仍然是√2,但是[1]标识的极端情况不是可能的输出,所以[−√(3/2), √(3 /2)] 是一个高估。 These folks 试图准确计算出来,是的,最大绝对值似乎确实严格大于 1。