Здравствуйте! Хочу заюзать на сайте эффект
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;
};