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) {
  p = p + 0.02;
  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;

  // part 4.5 - update noise function with time
  gradient = sin(gradient + u_time);
  return gradient;

  // gradient = sin(gradient);
  // return gradient;
}

// inigo quilez - https://iquilezles.org/articles/distfunctions2d/
float sdfCircle(in vec2 p, in float r) {
  return length(p) - r;
}

// inigo quilez - https://iquilezles.org/articles/distfunctions2d/
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 cubic(vec2 p) {
  return p * p * (3.0 - p * 2.0);
}

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

void main() {
  // part 0 - basic shader setup
  vec2 uv = gl_FragCoord.xy / u_resolution;

  // uncomment for final final demo
  uv = gl_FragCoord.xy / u_resolution.y;

  vec3 black = vec3(0.0);
  vec3 white = vec3(1.0);
  vec3 color = black;

  // part 1 - set up a grid of cells
  uv = uv * 4.0;
  vec2 gridId = floor(uv);
  vec2 gridUv = fract(uv);
  color = vec3(gridId, 0.0);
  color = vec3(gridUv, 0.0);

  // part 2.1 - start by finding the coords of grid corners
  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);

  // part 2.2 - find random gradient for each grid corner
  vec2 gradBl = randomGradient(bl);
  vec2 gradBr = randomGradient(br);
  vec2 gradTl = randomGradient(tl);
  vec2 gradTr = randomGradient(tr);

  // part 2.3 - visualize gradients (for demo purposes)
  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);
  }

  // part 3.1 - visualize a single center pixel on each grid cell
  float circleRadius = 0.025;
  vec2 circleCenter = vec2(0.5, 0.5);
  float distToCircle = sdfCircle(gridUv - circleCenter, circleRadius);
  color = distToCircle > 0.0 ? color : white;

  // part 3.2 - find distance from current pixel to each grid corner
  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);

  // part 4.1 - calculate the dot products of gradients + distances
  float dotBl = dot(gradBl, distFromPixelToBl);
  float dotBr = dot(gradBr, distFromPixelToBr);
  float dotTl = dot(gradTl, distFromPixelToTl);
  float dotTr = dot(gradTr, distFromPixelToTr);

  // part 4.4 - smooth out gridUvs
  // gridUv = smoothstep(0.0, 1.0, gridUv);
  // gridUv = cubic(gridUv);
  gridUv = quintic(gridUv);

  // part 4.2 - perform 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);

  // part 4.3 - display perlin noise
  color = vec3(perlin + 0.2);
  // color = distToCircle > 0.0 ? color : white;
  // if (distG1 < 0.0 || distG2 < 0.0 || distG3 < 0.0 || distG4 < 0.0) {
  //   color = vec3(1.0);
  // }

  // part 4.5 - update randomGradient function with time

  // part 5.1 - billow noise
  // float billow = abs(perlin);
  // color = vec3(billow);

  // part 5.2 - ridged noise
  // float ridgedNoise = 1.0 - abs(perlin);
  // ridgedNoise = ridgedNoise * ridgedNoise;
  // color = vec3(ridgedNoise);

  gl_FragColor = vec4(color, 1.0);
}