分享一个模拟广告大屏led效果的webgl shader

26

demo

  const material = new THREE.ShaderMaterial({
    vertexShader: `
          varying vec2 vUv;
          varying float vDist;
          varying float vRandom;
          uniform vec2 mouse;
          uniform float radius;
          uniform float time;
          uniform float drag;

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

          void main() {
              vUv = uv;
              vec3 pos = position;
              
              // 基于位置和时间生成随机值
              float rand = random(pos.xy) * 1.01 - 0.01;
              vRandom = rand;
              
              // 计算打散效果
              float disperseFactor = sin(time * 0.5) * 0.00001;
              vec3 disperseDir = vec3(
                  rand * disperseFactor,
                  rand * disperseFactor,
                  0
              );
              
              // 鼠标交互
              vec2 mouseDir = pos.xy - mouse;
              float dist = length(mouseDir);

              if (dist < radius) {
                  float force = (radius - dist) / radius;
                  pos.xy += normalize(mouseDir) * force * 0.5;
              }

              // 应用打散效果
              pos += disperseDir;
              
              // 减小粒子大小
              gl_PointSize = 3.0 * (1.0 + random(pos.xy));

              vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
              gl_Position = projectionMatrix * mvPosition;
              
              vDist = dist;
          }`,
    fragmentShader: `
          uniform sampler2D mainTexture;
          varying vec2 vUv;
          varying float vDist;
          varying float vRandom;
          uniform float time;

          // 颜色调整辅助函数
          vec3 adjustColor(vec3 color) {
              // 增加对比度
              vec3 contrast = (color - 0.5) * 1.4 + 0.5;
              
              // 计算亮度
              float luminance = dot(contrast, vec3(0.299, 0.587, 0.114));
              
              // 增加饱和度
              vec3 saturated = mix(vec3(luminance), contrast, 1.3);
              
              // 稍微压暗高光
              saturated = pow(saturated, vec3(1.1));
              
              return saturated;
          }

          void main() {
              // 马赛克大小
              float mosaicSize = 1000.0;
              vec2 mosaicUv = floor(vUv * mosaicSize) / mosaicSize;
              
              // 减小抖动效果
              float jitter = sin(time * 2.0 + vRandom * 1.28) * 0.001;
              mosaicUv += vec2(jitter);

              vec4 texColor = texture2D(mainTexture, mosaicUv);
              
              // 调整颜色
              vec3 adjustedColor = adjustColor(texColor.rgb);
              
              // 调整扭曲和淡出效果
              float distortionFactor = 1.0 - vDist * 0.005;
              float alpha = 0.99 + 0.01 * sin(time * 2.0 + vRandom * 6.28);
              
              // 边缘淡出效果
              float edgeFade = 1.0 - length(gl_PointCoord - vec2(0.5)) * 2.0;
              edgeFade = smoothstep(0.0, 0.5, edgeFade);

              gl_FragColor = vec4(adjustedColor, texColor.a * alpha * edgeFade);
          }`,
    uniforms: {
      mainTexture: { value: texture.value },
      mouse: { value: new THREE.Vector2(0, 0) },
      radius: { value: 0.5 },
      time: { value: 0 },
      drag: { value: 0.98 },
    },
    transparent: true,
    side: THREE.DoubleSide,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  });