简体   繁体   中英

three.js: Casting SpotLight Shadows

all.

I'm working with three.js 127, following the documentation to add a SpotLight . However, shadows won't get shown on the scene. Below, you can find my scene. I already set the plane to receive shadow as well as other elements enabled to cast shadows yet no shadows are rendered on the scene.

const canvas = document.getElementById('webgl-output')

const init = () => {
  const scene = new THREE.Scene()
  const camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    1000,
  )
  const renderer = new THREE.WebGLRenderer({
    canvas,
  })
  renderer.setClearColor(new THREE.Color(0x000000))
  renderer.setSize(window.innerWidth, window.innerHeight)

  const planeGeometry = new THREE.PlaneGeometry(60, 20)
  const planeMaterial = new THREE.MeshLambertMaterial({
    color: 0xaaaaaa,
  })

  const plane = new THREE.Mesh(planeGeometry, planeMaterial)
  plane.receiveShadow = true
  plane.rotation.x = -0.5 * Math.PI
  plane.position.x = 15
  plane.position.y = 0
  plane.position.z = 0
  scene.add(plane)

  // Creating a cube
  const cubeGeometry = new THREE.BoxGeometry(4, 4, 4)
  const cubeMaterial = new THREE.MeshLambertMaterial({
    color: 0xff0000,
  })
  const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
  cube.castShadow = true
  cube.position.x = -4
  cube.position.y = 3
  cube.position.z = 0
  scene.add(cube)

  // Creating a sphere
  const sphereGeometry = new THREE.SphereGeometry(4, 20, 20)
  const sphereMaterial = new THREE.MeshLambertMaterial({
    color: 0x7777ff,
  })
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
  sphere.castShadow = true
  sphere.position.x = 20
  sphere.position.y = 4
  sphere.position.z = 2
  scene.add(sphere)

  // Position and point the camera to the center of the scene
  camera.position.x = -30
  camera.position.y = 12
  camera.position.z = 30
  camera.lookAt(scene.position)

  // Add spotlight for the shadows
  const spotLight = new THREE.SpotLight(0xffffff)
  spotLight.position.set(8, 40, 80)

  spotLight.castShadow = true

  spotLight.shadow.mapSize.width = 1024
  spotLight.shadow.mapSize.height = 1024

  spotLight.shadow.camera.near = 8
  spotLight.shadow.camera.far = 80
  spotLight.shadow.camera.fov = 16

  scene.add(spotLight)

  renderer.render(scene, camera)
}

init()

Am I missing something to get the shadow rendered?

I noticed a few things from your code that may have caused this issue:

  1. The biggest thing is that you didn't enable the shadowMap on your renderer, you can do this like so:
renderer.shadowMap.enabled = true;

This part doesn't seem to be appearing on the documentation of SpotLight which you linked, more information about this can be found on the documentation of SpotLightShadow .

  1. After I tried this on a JS sandbox, I still didn't see the shadow, but it seems like the spotLight was simply too far away, it was set to 80 at it's 'z' position. I made the value slightly smaller (40) and it seemed to do the trick. What helped me figure it out is by using a helper and OrbitControls which makes it a little easier to debug:
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.127/examples/jsm/controls/OrbitControls.js';
...

spotLight.position.set(8, 40, 40); // Third parameter (z) with value of 80 was too far away

controls = new OrbitControls(camera, renderer.domElement);
helper = new THREE.PointLightHelper(pointLight);
scene.add(helper);

Here is a JSFiddle of the fixed version: https://jsfiddle.net/tombugolya/hx61L5vp/17/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM