哈哈哈这是什么玩意儿

Published on
/
/趣玩前端
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Fog of Worm</title>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas"></canvas>
    <script>
      const canvas = document.getElementById('myCanvas');
      const gl = canvas.getContext('webgl2');

      const vertexShaderSource = `#version 300 es

in vec2 a_position;

void main() {
    gl_Position = vec4(a_position, 0.0, 1.0);
}
`;

      const fragmentShaderSource = `#version 300 es

precision highp float;

uniform vec2 iResolution; // Declare as vec2 (canvas width and height)
uniform vec2 iMouse;
uniform float iTime;

out vec4 fragColor;

// Shadertoy code here

#define PI 3.14159265359
#define RES iResolution
#define PT iMouse
#define smin smoothmin
#define smax smoothmax

float sdSeg(in vec3 p, in vec3 a, in vec3 b) {
  vec3 pa = p - a, ba = b - a;
  float h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);
  return length(pa - ba * h);
}

float sdSphere(in vec3 p, in vec3 center, float radius) {
  return length(p - center) - radius;
}

float whiteNoise2x1(vec2 p) {
  float random = dot(p, vec2(12.235, 78.37283));
  random = sin(random);
  random *= 4358.4346;
  random = fract(random);
  return random;
}

float valueNoise(vec2 uv) {
  uv *= 4.0;
  vec2 gridUV = fract(uv);
  vec2 gridId = floor(uv);

  gridUV = smoothstep(0.0, 1.0, gridUV);

  float bL = whiteNoise2x1(gridId);
  float bR = whiteNoise2x1(gridId + vec2(1.0, 0.0));
  float b = mix(bL, bR, gridUV.x);

  float tL = whiteNoise2x1(gridId + vec2(0.0, 1.0));
  float tR = whiteNoise2x1(gridId + vec2(1.0));
  float t = mix(tL, tR, gridUV.x);
  float noise = mix(b, t, gridUV.y);

  return noise;
}

float sdPlane(vec3 p, vec3 n, float h) {
  float noiseValue = valueNoise(p.xz*10.);
  float heightAdjustment = 0.05 * noiseValue;
  return dot(p, n) + h + heightAdjustment;
}

float smoothmin(float d1, float d2, float k) {
  float h = max(k - abs(d1 - d2), 0.) / k;
  return min(d1, d2) - h * h * k * (1. / 4.);
}

float smoothmax(float d1, float d2, float k) {
    float h = max(k - abs(d1 - d2), 0.) / k;
    return max(d1, d2) + h * h * k * (1. / 4.);
}

int partID = 1;

float map(vec3 p) {
  
  vec3 g = p;
  float mx = .33, mz = 1.05;
  p.x = mod(p.x - mx,2.*mx) - mx;
  p.z = mod((p.z + iTime/4.) - mz,2.*mz) - mz;

  float m = .05*p.y*(-1. + cos(iTime*5.));

  p.x/=1.5;
  vec3 n = vec3(0,.25,0.);
  float off = n.z;
  n.z+=m;
  float nose = sdSphere(p,n,.125);

  p.x*=1.5;

  float tR = .125;
  vec3 ta = vec3(0,.5,.2+m),
       tb = ta;
       tb.y = - ta.y;
       tb.z = off + .2;
  float torso = sdSeg(p, ta, tb) - tR;

  vec3 tc = vec3(0,-.5,.35),
       td = tb;
  td.z = 0.95 - m*4.;

  float tail = sdSeg(p, tc, td) - tR;

  vec3 h = abs(p), z = abs(p);
  h.y = (mod(h.y - .05,.1));
  float cutY = h.y;
  z.z = (mod(z.z - .05+.005*cos(-iTime*5.),.1+.01*cos(-iTime*5.)));
  float cutZ = z.z;

  float body = smin(smin(
                smax(torso,-cutY,.03),
                smax(tail,-cutZ,.03),.1),
                nose,.025);

  vec3 eA = vec3(.075,.4,.1+m),
       eB = eA;
  eB.x = -eA.x;

  float eye1 = sdSphere(p,eA,.1),
        eye2 = sdSphere(p,eB,.09),
        eyes = min(eye1,eye2);

  vec3 pA = vec3(.075,.4,.045+m),
       pB = pA;
  pB.x = -pA.x;

  float p1 = sdSphere(p,pA,.048),
        p2 = sdSphere(p,pB,.041),
        pupils = min(p1,p2);

  
  p.z-=iTime*.5;
  float ground = sdPlane(g, vec3(0.,1.,0.), .6);

  float result = min(min(body, min(eyes,pupils)),ground);

  if (result == body) {
    partID = 1;
  } else if (result == eyes) {
    partID = 2;
  } else if (result == pupils) {
    partID = 3;
  }
  else {
    partID = 4;
  }

  return result;
}

vec3 norm(vec3 p) {
  float h = 1e-3;
  vec2 k = vec2(-1, 1);
  return normalize(
    k.xyy * map(p + k.xyy * h) +
    k.yxy * map(p + k.yxy * h) +
    k.yyx * map(p + k.yyx * h) +
    k.xxx * map(p + k.xxx * h)
  );
}

float d0 = 25.;

float raymarch(inout vec3 p, vec3 rd) {
  float dd = 0.0;

  for (float i = 0.0; i < 100.0; i++) {
    float d = map(p);
  if (d < 1e-3 || dd > d0) break;
    p += rd * d;
    dd += d;
  }
  return dd;
}

float shadow(vec3 p, vec3 lp) {
    float shd=1., maxd=length(lp-p);
    vec3 l=normalize(lp-p);
    for (float i=1e-3; i<maxd;) {
        float d=map(p+l*i);
        if (d<1e-3) {
            shd=.0;
            break;
        }
        shd=min(shd,128.*d/i);
        i+=d;
    }
    return shd;
}

vec3 render(vec3 p, vec3 rd) {
  float d = raymarch(p, rd);
  vec3 col = vec3(0);

  if (d < d0) {
    vec3 n = norm(p),
         lp = vec3(-1, 2, -5),
         l = normalize(lp - p);
    float diffuse = clamp(dot(l, n), 0., 1.),
          reflective = clamp(dot(reflect(rd, n), l), .0, 1.0);
          col += .5*diffuse;
          
    if (partID <= 3) {
      col += pow(reflective, 32.);
    }

    if (partID == 1) {
      col = mix(col, vec3(1.,0.,0.), .33);
    } else if (partID == 2) {
      col = mix(col, vec3(1.), .5);
    } else if (partID == 3) {
      col = mix(col, vec3(-.5), .5);
    } else if (partID == 4) {
      col = mix(col, vec3(-1.25,-2.,-2.25), .25);
    }
    col += .1+.4*diffuse*shadow(p+n*5e-2, lp);
  } else {
    col += vec3(.25,.6*(abs(rd.z)),.6);
  }

  float fogFactor = clamp(d / d0, 0.0, 1.0);
  vec3 fogColor = vec3(0.25, 0.6 * abs(rd.z), 0.6);
  col = mix(col, fogColor, fogFactor);


  return col;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 uv = (fragCoord.xy - .5 * RES.xy) / RES.y;

  // View angles based on mouse input
  float angleX;
  float angleY;
  
  if (iMouse.x > 0.) {
      angleX = PI + cos(iTime/6.);
      angleY = (PT.y / RES.y * 2. - 1. - 1.)*PI*-.25;
  }
  else {
      angleX = PI*.825;
      angleY = PI*.0625;
  }

  float camR = 5.;
  vec3 target = vec3(0.0);

  vec3 ro = vec3(
    sin(angleX)*cos(angleY),
    sin(angleY),
    cos(angleX)*cos(angleY)
    )*camR;

  vec3 fwd = normalize(target - ro),
      right = normalize(cross(vec3(0., 1., 0.), fwd)),
      up = cross(fwd, right),
      rd = normalize(fwd + uv.x * right + uv.y * up);

  float t = 0.0;
  vec3 p = ro, col = render(ro, rd);
  fragColor = vec4(col, 1);
}

// Shadertoy code ends here

void main() {
    mainImage(fragColor, gl_FragCoord.xy);
}

`;

      const vertexShader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexShaderSource);
      gl.compileShader(vertexShader);

      const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentShaderSource);
      gl.compileShader(fragmentShader);

      const program = gl.createProgram();
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
      gl.linkProgram(program);
      gl.useProgram(program);

      const positions = [-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0];

      const positionBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
      gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(positions),
        gl.STATIC_DRAW
      );

      const positionAttributeLocation = gl.getAttribLocation(
        program,
        'a_position'
      );
      gl.enableVertexAttribArray(positionAttributeLocation);

      gl.vertexAttribPointer(
        positionAttributeLocation,
        2,
        gl.FLOAT,
        false,
        0,
        0
      );

      const iResolutionLocation = gl.getUniformLocation(program, 'iResolution');
      const iMouseLocation = gl.getUniformLocation(program, 'iMouse');
      const iTimeLocation = gl.getUniformLocation(program, 'iTime');

      function resizeCanvas() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
      }

      window.addEventListener('resize', resizeCanvas);

      resizeCanvas(); // Initial resize

      canvas.addEventListener('mousemove', (event) => {
        const rect = canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = canvas.height - (event.clientY - rect.top);
        gl.uniform2f(iMouseLocation, x, y);
      });

      function render() {
        gl.viewport(0, 0, canvas.width, canvas.height);
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.uniform2f(iResolutionLocation, canvas.width, canvas.height);
        gl.uniform1f(iTimeLocation, performance.now() * 0.001);

        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

        requestAnimationFrame(render);
      }

      render();
    </script>
  </body>
</html>