ThreeJS is not casting shadows

Viewed 38

I am building a basic Three JS application. Basically, I am learning Three JS and so that I am experimenting with it. Now, I am building a scene where there is a floor, an object and a light. I want to see the shadow of the object on the floor due to light. This is my code.

import * as THREE from 'three';
const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);

const renderer = new THREE.WebGLRenderer();
renderer.shadowMapEnabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);

var shape = new THREE.TorusGeometry(100, 50, 8, 20);
var cover = new THREE.MeshPhongMaterial();
cover.emissive.setRGB(0.8, 0.1, 0.1);
cover.specular.setRGB(0.9, 0.9, 0.9);
var donut = new THREE.Mesh(shape, cover); scene.add(donut);
donut.castShadow = true;

var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;

var shape = new THREE.PlaneGeometry(1500, 1500);
var cover = new THREE.MeshBasicMaterial();
var ground = new THREE.Mesh(shape, cover);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

I am supposed to see the shadow of the donut on the floor. But this is what I see instead without shadow.

enter image description here

What is wrong with my code and how can I fix it?

2 Answers

You have to make the ground to receive shadow

to do this:

ground.receiveShadow = true;

There are multiple issues in your code. The most important problem is that you do not configure your shadow frustum correctly. Besides, MeshBasicMaterial is not affected by light and thus can't receive shadows. Try it like so:

const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);

const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);

const donutGeometry = new THREE.TorusGeometry(100, 50, 8, 20);
const donutMaterial = new THREE.MeshPhongMaterial();
donutMaterial.emissive.setRGB(0.8, 0.1, 0.1);
donutMaterial.specular.setRGB(0.9, 0.9, 0.9);
const donut = new THREE.Mesh(donutGeometry, donutMaterial); 
scene.add(donut);
donut.castShadow = true;

var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;
sunlight.shadow.camera.top = 200;
sunlight.shadow.camera.bottom = - 200;
sunlight.shadow.camera.left = - 200;
sunlight.shadow.camera.right = 200;
sunlight.shadow.camera.near = 1;
sunlight.shadow.camera.far = 1000;

//scene.add( new THREE.CameraHelper( sunlight.shadow.camera ) );

const groundGeometry = new THREE.PlaneGeometry(1500, 1500);
const groundMaterial = new THREE.MeshPhongMaterial();
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();
body {
      margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.144/build/three.min.js"></script>

Related