At the moment we’re sharing a artistic demo that showcases a scanning gentle impact utilizing a depth map. The scene is rendered with WebGPU through Three.js and react-three-fiber
, and enhanced utilizing TSL shaders for dynamic visible depth.
This demo consists of three variations of the impact, every exhibiting a distinct visible course. The aim is to exhibit how combining depth info with post-processing can create a enjoyable scanning impact that makes every part really feel alive:
Behind the Impact
Picture and Depth Map
The visible impact relies on a mix of a base picture and a corresponding depth map. The depth info is used to introduce a slight displacement within the picture’s UV coordinates, making a parallax-like distortion that provides a way of spatial depth.
const [rawMap, depthMap] = useTexture(
[TEXTUREMAP.src, DEPTHMAP.src],
() => {
setIsLoading(false);
rawMap.colorSpace = THREE.SRGBColorSpace;
}
);
Procedural Grid and Masking
A dot grid is generated procedurally utilizing cell noise. The place of the scan line determines which areas of the grid are revealed or hidden. That is executed by calculating distance from the scan line and mixing that with brightness values derived from the noise sample. The result’s a masks that fades out and in easily because the scan progresses.
const facet = float(WIDTH).div(HEIGHT);
const tUv = vec2(uv().x.mul(facet), uv().y);
const tiling = vec2(120.0);
const tiledUv = mod(tUv.mul(tiling), 2.0).sub(1.0);
const brightness = mx_cell_noise_float(tUv.mul(tiling).div(2));
const dist = float(tiledUv.size());
const dot = float(smoothstep(0.5, 0.49, dist)).mul(brightness);
Scan Animation
The scanning movement is managed by a uniform that animates from 0 to 1 over time utilizing GSAP. This worth is used inside the shader to check towards the scene’s depth and calculate the movement of the impact. The scan loops constantly, making a constant movement throughout the picture. Moreover, pointer enter is tracked and used to regulate the displacement, introducing a delicate interactive factor.
useGSAP(() => {
gsap.to(uniforms.uProgress, {
worth: 1,
repeat: -1,
period: 3,
ease: 'power1.out',
});
}, [uniforms.uProgress]);
Pointer place is tracked in real-time and handed into the shader.
useFrame(({ pointer }) => { uniforms.uPointer.worth = pointer; });
Shader Composition
The shader is constructed utilizing TSL (The Shader Language), which permits for a modular, readable method to constructing GLSL-like logic in JavaScript. Elements equivalent to smoothstep
, mod
, and blendScreen
are used to outline how completely different visible layers work together. The ultimate composition blends the displaced picture with the animated dot masks utilizing display screen mixing.
const depth = tDepthMap;
const movement = oneMinus(smoothstep(0, 0.02, abs(depth.sub(uProgress))));
const masks = dot.mul(movement).mul(vec3(10, 0, 0));
const ultimate = blendScreen(tMap, masks);
const materials = new THREE.MeshBasicNodeMaterial({
colorNode: ultimate,
});
Rendering and Structure
Rendering is dealt with with react-three-fiber
and Three.js’s WebGPU renderer. The canvas maintains facet ratio utilizing useAspect
from @react-three/drei
, making certain the picture scales persistently. Put up-processing passes are layered on high through a separate element, permitting for extra visible refinement with out complicating the core shader logic.
const [w, h] = useAspect(WIDTH, HEIGHT);
return (
);
Variations
Three visual variations are included, each using a different base image and depth map. While the core logic remains the same, these variations demonstrate how different source materials and depth data influence the final look of the effect.