Почему мой шум Perlin выглядит «блочным»?

21

Я попытался реализовать Perlin Noise самостоятельно, используя только теорию (следуя flafla2.github.io/2014/08/09/perlinnoise.html). К сожалению, мне не удалось добиться эффекта «оригинального» Perlin Noise.

По какой причине приведенный ниже код отображает блочную версию Perlin Noise?

Что я должен улучшить / изменить в коде, чтобы он отображал Perlin Noise без артефактов?

Я подозреваю, что может быть проблема или в способе, которым я интерполирую или в gradsвекторе. gradsВектор содержит точечные продукты (случайный вектор для решетки точки) и (вектор размера) - для всех 4 поблизости от точек решетки. (Случайные и размерные векторы описаны в самой первой ссылке.)

Песочница GLSL: http://glslsandbox.com/e#32663.0

Артефакты в шуме

float fade(float t) { return t * t * t * (t * (t * 6. - 15.) + 10.); }
vec2 smooth(vec2 x) { return vec2(fade(x.x), fade(x.y)); }

vec2 hash(vec2 co) {
    return fract (vec2(.5654654, -.65465) * dot (vec2(.654, 57.4), co));
}

float perlinNoise(vec2 uv) {
    vec2 PT  = floor(uv);
    vec2 pt  = fract(uv);
    vec2 mmpt= smooth(pt);

    vec4 grads = vec4(
        dot(hash(PT + vec2(.0, 1.)), pt-vec2(.0, 1.)),   dot(hash(PT + vec2(1., 1.)), pt-vec2(1., 1.)),
        dot(hash(PT + vec2(.0, .0)), pt-vec2(.0, .0)),   dot(hash(PT + vec2(1., .0)), pt-vec2(1., 0.))
    );

    return 5.*mix (mix (grads.z, grads.w, mmpt.x), mix (grads.x, grads.y, mmpt.x), mmpt.y);
}

float fbm(vec2 uv) {
    float finalNoise = 0.;
    finalNoise += .50000*perlinNoise(2.*uv);
    finalNoise += .25000*perlinNoise(4.*uv);
    finalNoise += .12500*perlinNoise(8.*uv);
    finalNoise += .06250*perlinNoise(16.*uv);
    finalNoise += .03125*perlinNoise(32.*uv);

    return finalNoise;
}

void main() {
    vec2 position = gl_FragCoord.xy / resolution.y;
    gl_FragColor = vec4( vec3( fbm(3.*position) ), 1.0 );
}
Сарасвати
источник

Ответы:

24

Интерполяция выглядит хорошо. Основная проблема здесь в том, что используемая хеш-функция не очень хороша. Если я смотрю только одну октаву и визуализирую результат хеширования, выводя hash(PT).x, я получаю что-то вроде этого:

плохая хеш-функция

Предполагается, что он должен быть абсолютно случайным для каждого квадрата сетки, но вы можете видеть, что в нем много шаблонов диагональных линий (это почти похоже на шахматную доску), так что это не очень случайный хэш, и эти шаблоны будут отображаться в шум, производимый им.

Другая проблема состоит в том, что ваш хэш возвращает только градиентные векторы в [0, 1], тогда как они должны быть в [-1, 1], чтобы получить градиенты во всех направлениях. Эту часть легко исправить, переназначив.

Чтобы исправить эти проблемы, я переключил код на использование этой хеш-функции (которую я узнал от Миккеля Гьоеля и , вероятно, из-за статьи WJJ Rey ):

vec2 hash(vec2 co) {
    float m = dot(co, vec2(12.9898, 78.233));
    return fract(vec2(sin(m),cos(m))* 43758.5453) * 2. - 1.;
}

Обратите внимание, что из-за функций триггера это будет немного дороже, чем ваша версия. Однако это значительно улучшает внешний вид получаемого шума:

FBM шум с лучшей хэш-функцией

Натан Рид
источник
Спасибо очень много для вашего объяснения. Это может быть не по теме, но я все равно спрошу; в некоторых исходных кодах, которые вычисляют шум, люди используют вектор vec3 (1, 57, 113) для вычисления точечного произведения с текущей координатой (я полагаю, целью является также получение хеша). Почему именно этот выбор констант (57 составляет около 1 радиан в градусах, 133 = около 2 * радиан в градусах)? Это из-за периодичности в тригонометрических функциях? Я не могу гуглить это.
Сарасвати
3
@sarasvati Я не совсем уверен, но предположение, что 57 и 113 выбраны потому, что они числа простых чисел. (113 - простое число; 57 - нет, но это 3 * 19, так что все еще немного примитивно ... если это так.) Умножение или изменение на число простого числа имеет тенденцию перемешивать биты, так что это не редкость ингредиент в хеше.
Натан Рид
1
@cat Я сомневаюсь, что GLSL имеет PRNG, учитывая, что программы GLSL являются детерминированными.
user253751
1
Похоже, в этой ветке комментариев есть несколько потенциальных новых вопросов ...
trichoplax
1
У меня были эти артефакты, и эта функция rand () исправила это. Проблема в том, что после того, как я прошел 2 км по своей местности, артефакты, такие как ОП, снова начали появляться. Здесь использовалась хеш-функция: amindforeverprogramming.blogspot.com/2013/07/… , из-за которой артефакты исчезли (за исключением расстояний в 100 км, bc неточности, но это нормально, мне просто пришлось разделить на куски и получить это работать, хэшируя оба значения, что позволит шуму perlin работать почти бесконечно). Итак, я оставлю это здесь, чтобы, возможно, помочь любому, кто имеет такую ​​же проблему.
Николас Пипитоне