我一直在尝试基于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数组只存储每个像素的高度值。可能导致这些形成的任何建议或想法?
答案 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
);
}