2D-шум перлина кажется квадратным

Кажется, я получаю квадратный шум перлина на 2D-вводе.

Я следил за этим https://www.shadertoy.com/view/4tGSzW, который использует WebGL вместо opengl. Где я заменил градиентный метод взятия из некоторого образца текстуры массивом с плавающей запятой в диапазоне от 0,0 до 1,0.

#version 330 core
out vec4 FragColor;


uniform float gradient[256];

float fade(float t)
{
    return t*t*t*(t*(t*6.0-15.0)+10.0);
}


vec2 grad(vec2 p){
    vec2 v = vec2(gradient[int(p.x)&255],gradient[int(p.y)&255]);
    return normalize(v.xy*2.0 - vec2(1.0));
}

float noise(vec2 p){
    vec2 p0 = floor(p);
    vec2 p1 = p0 + vec2(1.0,0.0);
    vec2 p2 = p0 + vec2(0.0,1.0);
    vec2 p3 = p0 + vec2(1.0,1.0);

    vec2 g0 = grad(p0);
    vec2 g1 = grad(p1);
    vec2 g2 = grad(p2);
    vec2 g3 = grad(p3);

    float t0 = p.x - p0.x;
    float fade_t0 = fade(t0);
    float t1 = p.y - p0.y;
    float fade_t1 = fade(t1);

    float p0p1 = (1.0-fade_t0)*dot(g0,(p-p0)) + fade_t0*dot(g1,(p-p1));
    float p2p3 = (1.0-fade_t0)*dot(g2,(p-p2)) + fade_t0*dot(g3,(p-p3));

    return ((1.0-fade_t1)*p0p1 + fade_t1*p2p3);
}


void main()
{
    float n = noise(vec2(gl_FragCoord.x,gl_FragCoord.y)/64.0)*1.0 +
              noise(vec2(gl_FragCoord.x,gl_FragCoord.y)/32.0) * 0.5 +
              noise(vec2(gl_FragCoord.x,gl_FragCoord.y)/16.0) * 0.25 +
              noise(vec2(gl_FragCoord.x,gl_FragCoord.y)/8.0) * 0.125;


    FragColor = vec4(vec3(n*0.5+0.5),1.0);

}

Квадратный шум перлина Генерируется изображение


person ashish    schedule 25.10.2019    source источник
comment
Можешь выложить фото как выглядит твой шум?   -  person Kalle Halvarsson    schedule 25.10.2019
comment
@ Калле Хальварссон готово   -  person ashish    schedule 28.10.2019


Ответы (1)


Исходная текстура в версии shapertoy является двухмерной и состоит из 256*256 случайных пикселей и нескольких цветовых каналов. Кроме того, когда текстура просматривается в исходной функции grad, пиксели интерполируются в соответствии с фильтром минимизации текстуры, который, вероятно, равен GL_LINEAR.

vec2 grad(vec2 p) {
  const float texture_width = 256.0;
  vec4 v = texture(iChannel0, vec2(p.x / texture_width, p.y / texture_width));
   return normalize(v.xy*2.0 - vec2(1.0));
}

Ваш юниформ-массив имеет всего 256 различных значений, а интерполяция между текселями не эмулируется в вашей функции grad:

vec2 grad(vec2 p){
   vec2 v = vec2(gradient[int(p.x)&255],gradient[int(p.y)&255]);
   return normalize(v.xy*2.0 - vec2(1.0));
}

Используйте функции случайного шума и интерпретируйте возвращаемое значение функции шума как угол ( шум*2*PI) для вычисления возвращаемого значения grad():

float rand(vec2 co){
    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
}

vec2 grad(vec2 p){
    float a = rand(p) * 2.0 * 3.1415926;
    return vec2(cos(a), sin(a)); 
}

Или используйте единый массив для генерации случайного значения

vec2 grad(vec2 p){

    ivec2 i00 = ivec2(int(p.x)&255, int(p.y)&255); 
    vec2  f   = floor(p); 

    float vx = mix(gradient[i00.x], gradient[i00.x+1], f.x);
    float vy = mix(gradient[i00.y], gradient[i00.y+1], f.y);

    float a = (vx + vy) * 3.141529;
    return vec2(cos(a), sin(a)); 
}

person Rabbid76    schedule 25.10.2019
comment
спасибо за решение, я получаю желаемые результаты. Но здесь я думаю, что это не интерполяция, которая вызывает квадратный шум, поскольку я всегда передаю пол (vec2) для градации в качестве входных данных. Являются ли генерируемые мной значения недостаточно случайными или что-то еще? - person ashish; 28.10.2019
comment
@ashish Как я уже упоминал в первом предложении ответа , исходная текстура в версии шейдертоя является двухмерной и состоит из 256 * 256 случайных пикселей и нескольких цветовых каналов. [...] Ваш юниформ-массив имеет всего 256 различных значений - person Rabbid76; 28.10.2019
comment
так что теоретически, если есть единый массив из 256 * 256 случайных значений пикселей (для каждого из двух компонентов vec2), он должен работать со старым подходом? - person ashish; 28.10.2019
comment
@ashish Конечно. Но обратите внимание, что 256 * 256 поплавков превышает предел стандартного размера блока (по умолчанию). Правильным решением для этого является использование текстуры (или функции случайного шума). - person Rabbid76; 28.10.2019
comment
хорошо, теперь я понял. Выбор значений для компонентов x и y из 256 чисел с плавающей запятой делал так называемые случайные значения не случайными, поскольку либо x повторялся по горизонтали, либо y повторялся по вертикали, отсюда и квадратный вид. Спасибо. - person ashish; 28.10.2019