感觉要被吸进去啦

Published on
/
/趣玩前端
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>感觉要被吸进去啦!</title>
    <style>
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <script type="module">
      import * as THREE from 'https://cdn.skypack.dev/three@0.139.2';
      import orbitControlsEs6 from 'https://cdn.skypack.dev/orbit-controls-es6@2.0.1';

      const canvasContainer = document.getElementById('container');

      const scene = new THREE.Scene();

      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      camera.position.set(0, -200, 0);

      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x080808);
      document.body.appendChild(renderer.domElement);

      new orbitControlsEs6(camera, renderer.domElement);

      window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      });

      const textureLoader = new THREE.TextureLoader();
      textureLoader.load(
        'https://images.unsplash.com/photo-1631519952398-5b1d76b946e8?q=80&w=3087&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
        function (texture) {
          const vertexShader = `
      varying vec2 vUv;
      uniform float u_time;
      varying float vElevation;
      varying vec3 vNormal;

      float oscillate(float time, float minVal, float maxVal) {
          float sineWave = sin(time);
          float normalizedSine = (sineWave + 1.0) / 2.0;
          return mix(minVal, maxVal, normalizedSine);
      }
        
      void main() {
          vUv = uv;
          vNormal = normalize(normalMatrix * normal);
          vec3 newPosition = vec3(position.x, position.y * oscillate(u_time/4.0, 4.0,15.0), position.z);
          gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
      }
    `;

          const fragmentShader = `
      varying vec2 vUv;
      uniform sampler2D u_texture;
      uniform float u_time;
      varying vec3 vNormal;

vec3 palette(float t, float u_time) {
    vec3 a = vec3(0.5 + 0.5 * sin(u_time * 6.28318), 0.5, 0.9);
    vec3 b = vec3(0.9, 0.5 + 0.5 * cos(u_time * 6.28318), 0.5);
    vec3 c = vec3(1.0, 1.0, 1.0);
    vec3 d = vec3(0.25, 0.4, 0.55 + 0.45 * sin(u_time * 6.28318));

    return a + b * cos(6.28318 * (c * t + d));
}
            float oscillate(float time, float minVal, float maxVal) {
          float sineWave = sin(time);
          float normalizedSine = (sineWave + 1.0) / 2.0;
          return mix(minVal, maxVal, normalizedSine);
      }
      
      void main() {
          vec2 animatedUv = (vUv.y + vUv.x) + vec2(u_time * -0.02, vUv.y); 
          vec4 color = texture2D(u_texture, mod(animatedUv, 1.0));
          float blackThreshold = 0.5;
          float intensity = max(color.r, max(color.g, color.b));

          if (intensity < blackThreshold) {
              discard;
          }
          gl_FragColor = color * vec4(palette(vUv.y, oscillate(u_time/5.0, 0.0, 1.0)), 1.0);
      }
    `;

          const radius = 50;
          const segments = 512;
          const rings = 512;
          const geometry = new THREE.SphereGeometry(radius, segments, rings);
          geometry.uvsNeedUpdate = true;

          const customMaterial = new THREE.ShaderMaterial({
            vertexShader: vertexShader,
            fragmentShader: fragmentShader,
            wireframe: false,
            side: THREE.DoubleSide,
            uniforms: {
              u_time: { value: 0.0 },
              u_texture: { value: texture },
            },
          });

          const sphere = new THREE.Mesh(geometry, customMaterial);
          scene.add(sphere);

          const bgVertex = `
      varying vec2 vUv;
      uniform float u_time;
      varying float vElevation;
      varying vec3 vNormal;

      float oscillate(float time, float minVal, float maxVal) {
          float sineWave = sin(time);
          float normalizedSine = (sineWave + 1.0) / 2.0;
          return mix(minVal, maxVal, normalizedSine);
      }
      
      void main() {
          vUv = uv;
          vNormal = normalize(normalMatrix * normal);
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `;
          const bgFragment = `
      varying vec2 vUv;
      uniform float u_time;
      varying vec3 vNormal;
      
      void main() {
          gl_FragColor = vec4(1.0); 
      }
    `;

          const backgroundShader = new THREE.ShaderMaterial({
            vertexShader: bgVertex,
            fragmentShader: bgFragment,
            side: THREE.DoubleSide,
            uniforms: {
              u_time: { value: 0.0 },
            },
          });

          const background = new THREE.SphereGeometry(800, 1024, 1024);
          const backgroundMesh = new THREE.Mesh(background, backgroundShader);
          backgroundMesh.position.z = -1;
          scene.add(backgroundMesh);

          const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
          scene.add(ambientLight);

          const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
          directionalLight.position.set(10, 10, 10);
          scene.add(directionalLight);

          function animate() {
            requestAnimationFrame(animate);

            customMaterial.uniforms.u_time.value = performance.now() / 1000;
            backgroundShader.uniforms.u_time.value = performance.now() / 1000;

            renderer.render(scene, camera);
          }
          animate();
        }
      );
    </script>
  </body>
</html>