Back to shaders

Shader test bench

Shader

suboptimal-shader-tutorials generative glsl runnable fragment MIT
Source
runnable fragment

Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.

Code

precision mediump float;

uniform float u_time;
uniform vec2 u_resolution;

vec2 randomGradient(vec2 p) {
  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);
  gradient = sin(gradient + u_time);
  return gradient;
}

vec2 quintic(vec2 p) {
  return p * p * p * (10.0 + p * (-15.0 + p * 6.0));
}

float perlinNoise(vec2 uv) {
  vec2 gridId = floor(uv);
  vec2 gridUv = fract(uv);

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

  vec2 g1 = randomGradient(bl);
  vec2 g2 = randomGradient(br);
  vec2 g3 = randomGradient(tl);
  vec2 g4 = randomGradient(tr);

  vec2 distFromBl = gridUv - vec2(0.0, 0.0);
  vec2 distFromBr = gridUv - vec2(1.0, 0.0);
  vec2 distFromTl = gridUv - vec2(0.0, 1.0);
  vec2 distFromTr = gridUv - vec2(1.0, 1.0);

  float d1 = dot(g1, distFromBl);
  float d2 = dot(g2, distFromBr);
  float d3 = dot(g3, distFromTl);
  float d4 = dot(g4, distFromTr);

  gridUv = quintic(gridUv);

  float bot = mix(d1, d2, gridUv.x);
  float top = mix(d3, d4, gridUv.x);
  float pNoise = mix(bot, top, gridUv.y);

  return pNoise + 0.1;
}

float fbmPerlinNoise(vec2 uv) {
  float fbmNoise = 0.0;
  float amplitude = 1.0;
  // const float octaves = 1.0;
  const float octaves = 2.0;
  // const float octaves = 3.0;
  // const float octaves = 4.0;
  // const float octaves = 5.0;

  for (float i = 0.0; i < octaves; i++) {
    fbmNoise = fbmNoise + perlinNoise(uv) * amplitude;
    amplitude = amplitude * 0.5;
    uv = uv * 2.0;
  }

  // fbmNoise = fbmNoise / 2.0;

  return fbmNoise;
}

float domainWarpFbmPerlinNoise(vec2 uv) {
  // return fbmPerlinNoise(uv);

  float fbm1 = fbmPerlinNoise(uv + vec2(0.0, 0.0));
  float fbm2 = fbmPerlinNoise(uv + vec2(5.2, 1.3));
  return fbmPerlinNoise(vec2(fbm1, fbm2));

  float fbm3 = fbmPerlinNoise(uv + 4.0 * fbm1 + vec2(1.7, 9.2));
  float fbm4 = fbmPerlinNoise(uv + 4.0 * fbm2 + vec2(8.3, 2.8));
  return fbmPerlinNoise(vec2(fbm3, fbm4));
}

vec3 calcNormal(vec2 uv) {
  float diff = 0.001;
  float p1 = domainWarpFbmPerlinNoise(uv + vec2(diff, 0.0));
  float p2 = domainWarpFbmPerlinNoise(uv - vec2(diff, 0.0));
  float p3 = domainWarpFbmPerlinNoise(uv + vec2(0.0, diff));
  float p4 = domainWarpFbmPerlinNoise(uv - vec2(0.0, diff));

  vec3 normal = normalize(vec3(p1 - p2, p3 - p4, 0.001));
  return normal;
}

void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  uv = gl_FragCoord.xy / u_resolution.y;

  vec3 color = vec3(0.0);

  uv = uv * 4.0;
  float pNoise = perlinNoise(uv);
  color = vec3(pNoise);

  // part 1 - fractional brownian motion
  float fbmNoise = fbmPerlinNoise(uv);
  // color = vec3(fbmNoise);

  // part 2 - domain warping
  float dwNoise = domainWarpFbmPerlinNoise(uv);
  color = vec3(dwNoise);

  // part 3.1 - central differences method
  vec3 normal = calcNormal(uv);

  // part 3.2 - diffuse lighting
  vec3 white = vec3(1.0);
  vec3 blue = vec3(0.65, 0.85, 1.0);
  vec3 lightColor = white;
  lightColor = blue;
  vec3 lightSource = vec3(1.0, 1.0, 1.0);
  float diffuseStrength = max(0.0, dot(normal, lightSource));
  vec3 diffuse = diffuseStrength * lightColor;
  vec3 lighting = diffuse * 0.5;
  color = lighting;

  // part 3.3 - specular lighting
  vec3 cameraSource = vec3(0.0, 0.0, 1.0);
  vec3 viewSource = normalize(cameraSource);
  vec3 reflectSource = normalize(reflect(-lightSource, normal));
  float specularStrength = max(0.0, dot(viewSource, reflectSource));
  specularStrength = pow(specularStrength, 32.0);
  vec3 specular = specularStrength * lightColor;

  lighting = diffuse * 0.5 + specular * 0.5;
  color = lighting;

  gl_FragColor = vec4(color, 1.0);
}