- 18, Oct 2024
- #1
Я работал над написанием функций для 5- и 6-мерного симплексного шума, работая над 4D-функция FastNoise в качестве базы. 2D, 3D и 4D шум следуют очень похожему и узнаваемому шаблону, который можно легко расширить до более высоких измерений, однако результат выглядит не так уж хорошо:
Видимые диагональные области (линии), где значения очень похожи, а также ромбы, где значения не сливаются друг с другом. (Считается ли это прерывистым?)
Полная функция 5D Noise:
0.8
t
consists of:
FN_DECIMAL(0.5)
И 8
consists of:
FN_DECIMAL(0.6)
Массив FN_DECIMAL(0.5)
is an array 400 items long, each 5 values representing a diagonal vector.
The array GRAD_5D
представляет собой массив перестановок длиной 512 элементов, значения от 0 до 255, в случайном порядке, вторая половина массива такая же, как и первая половина. m_perm
is also a 512 item long array, but the values of m_perm80
Массив m_perm
)
были увеличены по модулю 80. (Поскольку в GRAD_5D
s should actually be unsigned char FastNoise::Index5D_80(unsigned char offset, int x, int y, int z, int w, int v) const
{
return m_perm80[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + m_perm[(w & 0xff) + m_perm[(v & 0xff) + offset]]]]];
}
В настоящее время я не уверен, что
как это видно в функциях симплексного шума 3D и 4D и SimplexNoise.java Стефана Густавсона, который написал «Разоблачение симплексного шума», в котором он говорит, что значение следует изменить на 0,5 (и все же не делает этого в своем собственном исходном коде?). Кен Перлин использует 0,6 в своей статье о симплексном шуме, но это просто магическое число, значение или происхождение которого он не объясняет. Index5D_80
used to "normalise" the sum of the n components when returning the final value is correct, though it's doing a reasonable job of keeping the values within a usable range.
Я также не уверен, что я озадачился этот математический вопрос по обмену стеком 67.6953который подразумевает, что значение нормализации на самом деле должно быть
. Это значение действительно приближает шум к 4D-шуму в его вариациях значений, но приводит к тому, что некоторые значения выходят за пределы -1 и 1. Это также делает диагональные области более заметными, а ромбовидные артефакты - более четкими.
Однако коэффициент нормализации, похоже, не является проблемой, поскольку он просто переносит значения в диапазон от -1 до 1. inline FN_DECIMAL FastNoise::GradCoord5D(unsigned char offset, int x, int y, int z, int w, int v, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd, FN_DECIMAL wd, FN_DECIMAL vd) const
{
unsigned char lutPos = Index5D_80(offset, x, y, z, w, v) * 5;
return xd * GRAD_5D[lutPos] + yd * GRAD_5D[lutPos + 1] + zd * GRAD_5D[lutPos + 2] + wd * GRAD_5D[lutPos + 3] + vd * GRAD_5D[lutPos + 4];
}
value is officially called (I think it might be the spherical kernel radius, I can't find any hard proof), reducing it brings the values closer to 0 (effectively making the image flatter, because it makes it more likely that GradCoord5
Каким бы ни был будет меньше 0 и, следовательно, вклад этой вершины не будет использоваться). Кен Перлин упоминает«Точный радиус и амплитуда ядра в форме гиперсферы с центром в каждом симплексе должны быть настроены так, чтобы обеспечить наилучшие визуальные результаты для каждого выбора n» static const FN_DECIMAL F5 = (sqrt(FN_DECIMAL(6)) - 1) / 5;
static const FN_DECIMAL G5 = (6 - sqrt(FN_DECIMAL(6))) / 30;
FN_DECIMAL FastNoise::SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w, FN_DECIMAL v) const
{
FN_DECIMAL n0, n1, n2, n3, n4, n5;
FN_DECIMAL t = (x + y + z + w + v) * F5;
int i = FastFloor(x + t);
int j = FastFloor(y + t);
int k = FastFloor(z + t);
int l = FastFloor(w + t);
int h = FastFloor(v + t);
t = (i + j + k + l + h) * G5;
FN_DECIMAL X0 = i - t;
FN_DECIMAL Y0 = j - t;
FN_DECIMAL Z0 = k - t;
FN_DECIMAL W0 = l - t;
FN_DECIMAL V0 = h - t;
FN_DECIMAL x0 = x - X0;
FN_DECIMAL y0 = y - Y0;
FN_DECIMAL z0 = z - Z0;
FN_DECIMAL w0 = w - W0;
FN_DECIMAL v0 = v - V0;
int rankx = 0;
int ranky = 0;
int rankz = 0;
int rankw = 0;
int rankv = 0;
if (x0 > y0) rankx++; else ranky++;
if (x0 > z0) rankx++; else rankz++;
if (x0 > w0) rankx++; else rankw++;
if (x0 > v0) rankx++; else rankv++;
if (y0 > z0) ranky++; else rankz++;
if (y0 > w0) ranky++; else rankw++;
if (y0 > v0) ranky++; else rankv++;
if (z0 > w0) rankz++; else rankw++;
if (z0 > v0) rankz++; else rankv++;
if (w0 > v0) rankw++; else rankv++;
int i1 = rankx >= 4 ? 1 : 0;
int j1 = ranky >= 4 ? 1 : 0;
int k1 = rankz >= 4 ? 1 : 0;
int l1 = rankw >= 4 ? 1 : 0;
int h1 = rankv >= 4 ? 1 : 0;
int i2 = rankx >= 3 ? 1 : 0;
int j2 = ranky >= 3 ? 1 : 0;
int k2 = rankz >= 3 ? 1 : 0;
int l2 = rankw >= 3 ? 1 : 0;
int h2 = rankv >= 3 ? 1 : 0;
int i3 = rankx >= 2 ? 1 : 0;
int j3 = ranky >= 2 ? 1 : 0;
int k3 = rankz >= 2 ? 1 : 0;
int l3 = rankw >= 2 ? 1 : 0;
int h3 = rankv >= 2 ? 1 : 0;
int i4 = rankx >= 1 ? 1 : 0;
int j4 = ranky >= 1 ? 1 : 0;
int k4 = rankz >= 1 ? 1 : 0;
int l4 = rankw >= 1 ? 1 : 0;
int h4 = rankv >= 1 ? 1 : 0;
FN_DECIMAL x1 = x0 - i1 + G5;
FN_DECIMAL y1 = y0 - j1 + G5;
FN_DECIMAL z1 = z0 - k1 + G5;
FN_DECIMAL w1 = w0 - l1 + G5;
FN_DECIMAL v1 = v0 - h1 + G5;
FN_DECIMAL x2 = x0 - i2 + 2*G5;
FN_DECIMAL y2 = y0 - j2 + 2*G5;
FN_DECIMAL z2 = z0 - k2 + 2*G5;
FN_DECIMAL w2 = w0 - l2 + 2*G5;
FN_DECIMAL v2 = v0 - h2 + 2*G5;
FN_DECIMAL x3 = x0 - i3 + 3*G5;
FN_DECIMAL y3 = y0 - j3 + 3*G5;
FN_DECIMAL z3 = z0 - k3 + 3*G5;
FN_DECIMAL w3 = w0 - l3 + 3*G5;
FN_DECIMAL v3 = v0 - h3 + 3*G5;
FN_DECIMAL x4 = x0 - i4 + 4*G5;
FN_DECIMAL y4 = y0 - j4 + 4*G5;
FN_DECIMAL z4 = z0 - k4 + 4*G5;
FN_DECIMAL w4 = w0 - l4 + 4*G5;
FN_DECIMAL v4 = v0 - h4 + 4*G5;
FN_DECIMAL x5 = x0 - 1 + 5*G5;
FN_DECIMAL y5 = y0 - 1 + 5*G5;
FN_DECIMAL z5 = z0 - 1 + 5*G5;
FN_DECIMAL w5 = w0 - 1 + 5*G5;
FN_DECIMAL v5 = v0 - 1 + 5*G5;
t = FN_DECIMAL(0.5) - x0*x0 - y0*y0 - z0*z0 - w0*w0 - v0*v0;
if (t < 0) n0 = 0;
else
{
t *= t;
n0 = t*t * GradCoord5D(offset, i, j, k, l, h, x0, y0, z0, w0, v0);
}
t = FN_DECIMAL(0.5) - x1*x1 - y1*y1 - z1*z1 - w1*w1 - v1*v1;
if (t < 0) n1 = 0;
else
{
t *= t;
n1 = t*t * GradCoord5D(offset, i + i1, j + j1, k + k1, l + l1, h + h1, x1, y1, z1, w1, v1);
}
t = FN_DECIMAL(0.5) - x2*x2 - y2*y2 - z2*z2 - w2*w2 - v2*v2;
if (t < 0) n2 = 0;
else
{
t *= t;
n2 = t*t * GradCoord5D(offset, i + i2, j + j2, k + k2, l + l2, h + h2, x2, y2, z2, w2, v2);
}
t = FN_DECIMAL(0.5) - x3*x3 - y3*y3 - z3*z3 - w3*w3 - v3*v3;
if (t < 0) n3 = 0;
else
{
t *= t;
n3 = t*t * GradCoord5D(offset, i + i3, j + j3, k + k3, l + l3, h + h3, x3, y3, z3, w3, v3);
}
t = FN_DECIMAL(0.5) - x4*x4 - y4*y4 - z4*z4 - w4*w4 - v4*v4;
if (t < 0) n4 = 0;
else
{
t *= t;
n4 = t*t * GradCoord5D(offset, i + i4, j + j4, k + k4, l + l4, h + h4, x4, y4, z4, w4, v4);
}
t = FN_DECIMAL(0.5) - x5*x5 - y5*y5 - z5*z5 - w4*w4 - v5*v5;
if (t < 0) n5 = 0;
else
{
t *= t;
n5 = t * t * GradCoord5D(offset, i + 1, j + 1, k + 1, l + 1, h + 1, x5, y5, z5, w5, v5);
}
return 8 * (n0 + n1 + n2 + n3 + n4 + n5); // TODO: Find value scaler
}
(and bringing the normalisation value down to 6) does produce a more appealing image however it doesn't get rid of the odd diamond shapes and the diagonals can still sort of be seen as the slightly fuzzier areas under the diamond artifacts.
, и действительно увеличивает значение до
Что может быть причиной этих артефактов? Возможно, это проблема с индексацией? Что-то еще?