Чому мій Perlin Noise виглядає «блокадно»?


21

Я спробував реалізувати Перлін Шум самостійно, використовуючи лише теорію (слідуючи flafla2.github.io/2014/08/09/perlinnoise.html). На жаль, мені не вдалося досягти вигляду "оригінального" шуму Перліна.

У чому причина, що наведений нижче код надає комерційну версію Perlin Noise?

Що слід покращити / змінити в коді, щоб він видавав шум Перліна без артефактів?

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

GLSL Sandbox: 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], щоб отримати градієнти в усіх напрямках. Цю частину легко виправити шляхом перестановки.

Щоб виправити ці проблеми, я переключив код, щоб використовувати цю хеш-функцію (про яку я дізнався від Mikkel Gjoel, і , ймовірно, завдяки документу 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 * радіан у градусах)? Це через періодичність триггерних функцій? Я не можу це google.
сарасвати

3
@sarasvati Я не дуже впевнений, але гадаю, що 57 і 113 обрані, тому що вони є першими. (113 є простим; 57 - це не, але це 3 * 19, тому все одно своєрідний прем'єр ... якщо це річ.) Помноження або модифікація на перше число іменене, як правило, збільшується в бітах, тому це не рідкість інгредієнт в хешах.
Натан Рід

1
@cat Я сумніваюся, що GLSL має PRNG, враховуючи, що програми GLSL є детермінованими.
користувач253751

1
Схоже, у цій темі коментарів є декілька потенційних нових питань ...
trichoplax

1
У мене були ці артефакти, і ця функція rand () виправила це. Проблема полягає в тому, що коли я пройшов 2 км на своїй місцевості, артефакти, як ОП, почали з’являтися знову. Тут було використано хеш-функцію: amindforeverprogramming.blogspot.com/2013/07/…, що призвело до того, що артефакти відійдуть (за винятком відстані 100 км, точність точності , але це нормально, я просто мусив розколотись на шматки, і отримав це працювати, хешуючи обидві значення, що дозволить шуму перліна працювати майже нескінченно довго). Отже, я залишу це тут, щоб, можливо, допомогти тому, хто має те саме питання.
Микола Піпітон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.