Я полностью овладел искусством Perlin Noise в 3D, а теперь пытаюсь использовать ту же реализацию для 2D-алгоритма. Проблема, похоже, заключается в выборе направлений градиентов. В 3D я использую 16 градиентов в равномерно распределенных направлениях, и это отлично работает. В 2D я решил использовать 8 градиентов: вверх, вниз, влево, вправо и четыре диагональных направления.
Вот что я получил:
Общий вид шума всегда правильный, но края квадратов не совсем совпадают. Я также пробовал использовать другие градиенты или меньшее количество градиентов, но получил похожие результаты. Здесь в другом примере видно, что края иногда совпадают, и результаты в этой области в порядке -
Когда я не использую градиенты и вместо этого просто интерполирую между значениями, выбранными случайным образом в каждом из 4 углов, я получаю правильные результаты, что заставляет меня думать, что именно градиентная часть все портит.
Вот мой код:
//8 different gradient directions
private Point[] grads = new Point[] {
new Point(0, 1), new Point(1, 1), new Point(1, 0), new Point(1, -1),
new Point(0, -1), new Point(-1, -1), new Point(-1, 0), new Point(-1, 1),};
//takes the dot product of a gradient and (x, y)
private float dot2D(int i, float x, float y)
{
return
grads[i].X * x + grads[i].Y * y;
}
public float Noise2D(float x, float y)
{
int
ix = (int)(x),
iy = (int)(y);
x = x - ix;
y = y - iy;
float
fx = fade(x),
fy = fade(y);
ix &= 255;
iy &= 255;
// here is where i get the index to look up in the list of
// different gradients.
// hashTable is my array of 0-255 in random order
int
g00 = hashTable[ix + hashTable[iy ]],
g10 = hashTable[ix + 1 + hashTable[iy ]],
g01 = hashTable[ix + hashTable[iy + 1]],
g11 = hashTable[ix + 1 + hashTable[iy + 1]];
// this takes the dot product to find the values to interpolate between
float
n00 = dot2D(g00 & 7, x, y),
n10 = dot2D(g10 & 7, x, y),
n01 = dot2D(g01 & 7, x, y),
n11 = dot2D(g11 & 7, x, y);
// lerp() is just normal linear interpolation
float
y1 = lerp(fx, n00, n10),
y2 = lerp(fx, n01, n11);
return
lerp(fy, y1, y2);
}