Minecraft的世界生成過程(三)噪聲函數

接下來的地形生成代碼會接觸到噪聲函數,所以本篇內容就先逆向MC的噪聲函數吧

噪聲函數就是比較好看的隨機數,如果用純隨機數(白噪聲)不適合生成地形,但是噪聲函數就很適合

具體的噪聲介紹可以參考這篇文章,建議先閱讀一下,否則後面的算法可能看不懂…

各種NoiseGenerator

在包net.minecraft.world.gen裏可以看到幾個噪聲生成器,它們的命名比較亂所以不要看類名來推斷算法(本來柏林噪聲的命名就經常被混淆),其實MC裏只有Perlin噪聲和Simplex噪聲

NoiseGeneratorImproved

用來生成一個柏林噪聲

public class NoiseGeneratorImproved extends NoiseGenerator
{
    // 0~255的隨機排列
    private int[] permutations;
    // 座標偏移量
    public double xCoord;
    public double yCoord;
    public double zCoord;
    // 三維梯度向量,去掉y維度後和二維的一樣
    private static final double[] field_152381_e = new double[] {1.0D, -1.0D,  1.0D, -1.0D, 1.0D, -1.0D,  1.0D, -1.0D, 0.0D,  0.0D,  0.0D,  0.0D, 1.0D,  0.0D, -1.0D,  0.0D};
    private static final double[] field_152382_f = new double[] {1.0D,  1.0D, -1.0D, -1.0D, 0.0D,  0.0D,  0.0D,  0.0D, 1.0D, -1.0D,  1.0D, -1.0D, 1.0D, -1.0D,  1.0D, -1.0D};
    private static final double[] field_152383_g = new double[] {0.0D,  0.0D,  0.0D,  0.0D, 1.0D,  1.0D, -1.0D, -1.0D, 1.0D,  1.0D, -1.0D, -1.0D, 0.0D,  1.0D,  0.0D, -1.0D};
    // 二維梯度向量
    private static final double[] field_152384_h = new double[] {1.0D, -1.0D,  1.0D, -1.0D, 1.0D, -1.0D,  1.0D, -1.0D, 0.0D,  0.0D,  0.0D,  0.0D, 1.0D,  0.0D, -1.0D,  0.0D};
    private static final double[] field_152385_i = new double[] {0.0D,  0.0D,  0.0D,  0.0D, 1.0D,  1.0D, -1.0D, -1.0D, 1.0D,  1.0D, -1.0D, -1.0D, 0.0D,  1.0D,  0.0D, -1.0D};

    public NoiseGeneratorImproved()
    {
        this(new Random());
    }

    public NoiseGeneratorImproved(Random rand)
    {
        this.permutations = new int[512];
        this.xCoord = rand.nextDouble() * 256.0D;
        this.yCoord = rand.nextDouble() * 256.0D;
        this.zCoord = rand.nextDouble() * 256.0D;

        // 生成0~255的隨機排列

        for (int i = 0; i < 256; ++i)
        {
            this.permutations[i] = i;
        }

        for (int i = 0; i < 256; ++i)
        {
            // 從i~255中選j
            int j = rand.nextInt(256 - i) + i;
            // 把i和j交換
            int t = this.permutations[i];
            this.permutations[i] = this.permutations[j];
            this.permutations[j] = t;
            // 形成一個週期
            this.permutations[i + 256] = this.permutations[i];
        }
    }

    // 在a與b間線性插值
    public final double lerp(double t, double a, double b)
    {
        return a + t * (b - a);
    }

    // 返回與二維梯度向量點乘的結果,參數:梯度向量索引, 向量(其實就是權重)
    public final double func_76309_a(int index, double xWeight, double zWeight)
    {
        int i = index % 16;
        return   field_152384_h[i] * xWeight
               + field_152385_i[i] * zWeight;
    }

    // 返回與三維梯度向量點乘的結果,參數:梯度向量索引, 向量(其實就是權重)
    public final double grad(int index, double xWeight, double yWeight, double zWeight)
    {
        int i = index % 16;
        return   field_152381_e[i] * xWeight 
               + field_152382_f[i] * yWeight
               + field_152383_g[i] * zWeight;
    }

    /**
     * pars: noiseArray , xOffset , yOffset , zOffset , xSize , ySize , zSize , xScale, yScale , zScale , noiseScale.
     * noiseArray should be xSize*ySize*zSize in size
     */
    // 這個noiseScale和振幅成反比...
    public void populateNoiseArray(double[] result, double xOffset, double yOffset, double zOffset, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale, double noiseScale)
    {
        if (ySize == 1) // 二維
        {
            int resultIndex = 0;
            // 結果縮放係數,和noiseScale成反比
            double noiseRatio = 1.0D / noiseScale;

            for (int _x = 0; _x < xSize; ++_x)
            {
                // 經過偏移和縮放的x
                double x = xOffset + (double)_x * xScale + this.xCoord;
                // 不大於x的最大整數
                int xFloor = (int)x;
                if (x < (double)xFloor)
                {
                    --xFloor;
                }

                int xIndex = xFloor % 256;
                // 此時x爲晶格內的座標[0, 1)
                x = x - (double)xFloor;
                // 緩和曲線s(t) = 6t^5 - 15t^4 + 10t^3
                double sx = x * x * x * (x * (x * 6.0D - 15.0D) + 10.0D);

                for (int _z = 0; _z < zSize; ++_z)
                {
                    // 經過偏移和縮放的z
                    double z = zOffset + (double)_z * zScale + this.zCoord;
                    // 不大於z的最大整數
                    int zFloor = (int)z;
                    if (z < (double)zFloor)
                    {
                        --zFloor;
                    }

                    int zIndex = zFloor % 256;
                    // 此時z爲晶格內的座標[0, 1)
                    z = z - (double)zFloor;
                    // 緩和曲線s(t) = 6t^5 - 15t^4 + 10t^3
                    double sz = z * z * z * (z * (z * 6.0D - 15.0D) + 10.0D);

                    // 取梯度向量G=G[(i+P[j])mod n]
                    // 左上角梯度向量索引
                    int vecIndex1 = this.permutations[this.permutations[xIndex]] + zIndex;
                    // 右上角梯度向量索引
                    int vecIndex2 = this.permutations[this.permutations[xIndex + 1]] + zIndex;

                    // x方向上點乘(加權),結果用緩和曲線插值
                    double xRes1 = this.lerp(sx,
                                             this.func_76309_a(this.permutations[vecIndex1],          x ,       z),
                                             this.grad(        this.permutations[vecIndex2], -(1.0D - x), 0.0D, z));
                    double xRes2 = this.lerp(sx,
                                             this.grad(this.permutations[vecIndex1 + 1],          x , 0.0D, -(1.0D - z)),
                                             this.grad(this.permutations[vecIndex2 + 1], -(1.0D - x), 0.0D, -(1.0D - z)));
                    // 兩個x方向的結果在z方向用緩和曲線插值
                    double res = this.lerp(sz, xRes1, xRes2);

                    result[resultIndex++] += res * noiseRatio;
                }
            }
        }
        else // 三維,參考上面,懶得寫註釋和反混淆了...
        {
            int resultIndex = 0;
            double noiseRatio = 1.0D / noiseScale;
            int lastYIndex = -1;

            for (int _x = 0; _x < xSize; ++_x)
            {
                double x = xOffset + (double)_x * xScale + this.xCoord;
                int xFloor = (int)x;

                if (x < (double)xFloor)
                {
                    --xFloor;
                }

                int xIndex = xFloor % 256;
                x = x - (double)xFloor;
                double sx = x * x * x * (x * (x * 6.0D - 15.0D) + 10.0D);

                for (int _z = 0; _z < zSize; ++_z)
                {
                    double z = zOffset + (double)_z * zScale + this.zCoord;
                    int zFloor = (int)z;

                    if (z < (double)zFloor)
                    {
                        --zFloor;
                    }

                    int zIndex = zFloor % 256;
                    z = z - (double)zFloor;
                    double sz = z * z * z * (z * (z * 6.0D - 15.0D) + 10.0D);

                    double xRes1, xRes2, xRes3, xRes4;

                    for (int _y = 0; _y < ySize; ++_y)
                    {
                        double y = yOffset + (double)_y * yScale + this.yCoord;
                        int yFloor = (int)y;

                        if (y < (double)yFloor)
                        {
                            --yFloor;
                        }

                        int yIndex = yFloor % 256;
                        y = y - (double)yFloor;
                        double sy = y * y * y * (y * (y * 6.0D - 15.0D) + 10.0D);

                        if (_y == 0 || yIndex != lastYIndex)
                        {
                            lastYIndex = yIndex;
                            int l = this.permutations[xIndex] + yIndex;
                            int i1 = this.permutations[l] + zIndex;
                            int j1 = this.permutations[l + 1] + zIndex;
                            int k1 = this.permutations[xIndex + 1] + yIndex;
                            int l1 = this.permutations[k1] + zIndex;
                            int i2 = this.permutations[k1 + 1] + zIndex;
                            xRes1 = this.lerp(sx, this.grad(this.permutations[i1], x, y, z), this.grad(this.permutations[l1], x - 1.0D, y, z));
                            xRes2 = this.lerp(sx, this.grad(this.permutations[j1], x, y - 1.0D, z), this.grad(this.permutations[i2], x - 1.0D, y - 1.0D, z));
                            xRes3 = this.lerp(sx, this.grad(this.permutations[i1 + 1], x, y, z - 1.0D), this.grad(this.permutations[l1 + 1], x - 1.0D, y, z - 1.0D));
                            xRes4 = this.lerp(sx, this.grad(this.permutations[j1 + 1], x, y - 1.0D, z - 1.0D), this.grad(this.permutations[i2 + 1], x - 1.0D, y - 1.0D, z - 1.0D));
                        }

                        double yRes1 = this.lerp(sy, xRes1, xRes2);
                        double yRes2 = this.lerp(sy, xRes3, xRes4);
                        double res = this.lerp(sz, yRes1, yRes2);

                        result[resultIndex++] += res * noiseRatio;
                    }
                }
            }
        }
    }
}

NoiseGeneratorOctaves

用來把多個NoiseGeneratorImproved分形疊加

public class NoiseGeneratorOctaves extends NoiseGenerator
{
    /** Collection of noise generation functions.  Output is combined to produce different octaves of noise. */
    private NoiseGeneratorImproved[] generatorCollection;
    private int octaves;

    public NoiseGeneratorOctaves(Random rand, int octaveCount)
    {
        this.octaves = octaveCount;
        this.generatorCollection = new NoiseGeneratorImproved[octaveCount];

        for (int i = 0; i < octaveCount; ++i)
        {
            this.generatorCollection[i] = new NoiseGeneratorImproved(rand);
        }
    }

    /**
     * pars:(par2,3,4=noiseOffset ; so that adjacent noise segments connect) (pars5,6,7=x,y,zArraySize),(pars8,10,12 =
     * x,y,z noiseScale)
     */
    public double[] generateNoiseOctaves(double[] result, int x, int y, int z, int xArraySize, int yArraySize, int zArraySize, double xScale, double yScale, double zScale)
    {
        if (result == null)
        {
            result = new double[xArraySize * yArraySize * zArraySize];
        }
        else
        {
            // 結果清0,因爲後面會疊加
            for (int i = 0; i < result.length; ++i)
            {
                result[i] = 0.0D;
            }
        }

        // 控制倍頻函數的頻率、幅度
        double scale = 1.0D;

        // 遍歷倍頻函數
        for (int i = 0; i < this.octaves; ++i)
        {
            double x2 = (double)x * scale * xScale;
            double y2 = (double)y * scale * yScale;
            double z2 = (double)z * scale * zScale;

            // 這部分大概是防止溢出的
            // x2Floor爲不大於x2的最大整數
            long x2Floor = MathHelper.floor_double_long(x2);
            long z2Floor = MathHelper.floor_double_long(z2);
            x2 = x2 - (double)x2Floor;
            z2 = z2 - (double)z2Floor;
            x2Floor = x2Floor % 0x1000000L;
            z2Floor = z2Floor % 0x1000000L;
            x2 = x2 + (double)x2Floor;
            z2 = z2 + (double)z2Floor;

            // 疊加
            this.generatorCollection[i].populateNoiseArray(result, x2, y2, z2, xArraySize, yArraySize, zArraySize, xScale * scale, yScale * scale, zScale * scale, scale);
            // 頻率減半,幅度加倍
            scale /= 2.0D;
        }

        return result;
    }

    /**
     * Bouncer function to the main one with some default arguments.
     */
    public double[] generateNoiseOctaves(double[] result, int x, int z, int xArraySize, int zArraySize, double xScale, double zScale, double p_76305_10_)
    {
        return this.generateNoiseOctaves(result, x, 10, z, xArraySize, 1, zArraySize, xScale, 1.0D, zScale);
    }
}

NoiseGeneratorSimplex

用來生成一個Simplex噪聲

public class NoiseGeneratorSimplex
{
    // 梯度向量
    private static int[][] field_151611_e = new int[][] {{1, 1, 0}, { -1, 1, 0}, {1, -1, 0}, { -1, -1, 0}, {1, 0, 1}, { -1, 0, 1}, {1, 0, -1}, { -1, 0, -1}, {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}};
    // √3
    public static final double field_151614_a = Math.sqrt(3.0D);
    // 0~255的隨機排列
    private int[] field_151608_f;
    // 座標偏移量
    public double field_151612_b;
    public double field_151613_c;
    public double field_151610_d;
    // (√3 - 1) / 2,把二維空間下的單形網格變形成新網格公式中的K1
    private static final double field_151609_g = 0.5D * (field_151614_a - 1.0D);
    // (3 - √3) / 6,把新網格變回原來空間公式中的K2
    private static final double field_151615_h = (3.0D - field_151614_a) / 6.0D;

    public NoiseGeneratorSimplex()
    {
        this(new Random());
    }

    // 同NoiseGeneratorImproved,略
    public NoiseGeneratorSimplex(Random p_i45471_1_)
    {
        this.field_151608_f = new int[512];
        this.field_151612_b = p_i45471_1_.nextDouble() * 256.0D;
        this.field_151613_c = p_i45471_1_.nextDouble() * 256.0D;
        this.field_151610_d = p_i45471_1_.nextDouble() * 256.0D;

        for (int i = 0; i < 256; this.field_151608_f[i] = i++)
        {
            ;
        }

        for (int l = 0; l < 256; ++l)
        {
            int j = p_i45471_1_.nextInt(256 - l) + l;
            int k = this.field_151608_f[l];
            this.field_151608_f[l] = this.field_151608_f[j];
            this.field_151608_f[j] = k;
            this.field_151608_f[l + 256] = this.field_151608_f[l];
        }
    }

    // 返回不大於num的最大整數
    private static int func_151607_a(double num)
    {
        return num > 0.0D ? (int)num : (int)num - 1;
    }

    // 返回與二維向量點乘的結果,參數:兩個向量
    private static double func_151604_a(int[] vector, double xWeight, double zWeight)
    {
        return   (double)vector[0] * xWeight
               + (double)vector[1] * zWeight;
    }

    // 計算一個點的噪聲值
    public double func_151605_a(double x, double z)
    {
        // (√3 - 1) / 2,把二維空間下的單形網格變形成新網格公式中的K1
        double K1 = 0.5D * (field_151614_a - 1.0D);
        // 把二維空間下的三角形網格變形成新網格
        double offset = (x + z) * K1;
        // func_151607_a爲向下取整,newXZ爲該點在新網格的超立方體座標
        int newX = func_151607_a(x + offset);
        int newZ = func_151607_a(z + offset);

        // (3 - √3) / 6,把新網格變回原來空間公式中的K2
        double K2 = (3.0D - field_151614_a) / 6.0D;
        // 把新網格座標變回三角形網格的座標
        double offset2 = (double)(newX + newZ) * K2;
        // 點所在三角形左下角的座標
        double oldTriangleX = (double)newX - offset2;
        double oldTriangleZ = (double)newZ - offset2;

        // 點相對於所在三角形的座標
        double dx1 = x - oldTriangleX;
        double dx2 = z - oldTriangleZ;

        // 根據點在哪個三角形內,需要計算第二個頂點索引
        int vec2XIndexOffset;
        int vec2ZIndexOffset;

        if (dx1 > dx2)
        {
            // 在右下角的三角形內
            vec2XIndexOffset = 1;
            vec2ZIndexOffset = 0;
        }
        else
        {
            // 在左上角的三角形內
            vec2XIndexOffset = 0;
            vec2ZIndexOffset = 1;
        }

        int xIndex = newX % 256;
        int zIndex = newZ % 256;
        // 三個頂點對應的梯度向量索引
        int vecIndex1 = this.field_151608_f[xIndex                    + this.field_151608_f[zIndex]] % 12;
        int vecIndex2 = this.field_151608_f[xIndex + vec2XIndexOffset + this.field_151608_f[zIndex + vec2ZIndexOffset]] % 12;
        int vecIndex3 = this.field_151608_f[xIndex + 1                + this.field_151608_f[zIndex + 1]] % 12;

        // r^2 - dist^2
        double tmp1 = 0.5D - dx1 * dx1 - dx2 * dx2;
        double res1;

        if (tmp1 < 0.0D)
        {
            // 到該頂點距離太遠,貢獻爲0
            res1 = 0.0D;
        }
        else
        {
            tmp1 = tmp1 * tmp1;
            // 該頂點對結果的貢獻度:(r^2 − dist^2)^4 * dot(dist, grad)
            res1 = tmp1 * tmp1 * func_151604_a(field_151611_e[vecIndex1], dx1, dx2);
        }

        double dx2 = dx1 - (double)vec2XIndexOffset + K2;
        double dz2 = dx2 - (double)vec2ZIndexOffset + K2;
        double tmp2 = 0.5D - dx2 * dx2 - dz2 * dz2;
        double res2;

        if (tmp2 < 0.0D)
        {
            res2 = 0.0D;
        }
        else
        {
            tmp2 = tmp2 * tmp2;
            res2 = tmp2 * tmp2 * func_151604_a(field_151611_e[vecIndex2], dx2, dz2);
        }

        double dx3 = dx1 - 1.0D + 2.0D * K2;
        double dz3 = dx2 - 1.0D + 2.0D * K2;
        double tmp3 = 0.5D - dx3 * dx3 - dz3 * dz3;
        double res3;

        if (tmp3 < 0.0D)
        {
            res3 = 0.0D;
        }
        else
        {
            tmp3 = tmp3 * tmp3;
            res3 = tmp3 * tmp3 * func_151604_a(field_151611_e[vecIndex3], dx3, dz3);
        }

        return 70.0D * (res1 + res2 + res3);
    }

    // 生成噪聲,這個noiseScale和振幅成正比
    public void func_151606_a(double[] result, double xOffset, double zOffset, int xSize, int zSize, double xScale, double zScale, double noiseScale)
    {
        int resultIndex = 0;

        for (int _z = 0; _z < zSize; ++_z)
        {
            double z = (zOffset + (double)_z) * zScale + this.field_151613_c;

            for (int _x = 0; _x < xSize; ++_x)
            {
                double x = (xOffset + (double)_x) * xScale + this.field_151612_b;

                // 把二維空間下的三角形網格變形成新網格
                double offset = (x + z) * field_151609_g;
                // func_151607_a爲向下取整,newXZ爲該點在新網格的超立方體座標
                int newX = func_151607_a(x + offset);
                int newZ = func_151607_a(z + offset);

                // 把新網格座標變回三角形網格的座標
                double offset2 = (double)(newX + newZ) * field_151615_h;
                // 點所在三角形左下角的座標
                double oldTriangleX = (double)newX - offset2;
                double oldTriangleY = (double)newZ - offset2;

                // 點相對於所在三角形的座標
                double dx1 = x - oldTriangleX;
                double dz1 = z - oldTriangleY;

                // 根據點在哪個三角形內,需要計算第二個頂點索引
                int vec2XIndexOffset;
                int vec2ZIndexOffset;

                if (dx1 > dz1)
                {
                    // 在右下角的三角形內
                    vec2XIndexOffset = 1;
                    vec2ZIndexOffset = 0;
                }
                else
                {
                    // 在左上角的三角形內
                    vec2XIndexOffset = 0;
                    vec2ZIndexOffset = 1;
                }

                int xIndex = newX % 256;
                int zIndex = newZ % 256;
                // 三個頂點對應的梯度向量索引
                int vecIndex1 = this.field_151608_f[xIndex                    + this.field_151608_f[zIndex]] % 12;
                int vecIndex2 = this.field_151608_f[xIndex + vec2XIndexOffset + this.field_151608_f[zIndex + vec2ZIndexOffset]] % 12;
                int vecIndex3 = this.field_151608_f[xIndex + 1                + this.field_151608_f[zIndex + 1]] % 12;

                // r^2 - dist^2
                double tmp1 = 0.5D - dx1 * dx1 - dz1 * dz1;
                double res1;

                if (tmp1 < 0.0D)
                {
                    // 到該頂點距離太遠,貢獻爲0
                    res1 = 0.0D;
                }
                else
                {
                    tmp1 = tmp1 * tmp1;
                    // 該頂點對結果的貢獻度:(r^2 − dist^2)^4 * dot(dist, grad)
                    res1 = tmp1 * tmp1 * func_151604_a(field_151611_e[vecIndex1], dx1, dz1);
                }

                double dx2 = dx1 - (double)vec2XIndexOffset + field_151615_h;
                double dz2 = dz1 - (double)vec2ZIndexOffset + field_151615_h;
                double tmp2 = 0.5D - dx2 * dx2 - dz2 * dz2;
                double res2;

                if (tmp2 < 0.0D)
                {
                    res2 = 0.0D;
                }
                else
                {
                    tmp2 = tmp2 * tmp2;
                    res2 = tmp2 * tmp2 * func_151604_a(field_151611_e[vecIndex2], dx2, dz2);
                }

                double dx3 = dx1 - 1.0D + 2.0D * field_151615_h;
                double dz3 = dz1 - 1.0D + 2.0D * field_151615_h;
                double tmp3 = 0.5D - dx3 * dx3 - dz3 * dz3;
                double res3;

                if (tmp3 < 0.0D)
                {
                    res3 = 0.0D;
                }
                else
                {
                    tmp3 = tmp3 * tmp3;
                    res3 = tmp3 * tmp3 * func_151604_a(field_151611_e[vecIndex3], dx3, dz3);
                }

                result[resultIndex++] += 70.0D * (res1 + res2 + res3) * noiseScale;
            }
        }
    }
}

NoiseGeneratorPerlin

和NoiseGeneratorOctaves類似,是NoiseGeneratorSimplex的分形疊加

public class NoiseGeneratorPerlin extends NoiseGenerator
{
    private NoiseGeneratorSimplex[] field_151603_a;
    private int field_151602_b;

    // 同NoiseGeneratorOctaves,略
    public NoiseGeneratorPerlin(Random p_i45470_1_, int p_i45470_2_)
    {
        this.field_151602_b = p_i45470_2_;
        this.field_151603_a = new NoiseGeneratorSimplex[p_i45470_2_];

        for (int i = 0; i < p_i45470_2_; ++i)
        {
            this.field_151603_a[i] = new NoiseGeneratorSimplex(p_i45470_1_);
        }
    }

    public double func_151601_a(double p_151601_1_, double p_151601_3_)
    {
        double d0 = 0.0D;
        double d1 = 1.0D;

        for (int i = 0; i < this.field_151602_b; ++i)
        {
            d0 += this.field_151603_a[i].func_151605_a(p_151601_1_ * d1, p_151601_3_ * d1) / d1;
            d1 /= 2.0D;
        }

        return d0;
    }

    // 生成噪聲,默認振幅係數0.5
    public double[] func_151599_a(double[] p_151599_1_, double p_151599_2_, double p_151599_4_, int p_151599_6_, int p_151599_7_, double p_151599_8_, double p_151599_10_, double p_151599_12_)
    {
        return this.func_151600_a(p_151599_1_, p_151599_2_, p_151599_4_, p_151599_6_, p_151599_7_, p_151599_8_, p_151599_10_, p_151599_12_, 0.5D);
    }

    // 生成噪聲,_freqScale爲每次迭代頻率係數(一般取1,不變)
    // _noiseScale爲每次迭代振幅係數,也會影響頻率(一般取0.5,振幅加倍,頻率減半)
    public double[] func_151600_a(double[] result, double x, double z, int xSize, int zSize, double xScale, double zScale, double _freqScale, double _noiseScale)
    {
        if (result != null && result.length >= xSize * zSize)
        {
            // 結果清0,因爲後面會疊加
            for (int i = 0; i < result.length; ++i)
            {
                result[i] = 0.0D;
            }
        }
        else
        {
            result = new double[xSize * zSize];
        }

        // 和振幅成反比
        double noiseScale = 1.0D;
        // 和頻率成正比
        double freqScale = 1.0D;

        for (int i = 0; i < this.field_151602_b; ++i)
        {
            this.field_151603_a[i].func_151606_a(result, x, z, xSize, zSize, xScale * freqScale * noiseScale, zScale * freqScale * noiseScale, 0.55D / noiseScale);
            freqScale *= _freqScale;
            noiseScale *= _noiseScale;
        }

        return result;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章