@z_u_l

Как уменьшить размер билда с three.js?

Здравствуйте! Хочу заюзать на сайте эффект https://github.com/robin-dela/hover-effect . Всё хорошо, но вес эффекта с free.js ~ 400 кб, для такого эффекта многовато будет)
Пытался немного иначе импортировать модули библиотеки:
вместо import * as THREE from 'three', сделал так:

import { Scene } from 'three/src/scenes/Scene';
import { OrthographicCamera } from 'three/src/cameras/OrthographicCamera';
import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer';

import { TextureLoader } from 'three/src/loaders/TextureLoader';
import { LinearFilter } from 'three/src/constants';
import { VideoTexture } from 'three/src/textures/VideoTexture.js';
import { ShaderMaterial } from 'three/src/materials/ShaderMaterial.js';
import { Vector4 } from 'three/src/math/Vector4.js';
import { PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
import { Mesh } from 'three/src/objects/Mesh.js';

это помогло, но не сильно. Больше всего съедает места в билде модуль WebGLRenderer. Его можно как-то оптимизировать\сделать меньше под этот эффект? Кто сталкивался с подобным, помогите, пожалуйста.

Полный код эффекта:

import { Scene } from 'three/src/scenes/Scene';
import { OrthographicCamera } from 'three/src/cameras/OrthographicCamera';
import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer';

import { TextureLoader } from 'three/src/loaders/TextureLoader';
import { LinearFilter } from 'three/src/constants';
import { VideoTexture } from 'three/src/textures/VideoTexture.js';
import { ShaderMaterial } from 'three/src/materials/ShaderMaterial.js';
import { Vector4 } from 'three/src/math/Vector4.js';
import { PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
import { Mesh } from 'three/src/objects/Mesh.js';

import TweenMax from 'gsap/TweenMax';

export default function (opts) {

  var vertex = `
varying vec2 vUv;
void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;

  var fragment = `
varying vec2 vUv;

uniform float dispFactor;
uniform float dpr;
uniform sampler2D disp;

uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float angle1;
uniform float angle2;
uniform float intensity1;
uniform float intensity2;
uniform vec4 res;
uniform vec2 parent;

mat2 getRotM(float angle) {
  float s = sin(angle);
  float c = cos(angle);
  return mat2(c, -s, s, c);
}

void main() {
  vec4 disp = texture2D(disp, vUv);
  vec2 dispVec = vec2(disp.r, disp.g);

  vec2 uv = 0.5 * gl_FragCoord.xy / (res.xy) ;
  vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);


  vec2 distortedPosition1 = myUV + getRotM(angle1) * dispVec * intensity1 * dispFactor;
  vec2 distortedPosition2 = myUV + getRotM(angle2) * dispVec * intensity2 * (1.0 - dispFactor);
  vec4 _texture1 = texture2D(texture1, distortedPosition1);
  vec4 _texture2 = texture2D(texture2, distortedPosition2);
  gl_FragColor = mix(_texture1, _texture2, dispFactor);
}
`;

  // please respect authorship and do not remove
  console.log('%c Hover effect by Robin Delaporte: https://github.com/robin-dela/hover-effect ', 'color: #bada55; font-size: 0.8rem');


  function firstDefined() {
    for (var i = 0; i < arguments.length; i++) {
      if (arguments[i] !== undefined) return arguments[i];
    }
  }

  var parent = opts.parent;
  var dispImage = opts.displacementImage;
  var image1 = opts.image1;
  var image2 = opts.image2;
  var imagesRatio = firstDefined(opts.imagesRatio, 1.0);
  var intensity1 = firstDefined(opts.intensity1, opts.intensity, 1);
  var intensity2 = firstDefined(opts.intensity2, opts.intensity, 1);
  var commonAngle = firstDefined(opts.angle, Math.PI / 4); // 45 degrees by default, so grayscale images work correctly
  var angle1 = firstDefined(opts.angle1, commonAngle);
  var angle2 = firstDefined(opts.angle2, -commonAngle * 3);
  var speedIn = firstDefined(opts.speedIn, opts.speed, 1.6);
  var speedOut = firstDefined(opts.speedOut, opts.speed, 1.2);
  var userHover = firstDefined(opts.hover, true);
  var easing = firstDefined(opts.easing, Expo.easeOut);
  var video = firstDefined(opts.video, false);

  if (!parent) {
    console.warn('Parent missing');
    return;
  }

  if (!(image1 && image2 && dispImage)) {
    console.warn('One or more images are missing');
    return;
  }

  var scene = new Scene();
  var camera = new OrthographicCamera(
    parent.offsetWidth / -2,
    parent.offsetWidth / 2,
    parent.offsetHeight / 2,
    parent.offsetHeight / -2,
    1,
    1000
  );

  camera.position.z = 1;

  var renderer = new WebGLRenderer({
    antialias: false,
    alpha: true
  });

  renderer.setPixelRatio(2.0);
  renderer.setClearColor(0xffffff, 0.0);
  renderer.setSize(parent.offsetWidth, parent.offsetHeight);
  parent.appendChild(renderer.domElement);

  var render = function () {
    // This will be called by the TextureLoader as well as TweenMax.
    renderer.render(scene, camera);
  };

  var loader = new TextureLoader();
  loader.crossOrigin = '';

  var disp = loader.load(dispImage, render);
  disp.magFilter = disp.minFilter = LinearFilter;

  if (video) {
    var animate = function() {
        requestAnimationFrame(animate);

        renderer.render(scene, camera);
    };
    animate();

    var video = document.createElement('video');
    video.autoplay = true;
    video.loop = true;
    video.src = image1;
    video.load();

    var video2 = document.createElement('video');
    video2.autoplay = true;
    video2.loop = true;
    video2.src = image2;
    video2.load();

    var texture1 = new VideoTexture(video);
    var texture2 = new VideoTexture(video2);
    texture1.magFilter = texture2.magFilter = LinearFilter;
    texture1.minFilter = texture2.minFilter = LinearFilter;

    video2.addEventListener('loadeddata', function() {
      video2.play();

      texture2 = new VideoTexture(video2);
      texture2.magFilter = LinearFilter;
      texture2.minFilter = LinearFilter;

      mat.uniforms.texture2.value = texture2;

    }, false);

    video.addEventListener('loadeddata', function() {
      video.play();

      texture1 = new VideoTexture(video);

      texture1.magFilter = LinearFilter;
      texture1.minFilter = LinearFilter;

      mat.uniforms.texture1.value = texture1;
    }, false);
  } else {
    var texture1 = loader.load(image1, render);
    var texture2 = loader.load(image2, render);

    texture1.magFilter = texture2.magFilter = LinearFilter;
    texture1.minFilter = texture2.minFilter = LinearFilter;
  }

  let a1, a2;
  var imageAspect = imagesRatio;
  if (parent.offsetHeight / parent.offsetWidth < imageAspect) {
    a1 = 1;
    a2 = parent.offsetHeight / parent.offsetWidth / imageAspect;
  } else {
    a1 = (parent.offsetWidth / parent.offsetHeight) * imageAspect;
    a2 = 1;
  }

  var mat = new ShaderMaterial({
    uniforms: {
      intensity1: {
        type: 'f',
        value: intensity1
      },
      intensity2: {
        type: 'f',
        value: intensity2
      },
      dispFactor: {
        type: 'f',
        value: 0.0
      },
      angle1: {
        type: 'f',
        value: angle1
      },
      angle2: {
        type: 'f',
        value: angle2
      },
      texture1: {
        type: 't',
        value: texture1
      },
      texture2: {
        type: 't',
        value: texture2
      },
      disp: {
        type: 't',
        value: disp
      },
      res: {
        type: 'vec4',
        value: new Vector4(parent.offsetWidth, parent.offsetHeight, a1, a2)
      },
      dpr: {
        type: 'f',
        value: window.devicePixelRatio
      }
    },

    vertexShader: vertex,
    fragmentShader: fragment,
    transparent: true,
    opacity: 1.0,
  });

  var geometry = new PlaneBufferGeometry(parent.offsetWidth, parent.offsetHeight, 1);
  var object = new Mesh(geometry, mat);
  scene.add(object);

  function transitionIn() {
    TweenMax.to(mat.uniforms.dispFactor, speedIn, {
      value: 1,
      ease: easing,
      onUpdate: render,
      onComplete: render,
    });
  }

  function transitionOut() {
    TweenMax.to(mat.uniforms.dispFactor, speedOut, {
      value: 0,
      ease: easing,
      onUpdate: render,
      onComplete: render,
    });
  }

  if (userHover) {
    parent.addEventListener('mouseenter', transitionIn);
    parent.addEventListener('touchstart', transitionIn);
    parent.addEventListener('mouseleave', transitionOut);
    parent.addEventListener('touchend', transitionOut);
  }

  window.addEventListener('resize', function (e) {
    if (parent.offsetHeight / parent.offsetWidth < imageAspect) {
      a1 = 1;
      a2 = parent.offsetHeight / parent.offsetWidth / imageAspect;
    } else {
      a1 = (parent.offsetWidth / parent.offsetHeight) * imageAspect;
      a2 = 1;
    }
    object.material.uniforms.res.value = new Vector4(parent.offsetWidth, parent.offsetHeight, a1, a2);
    renderer.setSize(parent.offsetWidth, parent.offsetHeight);

    render()
  });

  this.next = transitionIn;
  this.previous = transitionOut;
};
  • Вопрос задан
  • 311 просмотров
Пригласить эксперта
Ответы на вопрос 2
@HungryGrizzzly
Сумасшедший кросс
По своему опыту могу сказать - никак. Вроде как я натыкался на либу, если её можно так назвать, в ней всего строк сто кода и она как раз реализовывать то, что вам нужно (пробрасывает шейдеры и юниформы) . Постараюсь найти.
Upd. Посмотрите другие либы
https://gist.github.com/dmnsgn/76878ba6903cf15789b...
Ответ написан
Комментировать
@Shamhaner
Проще из библиотеки three.js удалить неиспользуемое, а не тянуть всю библиотеку.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы