Tips on generating and receiving shadows in threeJs

As someone who is relatively new to working with threeJS, I have been trying to figure out how to make the shadow of the torus appear on the PlaneGeometry positioned behind it.

I experimented with the .castShadow and .receiveShadow properties, but unfortunately, I did not achieve the desired result.

Could you kindly help me understand what went wrong in my approach?

const canvas = document.getElementById("torus");
// ____RENDERER ___
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true,
  alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);

const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  1,
  500
);
camera.position.set(0, 0, 30);
camera.lookAt(0, 0, 0);

const textureLoader = new THREE.TextureLoader();
const normalTexture = textureLoader.load(
  "https://thumbs.dreamstime.com/b/normal-map-old-rough-loose-concrete-surface-normal-map-old-rough-loose-concrete-surface-texture-use-d-programs-d-195202276.jpg"
);

const scene = new THREE.Scene();

// _____Torus____
const geometry = new THREE.TorusGeometry(4, 1, 16, 100);
const material = new THREE.MeshStandardMaterial({
  metalness: 0.7,
  roughness: 0.2,
  color: new THREE.Color(0xf1f1f1),
  normalMap: normalTexture
});
const torus = new THREE.Mesh(geometry, material);
torus.castShadow = true; 
torus.receiveShadow = false;
scene.add(torus);

// _____Plane______
const planeGeometry = new THREE.PlaneGeometry(20, 20, 32);
const planeMaterial = new THREE.MeshBasicMaterial({
  color: 0xF0F0F0,
  side: THREE.DoubleSide
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.z = -4;
plane.receiveShadow = true;
scene.add(plane);

//______Light
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 6);
pointLight.intensity = 2;
pointLight.castShadow = true;

pointLight.shadow.mapSize.width = 512;
pointLight.shadow.mapSize.height = 512;
pointLight.shadow.camera.near = 0.5;
pointLight.shadow.camera.far = 500;

scene.add(pointLight);
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
scene.add(pointLightHelper);




function createGUI() {
  const lightColor = { color: "#ffffff" };
  var gui = new dat.GUI();

  var gui = gui.addFolder("PointLight 1");

  gui.add(pointLight.position, "x").min(-10).max(10).step(0.01);
  gui.add(pointLight.position, "y").min(-10).max(10).step(0.01);
  gui.add(pointLight.position, "z").min(-10).max(10).step(0.01);
  gui.add(pointLight, "intensity").min(0).max(10).step(0.01);
  gui.addColor(lightColor, "color").onChange(function () {
    pointLight.color.set(lightColor.color);
  });

  gui.open();

}

const animate = function () {
  requestAnimationFrame(animate);

  torus.rotation.x += 0.01;

  renderer.render(scene, camera);
};

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});

window.addEventListener("load", init, false);
function init() {
  createGUI();
  animate();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<canvas id="torus"></canvas>

Answer №1

It appears that you have utilized the MeshBasicMaterial for your plane mesh, which is a type of unlit material. Consequently, it does not have the ability to receive shadows. To rectify this issue, consider using a lit material such as MeshStandardMaterial.

const canvas = document.getElementById("torus");
// ____RENDERER ___
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true,
  alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);

const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  1,
  500
);
camera.position.set(0, 0, 30);
camera.lookAt(0, 0, 0);

const textureLoader = new THREE.TextureLoader();
const normalTexture = textureLoader.load(
  "https://thumbs.dreamstime.com/b/normal-map-old-rough-loose-concrete-surface-normal-map-old-rough-loose-concrete-surface-texture-use-d-programs-d-195202276.jpg"
);

const scene = new THREE.Scene();

// _____Torus____
const geometry = new THREE.TorusGeometry(4, 1, 16, 100);
const material = new THREE.MeshStandardMaterial({
  metalness: 0.7,
  roughness: 0.2,
  color: new THREE.Color(0xf1f1f1),
  normalMap: normalTexture
});
const torus = new THREE.Mesh(geometry, material);
torus.castShadow = true; //default is false
scene.add(torus);

// _____Plane______
const planeGeometry = new THREE.PlaneGeometry(20, 20, 32);
const planeMaterial = new THREE.MeshStandardMaterial({
  color: 0xF0F0F0,
  side: THREE.DoubleSide
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.z = -4;
plane.receiveShadow = true;
scene.add(plane);

//______Light
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 6);
pointLight.intensity = 2;
pointLight.castShadow = true;

pointLight.shadow.mapSize.width = 512;
pointLight.shadow.mapSize.height = 512;
pointLight.shadow.camera.near = 0.5;
pointLight.shadow.camera.far = 500;

scene.add(pointLight);
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
scene.add(pointLightHelper);




function createGUI() {
  const lightColor = { color: "#ffffff" };
  var gui = new dat.GUI();

  var gui = gui.addFolder("PointLight 1");

  gui.add(pointLight.position, "x").min(-10).max(10).step(0.01);
  gui.add(pointLight.position, "y").min(-10).max(10).step(0.01);
  gui.add(pointLight.position, "z").min(-10).max(10).step(0.01);
  gui.add(pointLight, "intensity").min(0).max(10).step(0.01);
  gui.addColor(lightColor, "color").onChange(function () {
    pointLight.color.set(lightColor.color);
  });

  gui.open();

}

const animate = function () {
  requestAnimationFrame(animate);

  torus.rotation.x += 0.01;

  renderer.render(scene, camera);
};

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});

window.addEventListener("load", init, false);
function init() {
  createGUI();
  animate();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<canvas id="torus"></canvas>

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

How can you make a Tempory Drawer wider in Material Components Web?

Increasing the Width of a Temporary Drawer in Material-components-web Greetings! I am currently facing an issue with Material-components-web In the provided demo here, I would like to extend the width of the Temporary drawer to accommodate additional co ...

What is the syntax for defining parameters in an overloaded arrow function in TypeScript?

Trying to create an async arrow function that can handle a single image object or an array of image objects. I'm new to TypeScript overloading and may be approaching this the wrong way. Here's what I've come up with: type ImageType = { ...

Is the image flickering non-stop when the button is pressed?

Every time I push the button, the image on the HTML 5 canvas flickers. After investigating, it seems like the issue might be related to the ctx.clearRect(0,0,100,500) function. Any suggestions on how to fix this problem? I'm currently working on anim ...

Transfer the URL of a template with a PK parameter from JavaScript to Django

I successfully implemented Ajax Search and the results are loaded into a table within a template file. The table header rows are static, and I iterate through each result to append them in < tr > < td >... using a foreach loop. if (data. ...

Populate the AngularJS scope with a dynamically generated array

My Angular Application is functioning properly with <script> var app = angular.module('MyApp', []); app.controller('myCtrl', function ($scope, $sce) { $scope.urls = [ { "url": $sce.t ...

Navigate to a New Page post Dropdown Selection

Currently working on developing a website using Github Pages where I need users to be directed to a specific page after choosing the final option. I am extracting data from a JSON file. I attempted to include an anchor tag in the JSON but it does not red ...

Issue with cordova plugin network interface connectivity

I'm currently working with Ionic 2 Recently downloaded the plugin from https://github.com/salbahra/cordova-plugin-networkinterface Attempting to retrieve IP addresses without utilizing global variables or calling other functions within the function ...

React context fails to refresh

I created a simple project that utilizes Context to store the page title, but I am experiencing an issue where the component is not being re-rendered after setting it. Main files: Context.js import React from 'react' const Context = React.cre ...

issue with the submit button due to non-functional base64 encoded image

After successfully converting multiple file images to base64 format, I encountered an issue when trying to submit the values. When a user selects multiple images and clicks the submit button, the converted base64 values are returned as undefined. How can t ...

Ways to verify the presence of users in the Database

I have successfully retrieved the data with the code below, but I am encountering issues with my script's if and else statements. Any tips or advice on how to improve this functionality? server.post('/like', (req, res,next) => { var ...

Event listener is failing to trigger when clicked in content script and directed to popup on Google Chrome Extension

I created a button within a popup using jQuery click event in a content script, but it is not working. How can I attach a click event to the button by Element ID? It is worth noting that the jQuery Document Load event is functioning properly. The followin ...

Discovering pairs of numbers that are not next to each other in an array that has not been

When working with an array of unsorted numbers, the goal is to identify and extract pairs of elements that are not consecutive. Input [2,3,4,5,9,8,10,13] Desired output (2,5)(8,10)(13,13) To achieve this: Input = [2,3,4,5,9,8,10,13] If we arrange the num ...

Retrieving the headers from an ajax request

Is there a method to retrieve the complete request headers used in an AJAX call made through jQuery? ...

"Using AngularJS to display a blank option as preselected in an ng-option

Having an issue with displaying a preselected value as the selected option in my select element. Check out the code below: <select ng-model="data.company" ng-options="company as company.name for company in companies"></select> $scope.compani ...

What is the best way to replace a state without causing any mutations?

Currently, I am utilizing React and Redux and facing the task of updating my state with new data. Within my state lies an array of objects structured like this: [ { "messages": [/*somedata*/], "users": [/*somedata*/] ...

What is the best way to access nested JSON array data that includes varying key names and content?

In my current project, I am trying to extract data from a JSON array. Here is my approach: Below is the jQuery/JavaScript code I used to generate and retrieve data, particularly focusing on the nodes object which determines different layouts: var getPost ...

Ways to import a library in JavaScript/TypeScript on a web browser?

I'm currently working on a project that involves a TypeScript file and an HTML page. Right now, I am loading the necessary libraries for the TypeScript file in the HTML Page using script tags like <script src="https://unpkg.com/<a href="/cd ...

Can you please explain how I can retrieve information from a Firebase collection using the NextJs API, Firebase Firestore, axios, and TypeScript?

I'm currently utilizing api routes within NextJS 13 to retrieve data from Firebase. The code for this can be found in api/locations.tsx: import { db } from "../../firebase"; import { collection, getDocs } from "firebase/firestore"; ...

Quick tip on closing an Angular-ui modal from a separate controller

I am currently using Angular-ui to display a modal with a form inside. Here is the code snippet: app.controller('NewCaseModalCtrl', ['$http', '$scope','$modal', function ($http, $scope, $modal, $log) { $scope.ite ...

Require a secondary navigation bar to remain fixed below the primary navigation bar as the user scrolls upwards

https://i.sstatic.net/esS0T.png Is there a way to make this second nav bar stick under the main nav bar when the user scrolls up? Currently, it sticks behind the main nav bar. I have attempted a few solutions, but I struggle with JavaScript. Here is the c ...