Search code examples
javascriptthree.jsgsap

Onmouseover onmouseout image change Liquid effect


I need to realize image change with liquid effect like in here

I have a simple block with image I need to change this image (to other image) in onmouseover with this effect and return to initial position in onmouseout also using this effect

const avatarQuantumBreak = document.querySelector(".avatar_quantum_break");
const avatar = document.querySelector(".avatar");

avatarQuantumBreak.style.opacity = "0";

let hover = () => avatarQuantumBreak.style.opacity = "1";
let normal = () => avatarQuantumBreak.style.opacity = "0";

avatar.onmouseover = () => hover();
avatar.onmouseout = () => normal();
html , body {
  height:100%;
}

.avatar {
  position: relative;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  height: 195px;
}
.avatar_simple,
.avatar_quantum_break {
  position: absolute;
  display: block;
  text-align:center;
  transition: opacity 1s ease-out;
}
.avatar .avatar_simple img,
.avatar .avatar_quantum_break img {
  border-radius: 50%;
  display: inline-block;
  width: 86%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>


<div class=avatar>
    <span class=avatar_simple>
        <img src="https://pixel.nymag.com/imgs/fashion/daily/2014/05/27/27-amber-heard.w330.h330.jpg">
    </span>
    <span class=avatar_quantum_break>
        <img src="https://pixel.nymag.com/imgs/daily/vulture/2016/05/31/31-amber-heard.w330.h330.jpg">
    </span>
</div>

Image transition function which trigger's liquid animation is below

transitionNext() {
    TweenMax.to(this.mat.uniforms.dispPower, 2.5, {
      value: 1,
      ease: Expo.easeInOut,
      onUpdate: this.render,
      onComplete: () => {
        this.mat.uniforms.dispPower.value = 0.0
        this.changeTexture()
        this.render.bind(this)
        this.state.animating = false
      }
    })

I try to use this function but this didn't help me.

Also I try to change images in this Array line 15 but this also didn't helped.

this.images = [ //1
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg1.jpg',
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg2.jpg',
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg3.jpg'
    ]

This function start's the animation

listeners() {
   window.addEventListener('wheel', this.nextSlide, { passive: true })
}

Next slide function

nextSlide() {
   if (this.state.animating) return

   this.state.animating = true

   this.transitionNext()

   this.data.current = this.data.current === this.data.total ? 0 : this.data.current + 1
this.data.next = this.data.current === this.data.total ? 0 : this.data.current + 1
}

Please help..


Solution

  • Nice one - realtime vfx meets web development :)

    All magic of this effect is done with GLSL shader (you can see it at the bottom of example html) here I've added some comments to it

      // next lines are input data that gpu gets form javascript
      varying vec2 vUv; // uv coordinate of current pixel
      uniform sampler2D texture1; // picture 1
      uniform sampler2D texture2; // picture 2
      uniform sampler2D disp; // noise texture
      uniform float dispPower; // effect progress
      uniform float intensity; // effect scale
    
      void main() {
        vec2 uv = vUv;
    
        vec4 disp = texture2D(disp, uv); // read noise texture
        vec2 dispVec = vec2(disp.x, disp.y); // get red and green values
    
        // calculate uv displacement
        vec2 distPos1 = uv + (dispVec * intensity * dispPower); 
        vec2 distPos2 = uv + (dispVec * -(intensity * (1.0 - dispPower)));
    
        // sample images with displaced uv
        vec4 _texture1 = texture2D(texture1, distPos1); 
        vec4 _texture2 = texture2D(texture2, distPos2);
    
        // mix both pictures using effect dispPower value and output pixel color
        gl_FragColor = mix(_texture1, _texture2, dispPower);
      }
    

    it takes 3 textures as an input: picture1 picture2 and noise texture used to distort uv and generates a color value for one pixel of one frame of transition effect on the fly on GPU this shader applied to all pixels of the surface

    a technique used here called "Texture Distortion" or "UV Displacement" the idea is to Adjust UV coordinates with data stored in noise texture.

    the good place to start learning GLSL is https://thebookofshaders.com/

    GLSL reference http://www.shaderific.com/glsl/

    also, I suggest visiting https://www.shadertoy.com/

    And welcome to the magical world of real-time vfx