1
votes

I'm working on building up quite a complex static render in the browser with three.js and have gotten stuck early in the process trying to produce correct shadows with a single THREE.DirectionalLight representing the sun in my scene. All the geometry (contained in another .js file) has shadows enabled. The green sphere is for debugging purposes and is translated (50,0,50) to the center of the plane to represent the target for the camera and location of DirectionalLight.target. The directional light position and main camera position did set correctly.

My theory on why the shadows aren't working is because the orthogonal camera representing the shadow camera is pointing off in the wrong direction. I failed yesterday to figure out and solve the behaviour of the directional light helper (white line to the origin) and shadow camera helper (right).

I'm assuming the correct orientation, and the orientation I'm aiming for, has the directional light helper and shadow camera helper aligned to the center of the plane. After so much research yesterday, my shadow camera doesn't seem to automatically pick up the light position / light target vector. Why are they still anchored to the origin?

Does anyone have any suggestions about how to fix the DirectionalLight.target in my scene? Why are the DirectionalLightHelper and CameraHelper inconsistent?

// Set up
const canvus = document.getElementById('canvus');
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;

//Camera
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 500);
camera.position.set(200, 100, 100);
camera.lookAt(50, 0, 50);

// Lighting
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(100, 200, 200);
directionalLight.target.position.set(50, 0, 50);
directionalLight.castShadow = true;
directionalLight.shadow.bias = 0.0001;
directionalLight.shadow.mapSize.width = 1024; // default
directionalLight.shadow.mapSize.height = 1024; // default

const view_n = 50;
directionalLight.shadow.camera = new THREE.OrthographicCamera(
    -view_n,
    view_n,
    view_n,
    -view_n,
    60,
    150
);

scene.add(directionalLight, directionalLight.target);

//helpers
const lighthelper = new THREE.DirectionalLightHelper(directionalLight, 10);
const camerahelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(lighthelper);
scene.add(camerahelper);

//Main Render
createBasicGeometry(scene); // from geometry.js
createGroundPlane(scene); // from geometry.js
renderer.render(scene, camera);

Update 2020-1-5

I had initially tried setting the camera and also found examples of people setting a new ortho shadow camera directly. As I'm motivated to overcome the issue, and for thoroughness, I updated my code to reflect the suggestion and unfortunately the problem persists. I've re-checked that all mesh geometry is set to both object.receiveShadow = true and object.castShadow = true with the MeshPhongMaterial. It's completely confounding why directionalLight.target.position.set(50, 0, 50) is not updating as expected. What is the cause of this behaviour?

// Updated Lighting
const view_n = 50;
directionalLight.castShadow = true;
directionalLight.shadow.bias = 0.0001;

directionalLight.shadow.camera.right = view_n;
directionalLight.shadow.camera.left = -view_n;
directionalLight.shadow.camera.top = view_n;
directionalLight.shadow.camera.bottom = -view_n;
directionalLight.shadow.camera.near = 60;
directionalLight.shadow.camera.far = 150;

directionalLight.shadow.mapSize.width = 1024; // default
directionalLight.shadow.mapSize.height = 1024; // default

scene.add(directionalLight, directionalLight.target);

When I dump the directionalLight I get the target position I expected, though not aligned correctly in the scene. While the camera position gives another strange results.

console.log(directionalLight.target.position);
//Vector3 {x: 50, y: 0, z: 50, isVector3: true}
console.log(directionalLight.shadow.camera.position);
2

2 Answers

1
votes

directionalLight.shadow.camera = new THREE.OrthographicCamera( -view_n, view_n, view_n, -view_n, 60, 150 );

Please do not overwrite the camera reference of LightShadow.camera. Configure the directional light like so:

dirLight.castShadow = true;
dirLight.shadow.camera.top = view_n;
dirLight.shadow.camera.bottom = - view_n;
dirLight.shadow.camera.left = - view_n;
dirLight.shadow.camera.right = view_n;
dirLight.shadow.camera.near = 60;
dirLight.shadow.camera.far = 150;

Besides shadow casting only works if all shadow casting objects (like your boxes) have castShadow set to true. All shadow receiving objects (like your floor) must set receiveShadow to true.

0
votes

Perhaps because I'm doing this render statically without an animation loop this problem cropped up but was solved by inserting updateMatrixWorld to the directional light target. (Unforuately I wasn't able to update the shadow's camerahelper but at least the shadows are now working as expected.)

directionalLight.target.updateMatrixWorld();
scene.add(directionalLight);
scene.add(directionalLight.target);