Three.js - Lights & Shadows



Lights make the objects visible, similarly, in Three.js THREE.Light lights up the scene and makes some things visible. Not all materials are affected by lighting. The MeshBasicMaterial and MeshNormalMaterial are self-illuminating, so they don't need lighting to be visible within a scene. However, most of the other materials do, the MeshLambertMaterial, MeshPhongMaterial, MeshStandardMaterial, MeshPhysicalMaterial, and MeshToonMaterial. We'll discuss more materials in further chapters. In this chapter, we'll focus on different types of lights in Three.js.

Every light has color and intensity properties.

  • color − (optional) hexadecimal color of the light. Default is 0xffffff (white).

  • intensity − (optional) numeric value of the light's strength/intensity. Default is 1.

Casting Shadows

The light that is coming from a specific direction can cast shadows. First, we should make the scene ready for casting shadows.

Step − 1

We should first tell the renderer that we want to enable shadows. Casting shadows is an expensive operation. WebGLRenderer only supports this functionality. It uses Shadow mapping, a technique specific to WebGL, performed directly on the GPU.

renderer.shadowMapEnabled = true

The above line of code tells the renderer to cast shadows in the scene.

Note − Three.js, by default, uses shadow maps. Shadow map works for light that casts shadows.

The scene renders all objects marked to cast shadows from the point of view of the light.

If your shadow looks a bit blocky around its edges, it means the shadow map is too small. To increase the shadow map size, you can define shadowMapHeight and shadowMapWidht properties for the light. Alternatively, you can also try to change the shadowMapType property of WebGLRenderer. You can set this to THREE.BasicShadowMap, THREE.PCFShadowMap, or THREE.PCFSoftShadowMap.

// to antialias the shadow
renderer.shadowMapType = THREE.PCFSoftShadowMap
// or
directionalLight.shadowMapWidth = 2048
directionalLight.shadowMapHeight = 2048

Step − 2

You should configure objects to cast shadows. You can inform Three.js which objects can cast shadows and which objects can receive shadows.

object.castShadow = true
object.recieveShadow = true

Step − 3

All the above steps are the same for every light. The next step is to set up the shadow-related properties.

light.castShadow = true
light.shadow.camera.near = 10
light.shadow.camera.far = 100
light.shadow.camera.left = -50
light.shadow.camera.right = 50
light.shadow.camera.top = 50
light.shadow.camera.bottom = -50

The first property, castShadow, tells Three.js that this light casts shadows. As casting shadows is an expensive operation, we need to define the area where shadows can appear. You can do it with the shadow.camera.near, shadow.camera.far, and shadow.camera.left, etc. properties. With the above properties, we create a box-like area where Three.js render shadows.

Example

Explore more in this example.

directional.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js - Directional Light</title>
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
            Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
   <div id="container"></div>
      <script type="module">
         // Adding directional light to the scene
         // The lights falls from the light only in one direction.
         // You can see the position of light using helpers provided in Three.j
         s for debugging purposes

         // GUI
         const gui = new dat.GUI()
         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0x262626)
         // camera
         const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000)
         camera.position.set(0, 0, 10)
         const camFolder = gui.addFolder('Camera')
         camFolder.add(camera.position, 'z', 10, 80, 1)
         camFolder.open()
         // lights
         const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
         scene.add(ambientLight)
         const light = new THREE.DirectionalLight()
         light.position.set(2.5, 2, 2)
         light.castShadow = true
         light.shadow.mapSize.width = 512
         light.shadow.mapSize.height = 512
         light.shadow.camera.near = 0.5
         light.shadow.camera.far = 100
         scene.add(light)
         const helper = new THREE.DirectionalLightHelper(light)
         scene.add(helper)
         // light controls
         const lightColor = {
            color: light.color.getHex()
         }
         const lightFolder = gui.addFolder('Directional Light')
         lightFolder.addColor(lightColor, 'color').onChange(() => {
         light.color.set(lightColor.color)
         })
         lightFolder.add(light, 'intensity', 0, 1, 0.01)
         lightFolder.open()
         const directionalLightFolder = gui.addFolder('Position of Light')
         directionalLightFolder.add(light.position, 'x', -10, 10, 0.1)
         directionalLightFolder.add(light.position, 'y', -10, 10, 0.1)
         directionalLightFolder.add(light.position, 'z', -10, 10, 0.1)
         directionalLightFolder.open()
         // plane
         const planeGeometry = new THREE.PlaneGeometry(100, 20)
         const plane = new THREE.Mesh(planeGeometry, new THREE.MeshPhongMateria
         l({ color: 0xffffff }))
         plane.rotateX(-Math.PI / 2)
         plane.position.y = -1.75
         plane.receiveShadow = true
         scene.add(plane)
         // cube
         const geometry = new THREE.BoxGeometry(2, 2, 2)
         const material = new THREE.MeshStandardMaterial({
            color: 0x87ceeb
         })
         const materialFolder = gui.addFolder('Material')
         materialFolder.add(material, 'wireframe')
         materialFolder.open()
         const cube = new THREE.Mesh(geometry, material)
         cube.position.set(0, 0.5, 0)
         cube.castShadow = true
         cube.receiveShadow = true
         scene.add(cube)
         // responsiveness
         window.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer
         const renderer = new THREE.WebGL1Renderer()
         renderer.setSize(window.innerWidth, window.innerHeight)
         renderer.shadowMap.enabled = true
         renderer.shadowMap.type = THREE.PCFSoftShadowMap
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         // animation
         function animate() {
            requestAnimationFrame(animate)
            cube.rotation.x += 0.005
            cube.rotation.y += 0.01
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         animate()
      </script>
   </body>
</html>

Output

Spot Light
Sr.No Lights & Description
1

Ambient Light

It is the most basic light, which illuminates the whole scene equally.

2

Directional Light

Directional light comes from a specific point and is emitted directly from far away to the target.

3

Spotlight

It is another kind of light that comes from a specific direction in the shape of the cone.

4

Point Light

The point light is a light source that emits light in all directions from a single point.

5

Hemisphere Light

It is a special light for creating natural lighting.

Advertisements