Scrashdown
Scrashdown

Reputation: 557

GLSL 2D Perlin noise looking weird

as part of a college assignment I have to implement Perlin noise in GLSL. I use this slide as my reference :

As well as this wikipedia article.

My course says I should get something like this :

Unfortunately I get this when I run my code :

By adding 0.5 to the noise value I get this :

What seems weird to me is that the interpolation doesn't seem to work very well from one cell to the other. As if the interpolation function didn't have C2 continuity. This is weird, since the function f I use for interpolation does have this property. Do you have any idea where this problem might come from ?

This is my fragment shader code :

#version 330

in vec2 uv;

out vec3 color;

uniform int width;
uniform int height;

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

vec2 rand(vec2 co) {
    float angle = 3.141592654 * 2 * simple_rand(co);
    return vec2(sin(angle), cos(angle));
}

// mix function as described in the slides
float lerp(float x, float y, float alpha) {
    return (1 - alpha) * x + alpha * y;
}

// interpolation function as described in the slides
float f(float t) {
    return t*t*t * (t * (6.0*t - 15.0) + 10.0);
}

vec3 noise(vec2 vec) {
    // number of pixels per cell
    int cell_px = 50;

    // get coordinates of current cell corners and calculate random gradients
    // GRID coordinates
    int cx = int(floor(vec.x * width / cell_px));
    int cy = int(floor(vec.y * height / cell_px));
    // ABSOLUTE coordinates
    vec2 x0y0 = vec2(cx*cell_px, cy*cell_px);
    vec2 x1y1 = vec2(x0y0.x + cell_px, x0y0.y + cell_px);
    vec2 x0y1 = vec2(x0y0.x, x1y1.y);
    vec2 x1y0 = vec2(x1y1.x, x0y0.y);

    // vec translated to inner cell coordinates, relative to x0y0, must be between 0 and 1
    vec2 cell_vec = vec2((vec.x * width - x0y0.x) / cell_px, (vec.y * height - x0y0.y) / cell_px);

    // compute difference vectors
    vec2 a = vec2(cell_vec);
    vec2 b = vec2(1.0 - cell_vec.x, cell_vec.y);
    vec2 c = vec2(cell_vec.x, 1.0 - cell_vec.y);
    vec2 d = vec2(1.0 - cell_vec.x, 1.0 - cell_vec.y);

    // dot products to get scalar values from the corners
    float s = dot(rand(x0y0), a);
    float t = dot(rand(x1y0), b);
    float u = dot(rand(x0y1), c);
    float v = dot(rand(x1y1), d);

    float st_ = lerp(s, t, f(cell_vec.x));
    float uv_ = lerp(u, v, f(cell_vec.x));
    float noise = lerp(st_, uv_, f(cell_vec.y));

    return vec3(noise);
}

void main() {
    color = noise(uv);
}

Upvotes: 1

Views: 1177

Answers (2)

Makogan
Makogan

Reputation: 9536

The error comes from flipping the direction of the vectors. You are supposed to calculate the vector from the corner to the point, you are however calculating the vector from the point to the corner.

This will fix it:

vec2 a = vec2(cell_vec);
vec2 b = vec2(cell_vec.x, -1.0+cell_vec.y);
vec2 c = vec2(-1.0+cell_vec.x, cell_vec.y);
vec2 d = vec2(-1.0 + cell_vec.x, -1.0 + cell_vec.y);

Upvotes: 0

frib
frib

Reputation: 11

vec2 cell_vec = vec2((vec.x * width - x0y0.x) / cell_px, (vec.y * height - x0y0.y) / cell_px);

Dividing by an int by an int can do weird things. You could try to convert cell_px to float first.

Upvotes: 1

Related Questions