<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>     
body {margin:0px; padding:0px; overflow: hidden}
let program, parallel = true;

function setup() {
  pixelDensity(1);
  const canvas = createCanvas(windowWidth, windowHeight,WEBGL);
  rectMode(CENTER);
  noStroke();
  fill(1);
  program = createShader(vert,frag);
}

function draw() {
  const lightPos = [-12, 12, -12];
  
  shader(program);
  background(0);
  program.setUniform('res',[width,height]);
  program.setUniform('lightPos', lightPos);
  program.setUniform('time', frameCount / 30);
  program.setUniform('parallel', parallel);
  rect(0,0,width,height);
}

function mousePressed() {
  parallel = !parallel
}


const vert=`
#ifdef GL_ES
precision highp float;
precision highp int;
#endif

#extension GL_OES_standard_derivatives : enable
attribute vec3 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;
void main() {
  gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
}`;


const frag=`
#ifdef GL_ES
precision highp float;
#endif

#define PI 3.14159265358979323846

uniform vec2 res;
uniform vec3 lightPos;
uniform float time;
uniform bool parallel;

float random (vec2 st) {
    return fract(sin(dot(st.xy,
                         vec2(12.9898,78.233)))*
        43758.5453123);
}

vec3 rotate(vec3 p, float angle, vec3 axis) {
  float s = sin(angle);
  float c = cos(angle);
  float oc = 1.0 - c;
  vec3 n = normalize(axis);
  return p * c + cross(n, p) * s + n * dot(n, p) * oc;
}

float sdBox( vec3 p, vec3 b )
{
  vec3 q = abs(p) - b;
  return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}

float SDF(vec3 p) {
  p = rotate(p, PI * 0.25, vec3(1.0, 0.0, 0.0));
  p = rotate(p, -PI * 0.125 * time, vec3(0.0, 1.0, 0.0));
  vec3 s = vec3(0.5);
  float d = 100.0;
  for (float i = -2.0; i <= 2.0; i ++) {
    for (float j = -2.0; j <= 2.0; j ++) {
      float h = random(vec2(i, j)) * 0.25+ 0.125;
      
      vec3 center = p - vec3(i * 0.25, h, j * 0.25);
      d = min(d, sdBox(center, vec3(0.1, h, 0.1)));
    }
  }
  return d;
}

vec3 getNormal(vec3 P) {  
  vec3 N;
  vec2 h = vec2(0.001, 0.0);
  N.x = SDF(P + h.xyy) - SDF(P - h.xyy);
  N.y = SDF(P + h.yxy) - SDF(P - h.yxy);
  N.z = SDF(P + h.yyx) - SDF(P - h.yyx);
  return normalize(N);
}

float raymarch(vec3 origin, vec3 rayDir) {
    float dist = 0.0;
    float threshold = 0.001;
    for(int i = 0 ; i < 48 ; ++i) {
        float d = SDF(origin + rayDir * dist);
        if(d < threshold) { return dist; }
        dist += d;
    }
    return -1.0;
}

float diffuse(vec3 l, vec3 n) {
  return max(0.0, dot(l, n));
}

void main(void)
{
  vec2 crd = (gl_FragCoord.xy - res * 0.5) / res.x * 2.5;
  
  vec3 origin, rayDir;
  if (parallel) {
    origin = vec3(crd, -2.0);
  } else {
    origin = vec3(0.0, 0.0, -2.0);
  }
  rayDir = normalize(vec3(crd, 0.0) - origin);

  //vec3 rayDir = normalize(vec3(crd, 0.0) - origin);
  float dist = raymarch(origin, rayDir);
  
  vec4 color = vec4(vec3(0.01), 1.0);
  if (dist >= 0.0) {
      vec3 P = origin + rayDir * dist;
      vec3 L = normalize(lightPos - P);
      vec3 N = getNormal(P);
      vec3 baseColor = vec3(1.0);
      vec3 Cd = diffuse(L, N) * baseColor;

      float shadowDist = raymarch(P + 0.001 * N, L);  // Start slightly above the surface to prevent self-shadowing
float shadow = shadowDist >= 0.0 ? 0.25 : 1.0;
      Cd *= shadow;
      Cd += vec3(0.1); // ambient light
      color = vec4(Cd, 1.0);
  }
  color.rgb = pow(color.rgb, vec3(1.0 / 2.2));
  gl_FragColor = color;
}`;

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.