Perlin Noise Visualization
Based on a tutorial
For the original video or blog post, please visit:
What is Perlin Noise? | YouTube.
You can also find more cool stuff on the author's blog:
SuboptimalEngineer @ GitHub
This experiment demonstrates Perlin noise using a custom WebGL shader.
precision highp float;
uniform float uTime;
uniform vec2 uResolution;
vec2 randomGradient(vec2 p) {
p = p + 0.01;
float x = dot(p, vec2(123.4, 234.5));
float y = dot(p, vec2(234.5, 345.6));
vec2 gradient = vec2(x, y);
gradient = sin(gradient);
gradient = gradient * 43758.5453;
gradient = sin(gradient + uTime);
return gradient;
}
float sdfOrientedBox(in vec2 p, in vec2 a, in vec2 b, float th) {
float l = length(b - a);
vec2 d = (b - a) / l;
vec2 q = (p - (a + b) * 0.5);
q = mat2(d.x, -d.y, d.y, d.x) * q;
q = abs(q) - vec2(l, th) * 0.5;
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0);
}
vec2 quintic(vec2 p) {
return p * p * p * (10.0 + p * (-15.0 + p * 6.0));
}
float sdfCircle(vec2 p, float r) {
return length(p) - r;
}
void main() {
// Normalized pixel coordinates (from 0 to 1)
vec2 fragCoord = gl_FragCoord.xy;
vec2 uv = fragCoord / uResolution.xy;
vec3 black = vec3(0.);
vec3 white = vec3(1.);
vec3 color = black;
uv = uv * 4.;
vec2 gridId = floor(uv);
vec2 gridUv = fract(uv);
color = vec3(gridUv, 0.);
vec2 bl = gridId + vec2(0.0, 0.0);
vec2 br = gridId + vec2(1.0, 0.0);
vec2 tl = gridId + vec2(0.0, 1.0);
vec2 tr = gridId + vec2(1.0, 1.0);
// Random gradient from each edge point
vec2 gradBl = randomGradient(bl);
vec2 gradBr = randomGradient(br);
vec2 gradTl = randomGradient(tl);
vec2 gradTr = randomGradient(tr);
vec2 gridCell = gridId + gridUv;
float distG1 = sdfOrientedBox(gridCell, bl, bl + gradBl / 2.0, 0.02);
float distG2 = sdfOrientedBox(gridCell, br, br + gradBr / 2.0, 0.02);
float distG3 = sdfOrientedBox(gridCell, tl, tl + gradTl / 2.0, 0.02);
float distG4 = sdfOrientedBox(gridCell, tr, tr + gradTr / 2.0, 0.02);
if (distG1 < 0.0 || distG2 < 0.0 || distG3 < 0.0 || distG4 < 0.0) {
color = vec3(1.0);
}
// For visualization
float circleRadius = 0.025;
vec2 circleCenter = vec2(0.5, 0.5);
float distToCircle = sdfCircle(gridUv - circleCenter, circleRadius);
color = distToCircle > 0.0 ? color : white;
vec2 distFromPixelToBl = gridUv - vec2(0.0, 0.0);
vec2 distFromPixelToBr = gridUv - vec2(1.0, 0.0);
vec2 distFromPixelToTl = gridUv - vec2(0.0, 1.0);
vec2 distFromPixelToTr = gridUv - vec2(1.0, 1.0);
float dotBl = dot(gradBl, distFromPixelToBl);
float dotBr = dot(gradBr, distFromPixelToBr);
float dotTl = dot(gradTl, distFromPixelToTl);
float dotTr = dot(gradTr, distFromPixelToTr);
gridUv = quintic(gridUv);
// Linear interpolation between 4 dot products
float b = mix(dotBl, dotBr, gridUv.x);
float t = mix(dotTl, dotTr, gridUv.x);
float perlin = mix(b, t, gridUv.y);
color = vec3(perlin + 0.1);
color = distToCircle > 0.0 ? color : white;
// Output to screen
gl_FragColor = vec4(color, 1.0);
}