A tutorial walks through creating a relighting effect for flat 2D images using depth maps generated by depth estimation models, combined with Three.js, TSL, and WebGPU. It covers converting 8-bit depth maps to smoothed float data, deriving normal maps from depth gradients to fake 3D surface lighting, computing soft shadows via ray marching through the depth map, and combining all three (color, normals, ambient occlusion) into a MeshPhongNodeMaterial for realistic dynamic lighting on flat images.
Questions this post answers
How can I create a normal map from a depth map for realistic lighting on a flat image using Three.js TSL?
Sample the depth texture at neighboring UV offsets along the x and y axes, subtract left from right and bottom from top, and scale the result to get the surface slope. Combine this slope vector with a constant z of 1 to build a normal vector, then normalize it. Optionally add a second gradient computed from the image's brightness to fake extra surface detail like grooves. Developers experimenting with WebGPU shader effects can find more Three.js techniques like this on daily.dev.
Why does my depth map produce blotchy or stepped lighting artifacts in a shader?
Raw depth maps are typically 8-bit images with only 256 possible values, so smooth surfaces get quantized into flat steps. Because lighting calculations read the slope of the depth map, each step edge causes a sudden spike in slope, breaking smooth shading into gritty noise. Fixing it requires converting the depth values to floats and blurring them to smooth out the steps before using them for lighting. Anyone debugging shader lighting artifacts can track similar rendering gotchas on daily.dev.
How do you simulate self-shadowing on a flat image using only a depth map?
Each pixel traces a ray toward the light direction through the depth map, sampling depth values at several points along that path. If a sampled point's depth is greater than the expected ray depth at that step, it indicates a blocking bump, and the occlusion amount is accumulated across steps to produce a soft shadow. This shadow value is then fed into a material's ambient occlusion node. Developers building depth-based shading effects can follow more WebGPU and Three.js techniques on daily.dev.