WebGL 액체 왜곡 이미지 호버 효과 - 세 부분 설정

오늘은 두 개의 메인 이미지와 하나의 변위 이미지로 ThreeJS와 TweenMaxJS를 사용하여 액체 왜곡 이미지 효과를 만들어 효과를 만드는 방법을 알려드리겠습니다.

시작하기



계속해서 CodePen playground을 사용하여 새 프로젝트를 초기화하거나 src 폴더 아래에 다음 파일 구조를 사용하여 Visual Studio Code에서 자신의 프로젝트를 설정하십시오.

WebGL Image Hover Master
  |- Images
    |- Image1.png
    |- Image2.png
    |- dist.png
  |- Js
    |- hover.js
    |- script.js
  |- /src
    |- index.html
    |- style.css


파트 1: HTML



index.html을 편집하여 시작하고 다음 코드로 바꿉니다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-with, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="./style.css" />
    <title>WebGl| Liquid Distortion Effect</title>
</head>
<body>
    <div class="landing">
        <div class="distortion"></div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js" integrity="sha256-lPE3wjN2a7ABWHbGz7+MKBJaykyzqCbU96BJWjio86U=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.min.js" integrity="sha256-tAVw6WRAXc3td2Esrjd28l54s3P2y7CDFu1271mu5LE=" crossorigin="anonymous"></script>
    <script>!(function (f, l) {
  "object" == typeof exports && "undefined" != typeof module
    ? (module.exports = l(require("three"), require("gsap/TweenMax")))
    : "function" == typeof define && define.amd
    ? define(["three", "gsap/TweenMax"], l)
    : (f.hoverEffect = l(f.THREE, f.TweenMax));
})(this, function (f, l) {
  return (
    (l = l && l.hasOwnProperty("default") ? l.default : l),
    function (h) {
      function F() {
        for (var f = arguments, l = 0; l < arguments.length; l++)
          if (void 0 !== f[l]) return f[l];
      }
      console.log(
        "%c Hover effect by Robin Delaporte: https://github.com/robin-dela/hover-effect ",
        "color: #bada55; font-size: 0.8rem"
      );
      var w = h.parent,
        L = h.displacementImage,
        M = h.image1,
        P = h.image2,
        U = F(h.intensity1, h.intensity, 1),
        V = F(h.intensity2, h.intensity, 1),
        C = F(h.angle, Math.PI / 4),
        D = F(h.angle1, C),
        S = F(h.angle2, 3 * -C),
        W = F(h.speedIn, h.speed, 1.6),
        _ = F(h.speedOut, h.speed, 1.2),
        z = F(h.hover, !0),
        q = F(h.easing, Expo.easeOut),
        G = F(h.video, !1);
      if (w)
        if (M && P && L) {
          var A = new f.Scene(),
            B = new f.OrthographicCamera(
              w.offsetWidth / -2,
              w.offsetWidth / 2,
              w.offsetHeight / 2,
              w.offsetHeight / -2,
              1,
              1e3
            );
          B.position.z = 1;
          var k = new f.WebGLRenderer({ antialias: !1, alpha: !0 });
          k.setPixelRatio(window.devicePixelRatio),
            k.setClearColor(16777215, 0),
            k.setSize(w.offsetWidth, w.offsetHeight),
            w.appendChild(k.domElement);
          var J = function () {
              k.render(A, B);
            },
            K = new f.TextureLoader();
          K.crossOrigin = "";
          var N = K.load(L, J);
          if (((N.wrapS = N.wrapT = f.RepeatWrapping), G)) {
            var Q = function () {
              requestAnimationFrame(Q), k.render(A, B);
            };
            Q(),
              ((G = document.createElement("video")).autoplay = !0),
              (G.loop = !0),
              (G.src = M),
              G.load();
            var X = document.createElement("video");
            (X.autoplay = !0), (X.loop = !0), (X.src = P), X.load();
            var Y = new f.VideoTexture(G),
              Z = new f.VideoTexture(X);
            (Y.magFilter = Z.magFilter = f.LinearFilter),
              (Y.minFilter = Z.minFilter = f.LinearFilter),
              X.addEventListener(
                "loadeddata",
                function () {
                  X.play(),
                    ((Z = new f.VideoTexture(X)).magFilter = f.LinearFilter),
                    (Z.minFilter = f.LinearFilter),
                    ($.uniforms.texture2.value = Z);
                },
                !1
              ),
              G.addEventListener(
                "loadeddata",
                function () {
                  G.play(),
                    ((Y = new f.VideoTexture(G)).magFilter = f.LinearFilter),
                    (Y.minFilter = f.LinearFilter),
                    ($.uniforms.texture1.value = Y);
                },
                !1
              );
          } else
            (Y = K.load(M, J)),
              (Z = K.load(P, J)),
              (Y.magFilter = Z.magFilter = f.LinearFilter),
              (Y.minFilter = Z.minFilter = f.LinearFilter);
          var $ = new f.ShaderMaterial({
              uniforms: {
                intensity1: { type: "f", value: U },
                intensity2: { type: "f", value: V },
                dispFactor: { type: "f", value: 0 },
                angle1: { type: "f", value: D },
                angle2: { type: "f", value: S },
                texture1: { type: "t", value: Y },
                texture2: { type: "t", value: Z },
                disp: { type: "t", value: N },
              },
              vertexShader:
                "\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n",
              fragmentShader:
                "\nvarying vec2 vUv;\n\nuniform float dispFactor;\nuniform sampler2D disp;\n\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform float angle1;\nuniform float angle2;\nuniform float intensity1;\nuniform float intensity2;\n\nmat2 getRotM(float angle) {\n  float s = sin(angle);\n  float c = cos(angle);\n  return mat2(c, -s, s, c);\n}\n\nvoid main() {\n  vec4 disp = texture2D(disp, vUv);\n  vec2 dispVec = vec2(disp.r, disp.g);\n  vec2 distortedPosition1 = vUv + getRotM(angle1) * dispVec * intensity1 * dispFactor;\n  vec2 distortedPosition2 = vUv + getRotM(angle2) * dispVec * intensity2 * (1.0 - dispFactor);\n  vec4 _texture1 = texture2D(texture1, distortedPosition1);\n  vec4 _texture2 = texture2D(texture2, distortedPosition2);\n  gl_FragColor = mix(_texture1, _texture2, dispFactor);\n}\n",
              transparent: !0,
              opacity: 1,
            }),
            y = new f.PlaneBufferGeometry(w.offsetWidth, w.offsetHeight, 1),
            b = new f.Mesh(y, $);
          A.add(b),
            z &&
              (w.addEventListener("mouseenter", j),
              w.addEventListener("touchstart", j),
              w.addEventListener("mouseleave", O),
              w.addEventListener("touchend", O)),
            window.addEventListener("resize", function (f) {
              k.setSize(w.offsetWidth, w.offsetHeight);
            }),
            (this.next = j),
            (this.previous = O);
        } else console.warn("One or more images are missing");
      else console.warn("Parent missing");
      function j() {
        l.to($.uniforms.dispFactor, W, {
          value: 1,
          ease: q,
          onUpdate: J,
          onComplete: J,
        });
      }
      function O() {
        l.to($.uniforms.dispFactor, _, {
          value: 0,
          ease: q,
          onUpdate: J,
          onComplete: J,
        });
      }
    }
  );
});
//# sourceMappingURL=hover-effect.umd.js.map
</script>
    <script src="./script.js"></script>
</body>
</html>


파트 2: CSS



다음 단계는 다음 스타일을 추가하고 style.css 파일을 완성하는 것입니다. 캔버스를 감싸는 div가 문서에 맞는지 확인하고 평면 div 요소에 원하는 크기를 적용하십시오.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background: white;
}
.landing {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50%;
  height: 50vh;
  box-shadow: 0 32px 32px -8px rgba(0, 0, 0, 0.5);
}
.distortion {
  position: fixed;
    width: 50vw;
    height: 50vh;
}


파트 3: 자바스크립트



이제 우리는 JavaScript 로직을 ThreeJS 설정에 구현할 수 있습니다.

new hoverEffect({
  parent: document.querySelector('.distortion'),
  intensity: 0.2,
  image1: 'https://images.unsplash.com/photo-1608501078713-8e445a709b39?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8d2FsbHBhcGVyJTIwNGt8ZW58MHx8MHx8&auto=format&fit=crop&w=600&q=60', 
  image2: 'https://images.unsplash.com/photo-1580617971627-cffa74e39d1d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwcm9maWxlLXBhZ2V8OTR8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=600&q=60',
  speedIn: 2,
  speedOut: 5,
  angle1 : Math.PI / 6,
  angle2 : -Math.PI / 6 * 3,
  displacementImage: 'https://i.postimg.cc/QNTRDRks/4.png',
  //displacementImage: 'https://i.ibb.co/tbSbc6k/clouds.jpg',
});


시원한! 이제 저장하면 브라우저에 표시됩니다.



요약



따라했다면 프로젝트를 완료하고 액체 왜곡 효과를 마무리했을 것입니다.

이제 여기까지 했다면 코드를 내Sandbox에 연결하여 포크하거나 복제하면 작업이 완료됩니다.

라이선스: 📝



이 프로젝트는 MIT 라이선스(MIT)에 따릅니다. 자세한 내용은 라이센스를 참조하십시오.

기여



기여는 언제나 환영합니다...

🔹 저장소 포크
🔹 현재 프로그램 개선
🔹 기능 개선
🔹 새로운 기능 추가
🔹 버그 수정
🔹 작업 푸시 및 풀 리퀘스트 생성

유용한 리소스



https://cdnjs.com/libraries/three.js/
https://cdnjs.com/libraries/gsap

좋은 웹페이지 즐겨찾기