As we speak we’re sharing a artistic demo that showcases a scanning gentle impact utilizing a depth map. The scene is rendered with WebGPU by way of 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 special visible path. The aim is to reveal 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 is predicated 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 performed 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 throughout the shader to match in opposition to the scene’s depth and calculate the stream of the impact. The scan loops repeatedly, making a constant movement throughout the picture. Moreover, pointer enter is tracked and used to regulate the displacement, introducing a refined 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 resembling smoothstep
, mod
, and blendScreen
are used to outline how totally 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 stream = oneMinus(smoothstep(0, 0.02, abs(depth.sub(uProgress))));
const masks = dot.mul(stream).mul(vec3(10, 0, 0));
const closing = blendScreen(tMap, masks);
const materials = new THREE.MeshBasicNodeMaterial({
colorNode: closing,
});
Rendering and Format
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 prime by way of a separate element, permitting for added visible refinement with out complicating the core shader logic.
const [w, h] = useAspect(WIDTH, HEIGHT);
return (
<mesh scale={[w, h, 1]} materials={materials}>
<planeGeometry />
</mesh>
);
Variations
Three visible variations are included, every utilizing a special base picture and depth map. Whereas the core logic stays the identical, these variations reveal how totally different supply supplies and depth information affect the ultimate look of the impact.