Navigate
Search topics across all sections
Light Types
Lights are what bring your 3D scene to life. Without them, most materials show up as solid black. Three.js gives you several light types, each mimicking a different real-world lighting situation.
You build a beautiful scene with detailed materials and textures, but everything renders pitch black. You check your meshes, your camera, your materials — everything looks right. The problem? You forgot to add lights. Most materials (Lambert, Phong, Standard, Physical) need at least one light source to be visible.
Scene renders but all meshes appear completely black.
Real-world
Think about the different lights in your home. Each one behaves differently, and Three.js has a match for each.
Ambient light is like daylight filling a room through windows — it is everywhere at once, comes from no particular direction, and casts no shadows. Everything gets the same amount.
Directional light is the sun — the rays are parallel because the source is so far away. Everything in your scene gets light from the same angle, no matter where it is.
Point light is a bare light bulb hanging from the ceiling — it radiates in all directions from a single point, and objects closer to it are brighter.
Spot light is a flashlight or a stage spotlight — it creates a cone of light pointing in one direction. Things outside the cone stay dark.
Picking the Right Light
Each light type has a trade-off between realism and performance. Here is a quick guide.
Base fill
Ambient or Hemisphere (cheapest)
Main light
Directional (sun, key light)
Local accents
Point or Spot (lamps, flashlights)
Soft panels
RectArea (PBR only, no shadows)
Guided Walkthrough
Let us light a scene step by step, from total darkness to a believable setup.
Step 1 — Prevent total darkness with ambient fill
{/* Soft fill so nothing is pure black */}
<ambientLight intensity={0.3} color="#ffffff" />Ambient light adds a flat amount of brightness to everything. Keep the intensity low (0.1 to 0.4) or your scene will look washed out — like a foggy day with no contrast.
Step 2 — Add a main directional light (the sun)
{/* The "sun" — parallel rays from one direction */}
<directionalLight
position={[5, 10, 5]}
intensity={1.5}
castShadow
/>This is your main light source. The position controls which direction the rays come from. Setting castShadow to true lets it create shadows (we will set those up in the shadows lesson).
Step 3 — Add a warm point light for local atmosphere
{/* A warm bulb near a table or lamp */}
<pointLight
position={[2, 3, 1]}
intensity={8}
color="#ff8844"
distance={20}
decay={2}
/>Point lights radiate in all directions from a single spot. The warm orange color and decay of 2 (physically correct falloff) make this feel like a real lamp. Objects farther away get less light.
<Canvas>
<mesh>
<boxGeometry />
<meshStandardMaterial color="orange" />
</mesh>
{/* No lights — everything is black */}
</Canvas>Without any lights, PBR materials render as pure black — the objects exist but you can't see them.
What you just learned
Ambient light fills the whole scene evenly — cheap but flat, no shadows
Directional light shoots parallel rays like the sun — great as a main light with shadows
Point light radiates in all directions from one spot — like a light bulb, with distance falloff
Spot light casts a cone of light — like a flashlight, with angle and penumbra controls
Question
A scene has only an AmbientLight. No matter how you position or rotate the objects, the shading never changes. Why? And what does that tell you about when ambient light alone is not enough?
Think about it...
You want to simulate a desk lamp shining down on a work surface. Which light type is the best fit?
Try These Challenges
Put what you learned into practice. Try each challenge in the demo above using the Leva controls, then check the solution.
Try This!
Beginner
Turn off all lights — complete darkness?
Try This!
Beginner
Enable only Point — watch it orbit
Try This!
Intermediate
Crank spotAngle to max
These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.
// Toggle by adding/removing from scene
function toggleLight() {
if (light.parent) {
scene.remove(light);
} else {
scene.add(light);
}
}
// Every add/remove recompiles all affected shaders!// 20 point lights for atmosphere
for (let i = 0; i < 20; i++) {
const light = new THREE.PointLight(0xff8844, 1, 10);
light.position.set(Math.random() * 20, 2, Math.random() * 20);
scene.add(light);
}
// 20 extra lighting passes per pixel — performance tanks// RectAreaLight with Lambert — light is ignored
<rectAreaLight args={[0xffffff, 5, 4, 4]} />
<mesh>
<boxGeometry />
<meshLambertMaterial color="#4488ff" />
</mesh>Best Practices
Limit to 1-3 direct lights
Each direct light adds per-pixel shader work. Supplement with an environment map or hemisphere light for ambient fill instead of adding more direct lights.
Use helpers while developing
DirectionalLightHelper, SpotLightHelper, and PointLightHelper visualize light position and direction. They make aiming lights much easier. Remove them before shipping.
Toggle with visible, not add/remove
Setting light.visible to false avoids shader recompilation. Only add or remove lights when you are permanently changing the scene layout.
Hemisphere + Directional for outdoors
For quick outdoor scenes, combine a HemisphereLight (sky and ground fill) with one DirectionalLight (the sun). This classic combo looks convincing with minimal performance cost.