Command Palette

Search for a command to run...

Hectal
Course outline
Topic 5.4Intermediate ~19 min · step 4 of 7

Lights and Their Cost

In one line

three.js has six kinds of light, each with its own unit and cost. You learn what they are for, how a point light fades with distance (the decay), and why twenty point lights is a mistake: each light adds work to every pixel.

0/7 · 0%

Think of it like this

A photographer has a sun-like window (far away, parallel rays), a bare bulb (rays go everywhere), a torch with a cone, a big soft-box panel, and a white room that bounces light. Every lamp also costs an assistant. In 3D the assistant is the GPU, and it works for every lamp, on every pixel.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

candela (cd)
A unit for how much light a point or spot light sends in one direction.
lumen (lm)
A unit for a light's total output in all directions. A 10 cd point light is 10 × 4π = 125.7 lm.
decay
How fast a point or spot light fades with distance. 2 is the inverse-square law of real light; 0 means no fading.
distance (of a light)
A range beyond which a point or spot light gives no light. 0 means unlimited.

Step by step

01One point light, a floor, a camera above

The first example puts a floor under a point light of 10 cd and looks straight down. The pixel in the middle is the point right under the light.

02Move the light up

The light moves to 1, 2, 3 and 4 m. With default decay the pixel goes 255, 228, 158, 122: 10 / h² divided by π gives 3.18, 0.80, 0.35 and 0.20 linear, and the screen clips the first to 255.

03Try the other settings

decay 1 fades slowly, decay 0 not at all (255 everywhere: clipped). distance: 3 makes the light vanish at 3 m, and the 2 m pixel is 187, dimmer than the uncut 228: the cut-off fades the light well before its edge.

04Add lights and read the shader

The second example adds 1, 5 and 20 coloured point lights. Look at the text of the newest fragment shader, which grows with the light count, and at the programs count, which grows too.

Try it yourself

  1. 1

    Move the cut-off

    In the first example change the cut-off column from 3 to 6. The last column now prints 225, 149 and 99 for 2, 3 and 4 m: the light reaches them, a little dimmer than the uncut 228, 158 and 122.

  2. 2

    Count the cost of 3 lights

    In the second example change [1, 5, 20] to [1, 2, 3]. The programs column prints 1, 2, 3 and the shader text 78161, 78892 and 79623 characters: 731 characters per light. A list of [1, 2, 3, 40, 150] prints 106824 characters for 40 lights and 188038 for 150, with 5 programs.

Code & diagrams

Distance, decay and cut-off of a point light New tab

The camera looks straight down. The picture is the pool of light of the light at 2 m. The 3 m cut-off column is the fourth in the table.

idle

Console

Run the scene to see its console.

Expected console output

point light, intensity 10 (candela): floor pixel straight below
height    decay 2 (default)   decay 1   decay 0   decay 2, distance 3
1 m        255       255       255       255
2 m        228       255       255       187
3 m        158       255       255         0
4 m        122       228       255         0
power of a 10 cd point light: 125.7 lm
20 point lights: what they add to the shader New tab

Each new light count compiles a new shader program (see programs). Draw calls stay 2: lights add work per pixel, not per mesh.

idle

Console

Run the scene to see its console.

Expected console output

lights  programs compiled so far  newest fragment shader
   1            1          78161 characters
   5            2          81085 characters
  20            3          92104 characters
draw calls: 2 (the same for 1 or 20 lights)

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Change the number of lights between frames

In the second example change [1, 5, 20] to [1, 2, 3]: the light count changes after frames were already drawn.

terminal
$ Run
── what you'll see ──
lights programs compiled so far newest fragment shader
1 1 78161 characters
2 2 78892 characters
3 3 79623 characters
Every new light count compiles a new program. Compiling a shader takes time, so on a real page the frame that meets a new light count can be late.

Myth vs fact

Myth

More lights means a better picture.

Fact

More lights means more work per pixel and a bigger shader. Two lights plus an environment beat twenty point lights on look and on speed.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Setting intensity = 0 does not remove a light from the shader; the light is still computed. Setting visible = false removes it from the count, but that changes the shader (a recompile).

  • ▸

    A PointLight's distance in r186 uses a smooth window, not a plain cut: the light is already weaker than the inverse-square value well before distance. That is why 2 m reads 187 with a 3 m cut-off, not 228.

Remember this

  1. 1

    The problem this solves: beginners add lights until the scene looks right, then wonder why a phone stutters. Knowing what each light does and costs, you use two or three well-placed ones, not twenty.

  2. 2

    The six lights. AmbientLight: the same light everywhere, no direction, no shadow. HemisphereLight: sky colour from above, ground colour from below, no shadow. DirectionalLight: parallel rays, like the sun; position only gives the direction. PointLight: rays go out from a point in all directions. SpotLight: a cone from a point. RectAreaLight: a glowing rectangle (a soft-box); it lights only Standard and Physical materials, casts no shadow and needs RectAreaLightUniformsLib.init() first, so this course does not use it.

  3. 3

    Units. three.js r186 uses physical units. PointLight and SpotLight intensity is in candela (cd): how much light goes in one direction. RectAreaLight is in nits (cd per square metre). The light's power property gives the total in lumens: PointLight = intensity × 4π, SpotLight = intensity × π. Ambient, hemisphere and directional intensities are plain strengths, where 1 on a white matt surface facing the light gives 1/π of full white (Topic 5.2).

  4. 4

    Decay. A point or spot light fades with distance. With the default decay = 2 it follows the inverse-square law: twice as far, a quarter of the light. decay = 0 means no fading. distance is a hard cut-off: beyond it the light is zero, and it fades smoothly towards that distance. distance = 0 means no cut-off. The first example prints the floor pixel at 1, 2, 3 and 4 m for each setting.

  5. 5

    Cost. Every light adds a few hundred characters of shader code for every material, and the GPU runs it for every pixel. The second example prints it: about 730 characters of fragment shader per point light. Each time the number of lights changes, three.js compiles a new program.

Explain it without notes

01

A point light of 10 cd hangs 4 m above a floor. By what factor does the light on the floor change if it moves to 2 m, and what does decay 0 change?

02

Why do 20 point lights cost more than one, even if only one mesh is in the scene?

Practice

01

Choose lights for the showroom: one that makes a shadow, one that keeps shadows from going black. Write the two lines.

02

The pool of light must stop 3 m from a lamp, with the default fading. Which property do you set?

Done when you can

  • Name the six lights and say which cast shadows

  • Say which unit each light uses

  • Predict how a point light fades with distance for a given decay

  • Say why the number of lights is built into the shader