Reputation: 557
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
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
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