Creating directional light shadows in Three.JS: A Step-by-Step Guide

Can shadows be generated using a DirectionalLight?

When I utilize SpotLight, shadows are visible. However, when I switch to DirectionalLight, the shadow functionality doesn't seem to work.

Answer №1

Remember that the effectiveness of shadow maps can vary depending on the scale of your scene. For example, in a setup where one unit distance represents one meter and objects are only 0.4 meters in size, adjustments may be necessary to ensure shadows behave as expected. Here are some key steps to consider:

  • Check and adjust the near/far planes of the shadow camera based on your scene's dimensions.
  • Ensure the top/left/bottom/right values of the shadow camera are appropriate to prevent overly large shadow 'pixels' that could go unnoticed.

Let's delve into how to tackle this challenge effectively.

Troubleshooting

To gain insight into how shadows are being rendered per light source, enable debug rendering with CameraHelper:

scene.add(new THREE.CameraHelper(camera)) 

In older versions of Three.js, you can use:

light.shadowCameraVisible = true;

This visualization highlights the volume used for shadow calculations, helping optimize shadow coverage around objects – even more tightly than illustrated here.

Implementation

Below are code snippets to aid in fine-tuning shadow behavior.

var light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 2, 2);
light.target.position.set(0, 0, 0);
light.castShadow = true;
light.shadowDarkness = 0.5;
light.shadowCameraVisible = true; // for debugging purposes
// Define boundaries of the yellow box in the visualization
light.shadowCameraNear = 2;
light.shadowCameraFar = 5;
light.shadowCameraLeft = -0.5;
light.shadowCameraRight = 0.5;
light.shadowCameraTop = 0.5;
light.shadowCameraBottom = -0.5;
scene.add(light);

Ensure specified object(s) cast shadows:

object.castShadow = true;

Guarantee designated object(s) receive shadows:

object.receiveShadow = true;

Lastly, configure settings on the WebGLRenderer:

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(canvasWidth, canvasHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;

Answer №2

Absolutely, directional lights can be used to create shadows in your scene. Just avoid using MeshBasicMaterial as it does not support shadows. Instead, opt for MeshLambertMaterial or MeshPhongMaterial.

To enable shadows in the renderer, you'll need to include these settings:

renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;

renderer.shadowCameraNear = 3;
renderer.shadowCameraFar = camera.far;
renderer.shadowCameraFov = 50;

renderer.shadowMapBias = 0.0039;
renderer.shadowMapDarkness = 0.5;
renderer.shadowMapWidth = 1024;
renderer.shadowMapHeight = 1024;

Make sure to set shadow casting and receiving properties for each object and light like so:

dirLight.castShadow = true;
object.castShadow = true;
otherObject.receiveShadow = true;

Assuming proper positioning of the light and objects, the shadow cast by dirLight will fall on otherObject from object.

[EDIT]: Check out this working demo for a practical example.

Answer №3

Changes in r139.2 include the following attributes:

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; //THREE.BasicShadowMap | THREE.PCFShadowMap |  THREE.VSMShadowMap | THREE.PCFSoftShadowMap

renderer.shadowMap.soft = true;
renderer.shadowMap.bias = -0.0001;
renderer.shadowMap.darkness = 1;
renderer.shadowMap.width = 2048;
renderer.shadowMap.height = 2048;

Example usage:

const spotLight = new THREE.DirectionalLight();
spotLight.castShadow = true;
scene.add(spotLight);
spotLight.position.set(0, 8, 0);

//Object casting shadows
const cube = new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial({color: 0x00ff00}));
cube.castShadow = true;
scene.add(cube);

//Plane floor receiving shadows
const planeShadow = new THREE.Mesh(new THREE.PlaneGeometry(3, 3), new THREE.MeshPhongMaterial()); 
planeShadow.name = "FloorShadow";
planeShadow.renderOrder = -2;
planeShadow.lookAt(new THREE.Vector3(0, 1, 0));
planeShadow.receiveShadow = true;
planeShadow.position.set(0, 0, 0);
scene.add(planeShadow);

For more information or additional examples, please refer to this link [https://sbcode.net/threejs/directional-light-shadow/]

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What exactly does a 'hoisted manifest' mean when it comes to using Yarn?

Encountering an issue while attempting to install a package using yarn, I am receiving the error message: expected hoisted manifest for \"myPackage#@material-ui/core#react-dom\" However, the concept of a 'hoisted manifest' is not entir ...

Ways to invoke a class method by clicking on it

My initialization function is defined as follows: init: function() { $("#editRow").click(function() { <code> } $(".removeRow").click(function() { <code> } } I am trying to find a way to call the class method removeRow directly in the onc ...

Is there a way to access a JSON node dynamically without relying on the eval function?

Path variables can be unpredictable, ranging from just a to a/b, and even a/b/c. My goal is to dynamically reach a node based on the path provided. The code snippet below achieves this, but I am open to exploring alternative methods that do not involve usi ...

Transferring a row name from PHP to AJAX using jQuery - the complete guide

In my current project, I have a table that displays details fetched from the database. if(mysql_num_rows($sql) > 0) { $row_count_n = 1; while($rows = mysql_fetch_assoc($sql)) { extract($rows); $options1 = select_data_as_options( ...

Importing or loading a JavaScript file in Vue.js is a crucial step

I'm in need of some assistance. I've been attempting to load my javascript file and listen for changes on the checkbox when it's clicked to show or hide a password. However, I can't seem to get it to work. I've tried everything I c ...

What is the best way to deactivate certain JavaScript functions on my webpage when accessed through a mobile device?

Is there a way to disable specific JavaScript functions when accessing my website from a mobile device? While I can achieve this using CSS only, certain buttons require JavaScript functionality. Below is the internal JavaScript code: var menuBtn = docume ...

How can I dynamically retrieve the width of an image in React as the screen size changes?

I have successfully implemented an image hover effect on my website. When I hover over a certain text, an image appears. The image is responsive, but I am facing an issue where I want the width of the text to be equal to the width of the image. When I resi ...

Vue.js - experiencing issues with conditional styling not functioning as expected

Can someone help me with an issue I'm having? I've created a button with a heart symbol that is supposed to change color when clicked, but it's not working as expected. This is my current code: <template> <button v-bind: ...

Changing buffer from base64 to UTF-8 encoding in Node.js

My application imports messages from the Notes folder of Gmail using the imap npm module. When following the example on their GitHub page, all message contents are read into a buffer: stream.on('data', function(chunk) { count += chunk.len ...

Using HapiJs in Node.js to communicate data back and forth with the client

I have client.js and server.js files that are used to send data to my server using ajax. I am able to successfully send the searched username, but on the server side, the domain is being received as undefined. I'm unsure if the issue lies on the clien ...

Updating inner text content dynamically can be accomplished without relying on the use of the eval() function

I am faced with a situation where I have multiple batches of code structured like this: 1 <div id="backgrounds" class="centery">Backgrounds 2 <div id="bk1" class="attr">Background 1 3 <div class="container"> 4 ...

Automatically populate textboxes with database information based on selected combobox item without the need to refresh the page

I would like to implement a feature where textboxes are automatically filled from a database when a user selects an option from a combo box. This can be achieved using jQuery or JavaScript in PHP. Once a user selects an element, the corresponding text sh ...

Why are Actions and Reducers essential components in the Redux framework?

Despite my experience with Redux, I still struggle to grasp the purpose of actions and reducers. The documentation defines a reducer as (previousState, action) => newState, a concept also seen in React's useReducer. Having one function handle all ...

The Forge Viewer's getState() function is providing inaccurate values for individual items

In our Angular application, we have integrated the latest version of Forge Viewer and are storing the current state of the viewer in our database for future restoration. After thorough testing, we discovered that isolated nodes are not being saved correct ...

Using a try block inside another try block to handle various errors is a common practice in JavaScript

In an effort to efficiently debug my code and identify the location of errors, I have implemented a try-catch within a try block. Here is a snippet of the code: for (const searchUrl of savedSearchUrls) { console.log("here"); // function will get ...

CSS guidelines for layering shapes and divs

Currently, I am in the process of developing a screenshot application to enhance my understanding of HTML, CSS, and Electron. One of the key features I have implemented is a toggleable overlay consisting of a 0.25 opacity transparent box that covers the en ...

Avoid data duplication or triplication by implementing a pop-up loop when adding new information

Seeking assistance in identifying the line of code that is causing data duplication or triplication when adding information in a pop-up form. The New/Update/Delete functions are functioning correctly, except for the Add function. The problem arises when i ...

What is the best way to conduct a conditional check across all subsequent visible rows of a table?

When a user clicks inside the text input field and presses either the down or up arrow keys, my JavaScript function is triggered. The purpose of this functionality is to search table values and allow the user to select one by pressing the arrow keys. Every ...

It seems that the JavaScript object is producing varied values in distinct locations despite no alterations made in between

I've encountered a puzzling issue where a variable is returning different values within a function, despite no modifications being made to it. This problem arises in a form component created using Vue.js (v2) that triggers a Vuex action. While I beli ...

Error: Unable to find axios module

screenshot of browser developer tool - network I have embedded the script in my base.pug file script(scr='https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js') Upon loading the page and inspecting the browser developer tool > n ...