Perlin噪音产生可见的“块状”形态,Java

时间:2014-08-13 10:01:01

标签: java perlin-noise procedural-generation

我一直在尝试基于this文章在java中实现perlin噪声生成器。 Homever,我的发生器产生的噪声不是连续的,而是"blocky",在每个偶数编号的坐标之间形成可见的线。以下是我目前的代码:

private static final Point[] grads = {
    new Point(1, 0), new Point(-1, 0), new Point(0, 1), new Point(0, -1),
    new Point(1, 1), new Point(1, -1), new Point(-1, 1), new Point(-1, -1)
};

private int permutations[] = new int[512]; private int frequency; private int seed; private double[][] heightMap; private double amplitude; public PerlinNoise(int frequency, int seed, double[][] heightMap, double amplitude) { this.frequency = frequency; this.seed = seed; //Seed for randomizing the permutation table this.heightMap = heightMap; //The Heightmap where the finalt result will be stored this.amplitude = amplitude; } private void seedPermutationTables() { LinkedList<PermutationValue> l = new LinkedList<PermutationValue>(); Random rand = new Random(this.seed); for (int i = 0; i < 256; i++) { l.add(new PermutationValue(i, rand)); } Collections.sort(l); for (int i = 0; i < 512; i++) { permutations[i] = l.get(i & 255).getValue(); } } public void generateNoise() { this.seedPermutationTables(); int sWidth = this.heightMap.length / frequency; int sHeight = this.heightMap[0].length / frequency; for (int i = 0; i < this.heightMap.length; i++) { for (int j = 0; j < this.heightMap[i].length; j++) { double x = (double)i / sWidth; double y = (double)j / sHeight; this.heightMap[i][j] = this.noise(x, y); } } } private double noise(double x, double y) { int xi = (int)x & 255; int yi = (int)y & 255; double xf = x - (int)x; double yf = y - (int)y; double u = this.fade(xf); double v = this.fade(yf); int aa = permutations[permutations[xi] + yi]; int ab = permutations[permutations[xi] + yi + 1]; int ba = permutations[permutations[xi + 1] + yi]; int bb = permutations[permutations[xi + 1] + yi + 1]; double x1 = this.lerp(this.grad(aa, xf, yf), this.grad(ab, xf - 1, yf), u); double x2 = this.lerp(this.grad(ba, xf, yf - 1), this.grad(bb, xf - 1, yf - 1), u); double noise = this.lerp(x1, x2, v); return (1D + noise) / 2 * this.amplitude; //The noise returns values between -1 and 1 //So we change the range to 0-amplitude } private double grad(int hash, double x, double y) { hash = hash & 7; Point p = grads[hash]; return p.x * x + p.y * y; } private double lerp(double a, double b, double x) { return a + x * (b - a); } private double fade(double x) { return x * x * x * (x * (x * 6 - 15) + 10); } private class PermutationValue implements Comparable<PermutationValue> { private int value; private double sortValue; public PermutationValue(int value, Random rand) { this.setValue(value); this.sortValue = rand.nextDouble(); } @Override public int compareTo(PermutationValue pv) { if (pv.sortValue > this.sortValue) { return -1; } return 1; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }

heightmap数组只存储每个像素的高度值。可能导致这些形成的任何建议或想法?

1 个答案:

答案 0 :(得分:0)

哈希表可以用rndng fct中的1-2次乘法替换: blocky可能来自哈希表中缺少三次插值或数字噪声。 在你的情况下,听起来它并没有在哈希表的两个值之间进行搜索。 lerp只需要任意2个值并在它们之间平滑。所以,如果它没有正常运行,那就太块了。

function rndng ( n: float ): float //total noise pseudo
{//random proportion -1, 1
    var e = ( n *321.9)%1;
    return  (e*e*111.0)%2-1;
}


function lerps(o:float, v:float, alpha:float):float
{
    o += ( v - o ) * alpha;
    return o;
}

function lnz ( vtx: Vector3 ): float//3d noise
{   
    vtx= Vector3 ( Mathf.Abs(vtx.x) , Mathf.Abs(vtx.y) , Mathf.Abs(vtx.z) ) ;
    var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
    var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
    D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
    var W = I.x + I.y*71.0 + 125.0*I.z;

    return lerps(           
                lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.y)
                ,
                lerps( lerps(rndng(W+125.0),rndng(W+126.0),D.x) , lerps(rndng(W+153.0),rndng(W+154.0),D.x) , D.y)
                ,
                D.z
                );
}

function lnzo ( vtx: Vector3 ): float
{
    var total = 0.0;    
    for (var i:int = 1; i < 5; i ++)
    {
        total+= lnz2(Vector3 (vtx.x*(i*i),0.0,vtx.z*(i*i)))/(i*i);
    }

    return total*5;

}
function lnzh ( vtx: Vector3 ): float//3 axis 3d noise
{   
    vtx= Vector3 ( Mathf.Abs(vtx.z) , Mathf.Abs(vtx.z*.5-vtx.x*.866) , Mathf.Abs(vtx.z*.5+vtx.x*.866) ) ;
    var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
    var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
   //D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
    var W = I.x + I.y*71.0 + 125.0*I.z;

    return lerps(           
                lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.y)
                ,
                lerps( lerps(rndng(W+125.0),rndng(W+126.0),D.x) , lerps(rndng(W+153.0),rndng(W+154.0),D.x) , D.y)
                ,
                D.z
                );
}

function lnz2 ( vtx: Vector3 ): float//2d noise
{   
    vtx= Vector3 ( Mathf.Abs(vtx.x) , Mathf.Abs(vtx.y) , Mathf.Abs(vtx.z) ) ;
    var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
    var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
    D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
    var W = I.x + I.y*71.0 + 125.0*I.z;

    return lerps(       
                lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.z)
                ,
                lerps( rndng(W+125.0), rndng(W+126.0),D.x)
                ,
                D.z
                );                  
}