The Torch That Broke the Frame Rate
You're in a dungeon. Stone walls, one flickering torch mounted left of a doorway. The torch sways. Behind every pillar, every crate, every iron bar in the gate, a shadow stretches and shifts. Looks beautiful. Also, depending on how the engine handles it, just made your GPU briefly scream.
Moving a single light source is one of those moments where the gap between a naively built renderer and a carefully engineered one becomes enormous. The question the engine has to answer in roughly sixteen milliseconds: which shadows actually changed, and which ones can I leave alone?
Not all of them. That's the whole game.
Shadow Maps and Why They're Expensive to Rebuild
Most real-time engines, from Unreal to Unity to Godot, represent shadows using shadow mapping. Place a virtual camera at the light source's position, render the scene from that viewpoint, record how far each visible surface sits from the light. That depth recording is the shadow map. Later, when rendering the actual frame, the engine checks whether any given surface point is closer to or farther from the light than the map recorded. Farther away means something is blocking the light. Shadow.
A shadow map for a single dynamic point light isn't one texture. It's a cube map: six faces, one for each direction the light can see. A mid-quality cube shadow map might be 512x512 pixels per face. Regenerating all six faces every frame for every moving light adds up fast.
So engines cheat. Intelligently.
The Four Questions an Engine Asks Before Redrawing Anything
When a torch moves three centimetres to the left, the shadow system runs through a cascade of culling logic before touching the GPU.
Did the light move enough to matter? Most engines use a movement threshold. Unreal Engine's shadow system tracks whether a dynamic light has moved or rotated beyond a small epsilon value before flagging its shadow map as dirty. A torch swaying imperceptibly in a slow ambient animation might never cross that threshold, so its shadow map sits untouched in GPU memory and gets reused frame after frame. Free shadows.
What objects are inside the light's influence radius? Every dynamic light has a radius, a sphere of space it can possibly illuminate. Only geometry inside that sphere can cast or receive shadows from this light. A pillar twenty metres away is simply ignored. The engine builds a list of shadow casters by testing each object's bounding box against the light's radius. A medium-complexity dungeon room might have eighty objects total; maybe fourteen are close enough to matter.
Which of those objects actually moved? Static geometry, a stone wall, a fixed barrel, a motionless iron gate, has its shadow contribution cached. Some engines maintain a separate static shadow map that gets baked once and composited with the dynamic one each frame. Only dynamic objects (the player character, a rolling barrel, a swinging door) need their shadow contributions recalculated. Of those fourteen objects in range, perhaps only three are moving.
How many shadow map faces actually changed? This is the sharp one. If a torch moves forward, away from the wall it's mounted on, the shadows cast behind objects will lengthen on the cube face pointing away from the wall, but the face pointing toward the wall barely changes at all. Some engines track per-face dirtiness. Only the dirty faces get redrawn.
Run through all four filters and you've turned a potentially catastrophic every-frame full rebuild into a partial update of two cube faces covering three dynamic objects. That's not an abstraction. That's approximately what a well-tuned engine does.
A Tale of Two Torches (and Two Very Different Frame Budgets)
Same dungeon. Same hardware. Same torch asset. Two different developers.
The first marks everything in the room as dynamic because it's easier during prototyping. The torch moves. All six shadow map faces are rebuilt. All eighty objects are evaluated as potential casters. The GPU spends around 2.1ms on shadows alone for that one light. With three torches in the room, that's over 6ms, nearly half the 16ms frame budget on shadows before a single character has been drawn.
The second developer marks the stone walls and fixed props as static shadow casters. Those get baked into a static shadow map at load time. Only the player character and two animated props remain dynamic. The torch moves, two cube faces are flagged dirty, three objects are re-evaluated. Shadow cost: roughly 0.3ms. Same visual result, almost identical output on screen, seven times cheaper.
The difference is entirely in how objects were classified. No exotic rendering technique required. Classification is craft, and most people treat it like housekeeping.
What People Overlook: It's Not About the Light
The common assumption is that shadow cost scales with how complex the light is. Bigger radius, more expensive. Softer penumbra, more expensive. That's partially true, but the dominant variable is usually the shadow caster list, specifically how many dynamic objects live inside the light's radius.
Think of it like a guest list for a very expensive party: the light is just the venue, and every dynamic object inside its radius is another guest the caterer has to track.
A torch with a large radius in an empty corridor costs almost nothing. The same torch in a crowd of animated NPCs, each with their own skeleton and moving independently, is genuinely punishing because every NPC's shadow contribution has to be re-evaluated every frame.
This is why dense crowd scenes often use a trick called shadow LOD (level of detail). NPCs beyond a certain distance from the camera cast simplified capsule shadows instead of geometry-accurate ones. The capsule is a single convex hull, trivially cheap to evaluate. You almost never notice the swap.
Are you a developer sitting above 0.5ms per dynamic light in a contained interior space? That number is worth your afternoon.
Cached, Dirty, and the Art of Knowing When to Bother
The deeper principle here is dirtiness tracking. Every object, every light, every shadow map face carries a dirty flag. The engine's job is to keep as many flags clean as possible and only do work when a flag flips.
A static scene with one moving light is cheap because almost nothing flips. A fully dynamic scene with many moving lights is expensive because almost everything does.
The torch doesn't know any of this. It just flickers. The engine is the one quietly deciding, sixty times a second, what actually needs to change and what can stay exactly as it was. Getting that decision right is less about raw GPU power and more about respecting what the engine already knows.