<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.5/gsap.min.js"></script>
<div class="three" id="three">
</div>
.three{
  position: absolute;
  top: 0;
  left: 0;
}
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import { EffectComposer } from "https://cdn.skypack.dev/[email protected]/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "https://cdn.skypack.dev/[email protected]/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "https://cdn.skypack.dev/[email protected]/examples/jsm/postprocessing/ShaderPass.js";

//renderer
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("three").appendChild(renderer.domElement);

//scene
const scene = new THREE.Scene();
//camera
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
camera.position.y = 2.5;
camera.position.x = 0.5;

//resize listener
window.addEventListener("resize", function() {
    let width = window.innerWidth;
    let height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
  });

//postprocessing
let postEffect = {
  uniforms: {
    tDiffuse: { value: null },
    tImage: { value: new THREE.TextureLoader().load('https://assets.codepen.io/6547170/SST-Neuron-442x252.jpeg') },
    uTime: { value: 0 },
    resolution: {
      value: new THREE.Vector2( window.innerWidth,window.innerHeight),
    },
    uMouse: { value: new THREE.Vector2(-100, -100) },
  },
  vertexShader: `
  varying vec2 vUv;
  varying vec2 pos;
  void main() {
  vUv = uv;
  pos = position.xy;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
  }`,
  fragmentShader: `
    
    uniform sampler2D tDiffuse;
    uniform sampler2D tImage;
    uniform vec2 resolution;
    uniform vec2 uMouse;
    uniform float uTime;
    
    varying vec2 vUv;
    varying vec2 pos;

    #define AA 2.

    struct MetaBall{
      float r;
        vec2 pos;
        vec3 col;
    };

    vec4 BallSDF(MetaBall ball, vec2 uv){
        float dst = ball.r / length(uv - ball.pos);
        return vec4(ball.col * dst, dst);
    }

    vec3 renderMetaBall(vec2 uv){
    MetaBall  mb1, mb2, mb3, mb4, mouseMb;
        mb1.pos = vec2(-0.5,0.5);   mb1.r = 0.6; mb1.col = vec3(1., 0., 0.);

        mb2.pos = vec2(0.5,0.5);   mb2.r = 0.6; mb2.col = vec3(1., 0., 0.);

        mb3.pos = vec2(-0.5,-0.5);   mb3.r = 0.6; mb3.col = vec3(1., 0., 0.);

        mb4.pos = vec2(0.5,-0.5);   mb4.r = 0.6; mb4.col = vec3(1., 0., 0.);

        mouseMb.pos = vec2(vUv - uMouse); mouseMb.r = 0.1; mouseMb.col = vec3(1., 1., 1.);

        vec4 ball1 = BallSDF(mb1, uv);
        vec4 ball2 = BallSDF(mb2, uv);
        vec4 ball3 = BallSDF(mb3, uv);
        vec4 ball4 = BallSDF(mb4, uv);
        vec4 mouseBall = BallSDF(mouseMb, uv);


        float total = ball1.a + ball2.a + ball3.a + ball4.a + mouseBall.a;
        float threshold = total > 4.5 ? 1. : 0.;
        vec3 color = (ball1.rgb + ball2.rgb + ball3.rgb + ball4.rgb + mouseBall.rgb) / total;
        color *= threshold;
        return color;
    }

    void main()
    {
        vec3 col = renderMetaBall(pos);
        vec4 tex = texture2D(tImage,vUv);

        gl_FragColor = vec4(col,1.0) + tex;
    }
   `,
};
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
const customPass = new ShaderPass(postEffect);
customPass.renderToScreen = true;
composer.addPass(customPass);

let mouse = new THREE.Vector2(-100, -100);         

//animation loop
function animate() {
  requestAnimationFrame(animate);
  composer.render();
  if (customPass) {
  customPass.uniforms.uTime.value += 0.01;
  customPass.uniforms.uMouse.value = mouse;

  } 
}
animate();

document.addEventListener("mousemove", (e) => {
  mouse.x = 1 - e.clientX / window.innerWidth;
  mouse.y = e.clientY / window.innerHeight;
});

Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.