three.js Materials & Lighting
Make three.js surfaces look right: pick the correct material, light the scene, enable shadows, and add image-based lighting. Patterns target r186, verified against r186 (lighting is physically based by default since r155).
When to use
- Use when a mesh renders black or flat, when choosing a material, adding lights, enabling shadows, or setting up environment-map reflections (IBL).
- Use when code constructs
MeshStandardMaterial,DirectionalLight, etc., or setsrenderer.shadowMap.enabledorscene.environment.
When not to use: the renderer/camera/loop → threejs-scene-setup. Loading
models (whose PBR materials this complements) → threejs-gltf-loading. Custom
GLSL/ShaderMaterial is its own topic; for the portable concept see
shader-programming.
Core workflow
- Pick a material by need.
MeshStandardMaterial(PBR:roughness,metalness, reacts to lights/IBL) for realism;MeshPhysicalMaterialfor clearcoat/transmission;MeshBasicMaterial(unlit, ignores lights) for UI/flat;MeshNormalMaterial/MeshDepthMaterialfor debugging. - Add light, or nothing shows. Lit materials need a light source and/or
scene.environment. Combine a soft fill (AmbientLight/HemisphereLight) with a keyDirectionalLight. - Mind light intensity. Since r155, lighting is physically based; modern
intensities are higher than old tutorials (a key
DirectionalLight≈ 1–3). - Enable shadows in three places.
renderer.shadowMap.enabled = true, the light'scastShadow = true, and each mesh'scastShadow/receiveShadow. Then fit the light's shadow camera to the scene. - Use an environment map for grounded reflections. Assign an equirectangular or
PMREM-processed texture to
scene.environment; PBR materials pick it up automatically. - Verify under real lighting — confirm the surface responds to the key light (highlights move), shadows land where expected, and reflections look plausible.
Patterns
1. PBR material under a 3-light rig
2. Unlit material (no light needed)
3. Shadows (the three required switches + camera fit)
4. PBR textures on a material
5. Image-based lighting from an HDR environment
Pitfalls
- Mesh is pure black → a lit material with no light and no
scene.environment. Add a light or an environment map; to confirm geometry, temporarily swap toMeshBasicMaterial/MeshNormalMaterial. - Scene too dark even with lights → old tutorial intensities. r155+ is physically based; raise intensities (key light ≈ 2–3) or add an environment map.
- Shadows don't appear → you missed one of the three switches
(
renderer.shadowMap.enabled,light.castShadow, meshcastShadow/receiveShadow). - Shadows are cut off or blocky → the
DirectionalLight's orthographicshadow.camerafrustum is too big/small or doesn't cover the scene; tightenleft/right/top/bottom/near/farand raiseshadow.mapSize. Visualise it withnew THREE.CameraHelper(light.shadow.camera). - Shadow acne / peter-panning → adjust
light.shadow.bias(small negative) andlight.shadow.normalBias. - Colors look washed out / too bright → color (albedo) textures need
texture.colorSpace = THREE.SRGBColorSpace; normal/roughness/metalness maps must stay linear (leave them asNoColorSpace). - PointLight shadows tank performance → a point light renders the scene 6 times
(cube map). Prefer one shadow-casting
DirectionalLight; use cheaper fakes elsewhere.
References
- For the material cheat-sheet (which
Mesh*Materialfor which look), light types and their parameters/units, transparency vsalphaTestordering, and thePMREMGenerator/RoomEnvironmentroute to IBL without an HDR file, readreferences/materials-lights-table.md.
Related skills
threejs-scene-setup— renderer, camera, and loop (setshadowMap, tone mapping).threejs-gltf-loading— models arrive with PBR materials this skill tunes.shader-programming— custom shader effects (engine-agnostic concept).


