Fake Shadow

5 / 17
Learn core lighting terms (diffuse/specular/rim) on a simple sphere.

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.28 shifts the center down 0.28 units from the sphere's origin
  • - 0.28 subtracts 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

ChangeEffect
Change the 0.28 offset to 0.35Shadow moves down, sphere appears to float higher
Change the 0.08 blur range to 0.02Shadow has a sharper edge
Change 0.35 opacity to 0.7Deeper, more prominent shadow
Change the radius 0.28 to 0.15Smaller 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.

GLSL Code Editor

Correct Code Preview

Current Code Preview