Трансформация фона

Трансформация фона

Модификация позволяет создать эффект искажения изображения при движении мыши. Такой эффект сможет добавить динамичности для блока и разбавить скучный контент.

Описание
Видеоинструкция по подключению
Инструкция с копированием шаблона к себе
ID шаблона:
39830660
Создаём новую страницу на сайте
Шаг 1
Скроллим в самый низ и нажимаем кнопку «Указать ID шаблона»
Шаг 2
В графе указываем номер шаблона (он указан в начале инструкции), нажимаем кнопку «Выбрать»
Шаг 3
Пошаговая инструкция с подключением кода
В Zero блоке создаём HTML блок и помещаем в него код
Шаг 1
<!--Трансформация фона
https://mt-webdesign.ru/transformation-img-->
<div id="mouse-deformation">
<div id="canvas-container">
</div>
</div>
В Zero блоке создаём HTML блок и помещаем в него код
Шаг 2
<!--Трансформация фона
https://mt-webdesign.ru/transformation-img-->
<!-- Поместить под Zero-блоком -->
<style>
#mouse-deformation {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
#canvas-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
canvas {
width: 100% !important;
height: 100% !important;
}
</style>
<script src='https://cdn.jsdelivr.net/npm/ogl@0.0.64/dist/ogl.umd.js'></script>
<script type="module">
const imgSize = [1650, 1200];
const vertex = `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
const fragment = `
precision highp float;
precision highp int;
uniform sampler2D tWater;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;
void main() {
// R and G values are velocity in the x and y direction
// B value is the velocity length
vec3 flow = texture2D(tFlow, vUv).rgb;
vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV -= flow.xy * (0.15 * 0.7);
vec2 myUV2 = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV2 -= flow.xy * (0.125 * 0.7);
vec2 myUV3 = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV3 -= flow.xy * (0.10 * 0.7);
vec3 tex = texture2D(tWater, myUV).rgb;
vec3 tex2 = texture2D(tWater, myUV2).rgb;
vec3 tex3 = texture2D(tWater, myUV3).rgb;
gl_FragColor = vec4(tex.r, tex2.g, tex3.b, 1.0);
}
`;
{
const renderer = new ogl.Renderer({ dpr: 2 });
const gl = renderer.gl;
$(gl.canvas).appendTo('#canvas-container');
let aspect = 1;
const mouse = new ogl.Vec2(-1);
const velocity = new ogl.Vec2();
function resize() {
let a1, a2;
var imageAspect = imgSize[1] / imgSize[0];
if (window.innerHeight / window.innerWidth < imageAspect) {
a1 = 1;
a2 = window.innerHeight / window.innerWidth / imageAspect;
} else {
a1 = (window.innerWidth / window.innerHeight) * imageAspect;
a2 = 1;
}
mesh.program.uniforms.res.value = new ogl.Vec4(
window.innerWidth,
window.innerHeight,
a1,
a2
);
renderer.setSize(window.innerWidth, window.innerHeight);
aspect = window.innerWidth / window.innerHeight;
}
const flowmap = new ogl.Flowmap(gl, {
falloff: 1.0, 
alpha: 0.3,
dissipation: 0.94 
});
const geometry = new ogl.Geometry(gl, {
position: {
size: 2,
data: new Float32Array([-1, -1, 3, -1, -1, 3])
},
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) }
});
const texture = new ogl.Texture(gl, {
minFilter: gl.LINEAR,
magFilter: gl.LINEAR
});
const img = new Image();
img.onload = () => (texture.image = img);
img.crossOrigin = "Anonymous";
img.src = "https://static.tildacdn.com/tild6637-3865-4861-b637-353137633834/nikolay-hristov-E2V8.jpg";
let a1, a2;
var imageAspect = imgSize[1] / imgSize[0];
if (window.innerHeight / window.innerWidth < imageAspect) {
a1 = 1;
a2 = window.innerHeight / window.innerWidth / imageAspect;
} else {
a1 = (window.innerWidth / window.innerHeight) * imageAspect;
a2 = 1;
}
const program = new ogl.Program(gl, {
vertex,
fragment,
uniforms: {
uTime: { value: 0 },
tWater: { value: texture },
res: {
value: new ogl.Vec4(window.innerWidth, window.innerHeight, a1, a2)
},
img: { value: new ogl.Vec2(imgSize[0], imgSize[1]) },
tFlow: flowmap.uniform
}
});
const mesh = new ogl.Mesh(gl, { geometry, program });
const canvasElement = gl.canvas;
window.addEventListener("resize", resize, false);
resize();
const isTouchCapable = "ontouchstart" in window;
if (isTouchCapable) {
let touchStartX = 0;
let touchStartY = 0;
window.addEventListener("touchstart", (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
});
window.addEventListener("touchmove", (e) => {
const touchEndX = e.touches[0].clientX;
const touchEndY = e.touches[0].clientY;
const deltaX = touchEndX - touchStartX;
const deltaY = touchEndY - touchStartY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
} else {
}
});
} else {
canvasElement.addEventListener("mousemove", updateMouse, false);
}
let lastTime;
const lastMouse = new ogl.Vec2();
function updateMouse(e) {
e.preventDefault();
if (e.changedTouches && e.changedTouches.length) {
e.x = e.changedTouches[0].pageX;
e.y = e.changedTouches[0].pageY;
}
if (e.x === undefined) {
e.x = e.pageX;
e.y = e.pageY;
}
mouse.set(e.x / gl.renderer.width, 1.0 - e.y / gl.renderer.height);
if (!lastTime) {
lastTime = performance.now();
lastMouse.set(e.x, e.y);
}
const deltaX = e.x - lastMouse.x;
const deltaY = e.y - lastMouse.y;
lastMouse.set(e.x, e.y);
let time = performance.now();
let delta = Math.max(10.4, time - lastTime);
lastTime = time;
velocity.x = deltaX / delta;
velocity.y = deltaY / delta;
velocity.needsUpdate = true;
}
requestAnimationFrame(update);
function update(t) {
requestAnimationFrame(update);
if (!velocity.needsUpdate) {
mouse.set(-1);
velocity.set(0);
}
velocity.needsUpdate = false;
flowmap.aspect = aspect;
flowmap.mouse.copy(mouse);
flowmap.velocity.lerp(velocity, velocity.len ? 0.15 : 0.1);
flowmap.update();
program.uniforms.uTime.value = t * 0.01;
renderer.render({ scene: mesh });
}
}
</script>
В скрипте меняем путь до изображения
Шаг 3
Более подробные настройки, возможности взаимодействия и подключение в видео
Другие модификации
3D галерея
Tilda
Подсказки при наведении курсора
Tilda