2

I seem to be getting boxy perlin noise terrain on 2d input.

I have been following this https://www.shadertoy.com/view/4tGSzW, which uses WebGL instead of opengl. Where i have replaced the gradient method of taking from some sample texture by a float array of range 0.0 to 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);

}

Boxy perlin noise Image being generated

ashish
  • 23
  • 5

1 Answers1

2

The source texture in the shadertoy version is 2 dimensional and consists of 256*256 random pixels and multiple color channels. Further when the texture is looked up in the original grad function then the pixels are interpolated according to the texture minification filter, which is probably 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));
}

Your uniform array has just 256 different values and the interpolation between the texels is not emulated in your grad function:

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));
}

Use a Random noise functions and interpret the return value of the noise function as an angle (noise*2*PI) to calculate the return value of 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)); 
}

Or use the uniform array to generate a random value

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)); 
}

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • thanks for the solution, I am getting the desired results. But here i think it's not interpolation whats causing the boxy noise as i am always passing a floor(vec2) to grad as input. Are the values being generated by me not random enough or something else? – ashish Oct 28 '19 at 07:34
  • @ashish As I mentioned in the first sentence of the answer *"The source texture in the shadertoy version is 2 dimensional and consists of 256*256 random pixels ans multiple color channels. [...] Your uniform array has just 256 different values"* – Rabbid76 Oct 28 '19 at 07:45
  • so theoretically if have a uniform array of 256*256 random pixel values(for each of the two components of vec2), it should work with the old approach? – ashish Oct 28 '19 at 08:40
  • @ashish Of course. But note 256*256 floats exceeds the limit of the (default) uniform block size. The proper solution for this is to use a texture (or a random noise function). – Rabbid76 Oct 28 '19 at 08:56
  • 1
    okay, now i get it. Me picking values for x and y component from 256 floats was making the so called random values not random as either x was repeating horizontally or y was repeating vertically hence the boxy appearance. Thanks. – ashish Oct 28 '19 at 09:13