Fake Shadow
This tutorial fakes a shadow by drawing a blurry ellipse below the sphere — no ray tracing needed. The key lines are:
Let's break down the technique.
What is a fake shadow
Real shadows require tracing rays through the scene to find occlusions — expensive in a fragment shader. A fake shadow takes a shortcut: a shadow on a flat ground is roughly the shape of the object's silhouette projected down. For a sphere, that's an ellipse. Just paint a blurry dark ellipse below the sphere and it reads convincingly as a shadow.
Drawing the ellipse with an SDF
length(vec2(p.x, p.y+0.28)) - 0.28 is the signed distance field of a circle:
p.y + 0.28shifts the center down 0.28 units from the sphere's origin- 0.28subtracts the radius, so the SDF equals 0 exactly on the circle's edge
Feeding that distance into smoothstep(0.0, 0.08, d) smoothly transitions from 0 (inside) to 1 (outside) over an 0.08-wide band. Flipping with 1.0 - ... makes the interior 1 (shadow present) and the exterior 0 (no shadow).
Controlling shadow darkness
The raw mask peaks at 1.0 (solid black). Multiplying by 0.35 caps it at 35% opacity, making the shadow semi-transparent and more natural. Then mix(bg, vec3(0.0), shadow) blends the background toward black based on shadow strength.
Try changing it
| Change | Effect |
|---|---|
Change the 0.28 offset to 0.35 | Shadow moves down, sphere appears to float higher |
Change the 0.08 blur range to 0.02 | Shadow has a sharper edge |
Change 0.35 opacity to 0.7 | Deeper, more prominent shadow |
Change the radius 0.28 to 0.15 | Smaller shadow |
Exercise
The exercise has the sphere already drawn, but shadow is not computed. Fill in the SDF calculation for the shadow and blend it into the background color, so a soft elliptical shadow appears beneath the sphere.
Answer Breakdown
The starting code renders the background directly as bg with no shadow.
length(vec2(p.x, p.y+0.28)) - 0.28 places a circle SDF centered 0.28 units below the sphere's origin, with radius 0.28. smoothstep(0.0, 0.08, d) maps distances 0–0.08 smoothly to 0→1; 1.0 - ... flips it so the interior is 1. Multiplying by 0.35 sets opacity, and mix(bg, vec3(0.0), shadow) composites the dark patch onto the background.
Try replacing the fixed 0.28 y-offset with p.x * 0.2 + 0.28 to shift the shadow sideways based on x-position, simulating angled light.