Hover / Maus bewegen für den Depth-Map-Effekt
WebGL · Fragment Shader · React
"use client";
import { useEffect, useRef, useState } from "react";
const VS_SOURCE = `
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = position * 0.5 + 0.5;
vUv.y = 1.0 - vUv.y;
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const FS_SOURCE = `
precision mediump float;
varying vec2 vUv;
uniform sampler2D uImage;
uniform sampler2D uDepth;
uniform vec2 uMouse;
uniform float uIntensity;
uniform vec2 uResolution;
uniform vec2 uImageRes;
void main() {
float containerAspect = uResolution.x / uResolution.y;
float imageAspect = uImageRes.x / uImageRes.y;
vec2 uv = vUv;
// object-fit: contain — ganzes Bild im Frame
if (containerAspect > imageAspect) {
float scale = imageAspect / containerAspect;
uv.x = (uv.x - 0.5) * scale + 0.5;
} else {
float scale = containerAspect / imageAspect;
uv.y = (uv.y - 0.5) * scale + 0.5;
}
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
gl_FragColor = vec4(0.035, 0.035, 0.043, 1.0);
return;
}
float depth = texture2D(uDepth, uv).r;
vec2 displacement = uMouse * depth * uIntensity;
gl_FragColor = texture2D(uImage, uv + displacement);
}
`;
export default function DepthParallax({ image, depthMap, intensity = 0.03 }) {
const containerRef = useRef(null);
const canvasRef = useRef(null);
const mouse = useRef({ x: 0, y: 0 });
useEffect(() => {
const canvas = canvasRef.current;
const container = containerRef.current;
const gl = canvas.getContext("webgl");
// … Shader kompilieren, Texturen laden (Foto + Depth Map)
const render = () => {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
gl.uniform2f(uMouseLoc, mouse.current.x, mouse.current.y);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(render);
};
render();
container.addEventListener("pointermove", (e) => {
const rect = container.getBoundingClientRect();
mouse.current = {
x: ((e.clientX - rect.left) / rect.width) * 2 - 1,
y: -(((e.clientY - rect.top) / rect.height) * 2 - 1),
};
});
}, [image, depthMap, intensity]);
return (
<div ref={containerRef}>
<canvas ref={canvasRef} style={{ pointerEvents: "none" }} />
</div>
);
}
Depth Maphell = vorne




