articles » current » javascript » three-js » shadows

ThreeJS: Cast Shadows

Cast object shadows and receive shadows from objects; how to create shadows in THREE.js, including how to configure a 3D model to cast and receive a shadow.

These are the steps to create shadows in THREE.js:

  1. Create an HTML document with a <CANVAS> element.
  2. Create a THREE.js scene object.
  3. Create a THREE.js camera object with the frustum defined; position the camera back a little to view the scene.
  4. Create a THREE.js renderer object.
  5. Set the renderer.shadowMap.enabled to true.
  6. Create and add to the scene the THREE.js objects that will cast shadows on each other making sure to use a reflective material such as MeshPhongMaterial.
  7. For each object set the receiveShadow and castShadow properties to true for a realistic rendering.
  8. At least one light of a directional type must be created.
    1. Set its castShadow property to true.
    2. Set its shadow.mapSize.width property to the canvas size or an arbitrary value (1024 works well).
    3. Set its shadow.mapSize.height property to the canvas size or an arbitrary value (1024 works well).
    4. Set its property to the camera's near frustum value.
    5. Set its property to the camera's far frustum value.
    6. Add the light to the scene.
  9. Animate the scene with a standard animation function.

The following is an example of the above steps. It is layed out to show that shadows are cast and received by several scene objects.

<!DOCTYPE html>
<html lang="en">
	<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>Shadows Example</title>
		body {
			margin: 0;
			padding: 0;
			height: 100vh;
		canvas {
			display: block;
			width: 100%;
			height: 100vh;
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

(function () {

	var canvas = document.getElementsByTagName("canvas")[0];

	// NOTE: create the scene to place objects in
	var scene = new THREE.Scene();
	scene.background = new THREE.Color(0x6699CC); // NOTE: make the background blue for the sky
	scene.matrixWorldAutoUpdate = true;

	var size = {
		width: canvas.offsetWidth,
		height: canvas.offsetHeight

	// NOTE: issue these statements when resizing the window
	// camera.aspect = size.width / size.height;
	// camera.updateProjectionMatrix();
	// renderer.setPixelRatio(window.devicePixelRatio);
	// renderer.setSize(size.width, size.height);

	var cameraNear = 1, cameraFar = 5000;
	// NOTE: create the camera with 60 degree field of view; this is how the scene is viewed by the user
	var camera = new THREE.PerspectiveCamera(60, size.width / size.height, cameraNear, cameraFar);

	// NOTE: position the camera in space a bit
	camera.position.z = 20;

	var renderer = new THREE.WebGLRenderer({
		canvas: canvas,
		antialias: true
	renderer.shadowMap.enabled = true; // NOTE: must enable shadowing on the renderer
	renderer.setSize(size.width, size.height);
	renderer.render(scene, camera);

	var objects = {};

	objects.sphere = new THREE.Mesh(new THREE.SphereGeometry(2, 32, 32), new THREE.MeshPhongMaterial({ color: 0xFFFFFF, dithering: true }));
	// NOTE: position each object in space
	objects.sphere.position.x = -9;
	objects.sphere.position.y = 3;
	objects.sphere.position.z = -1;
	// NOTE: receiving shadows and casting them is the most natural
	objects.sphere.receiveShadow = true;
	objects.sphere.castShadow = true;
	scene.add(objects.sphere); = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), new THREE.MeshPhongMaterial({ color: 0xFFFFFF, dithering: true })); = 0; = 3.5; = true; = true;

	objects.torus = new THREE.Mesh(new THREE.TorusGeometry(1, 0.5, 16, 100), new THREE.MeshPhongMaterial({ color: 0xFFFFFF, dithering: true }));
	objects.torus.position.x = 9;
	objects.torus.position.y = 4;
	objects.torus.position.z = 2;
	objects.torus.receiveShadow = true;
	objects.torus.castShadow = true;

	// NOTE: create the ground plane and make sure it can receive shadows
	var plane = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000), new THREE.MeshPhongMaterial({ color: 0x00aa00, dithering: true }));
	plane.position.x = 0;
	plane.position.y = 0;
	plane.position.z = -50;
	plane.rotation.x = 4.75;
	plane.receiveShadow = true;

	var light = new THREE.PointLight(0xffffff, 1);
	light.position.set(20, 8, 5); // NOTE: the farther away the light is from the objects then the blockier the shadows will be

	// NOTE: must configure light to create shadows
	light.castShadow = true;
	light.shadow.mapSize.width = 1024;
	light.shadow.mapSize.height = 1024; = cameraNear; = cameraFar;


	scene.add(new THREE.AmbientLight(0xffffff, .33)); // NOTE: add a touch of ambient light

	var animate = function () {

		for(var name in objects) {
			objects[name].rotation.x += 0.01;
			objects[name].rotation.y += 0.02;
			objects[name].rotation.z += 0.03;

		renderer.render(scene, camera);


Configure 3D Models to Cast and Receive Shadows

THREE.js supports 3D models and these can be configured to cast and receive shadows, too. Each node of the model must be configured to cast and/or receive a shadow.

// NOTE: load the GLTFLoader library first
var modelPath = "/gltf/model.gltf";
new THREE.GLTFLoader().load(modelPath, function (gltf) {
	var model = gltf.scene;
	model.traverse(function(node) {
		if(node.isMesh) {
			node.castShadow = node.receiveShadow = true; // NOTE: either property is optional

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.