Shadows Distance problems in ThreeJS - three.js

I'm currently working with a directionnal ligth for my scene. A small character can move around. All shadows works. But if I start to go a bit further with the avatar, the shadows don't work anymore on it. I think it's may come from the angle of the light but I can't change it. I can draw a square around the shadow/non-shadow area.
Here is my code. Huge numbers were here for me to test things
const dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.color.setHSL( 0.1, 1, 0.95 );
dirLight.position.set( - 1, 1.75, 1 );
dirLight.position.multiplyScalar( 30 );
dirLight.distance = 1200;
dirLight.focus = 1200;
dirLight.angle = Math.PI / 1;
scene.add( dirLight );
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
const d = 100;
dirLight.shadow.camera.left = - d;
dirLight.shadow.camera.right = d;
dirLight.shadow.camera.top = d;
dirLight.shadow.camera.bottom = - d;
dirLight.shadow.camera.far = 35000;
dirLight.shadow.bias = - 0;
const dirLightHelper = new THREE.DirectionalLightHelper( dirLight, 10 );
scene.add( dirLightHelper );
Here is the code of the ground that recive shadows
const groundGeo = new THREE.PlaneBufferGeometry( 10000, 10000 );
const groundMat = new THREE.MeshLambertMaterial( { color: 0xffffff } );
groundMat.color.setHSL( 0.095, 1, 0.75 );
const ground = new THREE.Mesh( groundGeo, groundMat );
ground.position.y = - 33;
ground.rotation.x = - Math.PI / 2;
ground.receiveShadow = true;
scene.add( ground );
I reused a huge part of the code provided by the ThreeJS example with the flamingo https://threejs.org/examples/?q=light#webgl_lights_hemisphere
Here is also a link to an imgur where I just put some picture to see the shadows
https://imgur.com/a/MGrc5cw
Thanks

If your shadows are working within a limited area, then it must be that your character is walking beyond the frustum of the shadow-camera.
To create directional shadows, you create an orthographic camera and assign its dimensions with .left, .right, .top, .bottom, in this case your camera is has 100 in each direction. When your character walks beyond those 200 units, it is outside the shadow camera, and it no longer receives shadows.
You should add a CameraHelper to the light shadow to let you see the space within its view frustum, as seen in the DirectionalLightShadow code sample
const helper = new THREE.CameraHelper( dirLight.shadow.camera );
scene.add( helper );
Maybe you could have the shadow camera follow the character so he'll always be inside of it.

Related

Directional light shadow in mapbox

I have a custom mesh geometry (three js) in mapbocx. I am trying to create a light for casting directional shadows but I always end up woth the light source in the base plane (which results in no casted shadows on my objects above the plane). Does anyone know how I can move the light source so it is above the plane? I added a helper to see the scope box and I would like to move it upwards along the z-vector in the image below.
//Create a WebGLRenderer and turn on shadows in the renderer
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
//Add Ambient light
const amblight = new THREE.AmbientLight(0xffffff, 0.8);
amblight.position.set(8, 10, 5); //default; light shining from top
scene.add(amblight);
//Create a DirectionalLight and turn on shadows for the light
const light = new THREE.DirectionalLight(0xffffff, 0.5);
//light.position.set(8, 10, 5); //default; light shining from top
light.position.y = 2000;
light.position.x = 10;
light.position.z = 5;
light.castShadow = true; // default false
scene.add(light);
//scene.add(light.target);
//Set up shadow properties for the light
light.shadow.mapSize.width = 512;
light.shadow.mapSize.height = 512;
light.shadow.camera.left = -100;
light.shadow.camera.right = 100;
light.shadow.camera.top = 100;
light.shadow.camera.bottom = -100;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 100; //Scope box depth
//Create a plane that receives shadows (but does not cast them)
const planeGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
const planeMaterial = new THREE.MeshPhongMaterial({
color: 0x808080,
opacity: 0.8,
transparent: true,
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
scene.add(plane);
const meshString = result.mesh.meshString;
const mesh = meshToThreejs(rhino, meshString, THREE);
//scene.add(mesh);
//Add shadows
mesh.castShadow = true; //default is false
mesh.receiveShadow = true; //default
scene.add(mesh);
//ENd shadows
//Create a helper for the shadow camera (optional)
const helper = new THREE.CameraHelper(light.shadow.camera);
scene.add(helper);
"move the light source so it is above the plane" - It looks like you already know how to do this, just change the z number.
light.position.z = 20;
// or
light.position.set(0, 0, 20);
// Check note below - If y is up
light.position.y = 20;
// or
light.position.set(0, 20, 0);
Just a note, by default Y is up in Three.js unless you have already handled that in code not shown here. If you need to check this add the axesHelper to your scene. The X axis is red. The Y axis is green. The Z axis is blue. Make sure the camera is moved in the correct direction.
const axesHelper = new THREE.AxesHelper( 100 );
scene.add( axesHelper );
If you are still not getting shadows you could try to add a sphere like in the Three.js docs (https://threejs.org/docs/#api/en/lights/shadows/DirectionalLightShadow)
//Create a sphere that cast shadows (but does not receive them)
const sphereGeometry = new THREE.SphereGeometry( 5, 32, 32 );
const sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xff0000 } );
const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
sphere.castShadow = true; //default is false
sphere.receiveShadow = false; //default
scene.add( sphere );
If that is casting a shadow correctly then perhaps there is an issue with your mesh, or the height of those buildings is so small that the shadows are really small

Shadow on floor doesn't work in three.js v104 but works in r71

If you take a look here which is done with r71 the shadows work:
var shadowlight = new THREE.DirectionalLight( 0xffffff, 1.8 );
shadowlight.position.set( 0, 100, 0 );
shadowlight.castShadow = true;
shadowlight.shadowDarkness = 0.1;
this.scene.add(shadowlight);
this.renderer.setClearColor( 0xf1c140, 1 );
this.renderer.shadowMapEnabled = true;
this.renderer.shadowMapType = THREE.PCFSoftShadowMap;
https://codepen.io/nicolasdnl/pen/VYRXWr
However, if I change the version to 104, and make the necessary changes that it suggests:
.shadowMapEnabled is now .shadowMap.enabled.
.shadowMapType is now .shadowMap.type.
THREE.Light: .shadowDarkness has been removed.
The shadow doesn't work any more: https://codepen.io/bertug48/pen/YMowKx
How to enable the shadows like r71 on v104?
MeshBasicMaterial is not able to receive shadows for over three years now. You have to use a lit material for your ground or add an additional ground mesh with an instance of THREE.ShadowMaterial.
Demo: https://jsfiddle.net/38weog40/
var planeGeometry = new THREE.PlaneGeometry( 200, 200 );
planeGeometry.rotateX( - Math.PI / 2 );
var planeMaterial = new THREE.ShadowMaterial();
planeMaterial.opacity = 0.2;
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.position.y = -200;
plane.receiveShadow = true;
scene.add( plane );
BTW: Here is the reason why MeshBasicMaterial does not receive shadows anymore: https://github.com/mrdoob/three.js/issues/8116#issuecomment-183540170
three.js R104

three.js r75 pointLight shadows in wrong places

I have a jsfiddle containing a fixed Sun and Moons and a moving planet Earth which orbits the Sun.
Here is the code for the two Lights (Ambient and Point) and example objects.
var light2 = new THREE.AmbientLight(0x444444);//... for lighting the Sun and other MeshBasicMaterial meshes.
scene.add(light2);
//... PointLight
// http://threejs.org/docs/#Reference/Lights/PointLight
var light3 = new THREE.PointLight( 0xffffff, 10, 150000,1);
light3.castShadow = true;
light3.shadow.camera.near = 1;
light3.shadow.camera.far = 5000;
light3.shadow.camera.fov = 90;
// light3.shadowCameraVisible = true;
light3.shadow.bias = 0.001;
scene.add( light3 );
// SPHERES
var sphereGeom = new THREE.SphereGeometry( 40, 32, 16 );
var SunMaterial = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
this.Sun01 = new THREE.Mesh( sphereGeom.clone(), SunMaterial );
Sun01.position.set(-500, 0, 220);
scene.add( Sun01 );
//Sun01.castShadow = false;
//Sun01.receiveShadow = false;
light3.position.set( Sun01.position.x, Sun01.position.y , Sun01.position.z);
var moonMaterial = new THREE.MeshPhongMaterial( { color: 0xaa00aa } );
var Moon02 = new THREE.Mesh( sphereGeom.clone(), moonMaterial );
Moon02.scale.set( 0.5,0.5,0.5 );
Moon02.position.set(-200, 0, 220);
scene.add( Moon02 );
Moon02.castShadow = true;
Moon02.receiveShadow = false;
There are two problems.
Firstly distant fixed moons are not illuminated by the PointLight even though they are within range.
Secondly shadows from the distant moons appear on the (Sun-orbitting) Earth even though the Earth is nearer the Sun than those fixed moons.
Note that an inner fixed moon (named Moon02, magenta in color) does get illuminated by the PointLight and it does cast a shadow on the Earth.
Here is the Renderer set-up code:-
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0x000022 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
//... Enable Shadows
renderer.shadowMap.enabled = true;//.shadowMapEnabled = true;
//renderer.shadowMap.type = THREE.BasicShadowMap;//
//renderer.shadowMap.type = THREE.PCFShadowMap
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
My Question = What needs to be done to (a) illuminate the outer moons and (b) ensure the shadows of outer moons do not appear on the (inner, nearer-to-Sun) planet Earth.
Simply put, you're spacing things out too far.
Calculating shadows from a point light is very expensive. In fact, THREE.js only added functionality for it a few months ago. I can't find anything solid in the documentation yet, but it seems likely that there's a hard coded limit on how far out shadows will be calculated from a point light.
The solution is easy: reduce the space between your objects. There's absolutely no reason that objects need to be thousands of units away from each other when a dozen will suffice. I solved both of your problems just by reducing all distances and scales by a factor of 10. I also tweaked the intensity of the PointLight because 10 was pretty harsh haha.
// color, intensity, falloff radius, falloff amount
// if falloff radius is 0 then there is no falloff
var light3 = new THREE.PointLight( 0xffffff, 1, 0, 0);

in three.js, the spotlight is not showing a cone on a plane

I have a very simple example: a spot light pointed at a plane. I am expecting to see a cone of light whose diameter depends on the setting of the spot light angle. I cannot see any cone, the whole plane is illuminated, even for very narrow settings of angle.
Here is my jfiddle: http://jsfiddle.net/blwoodley/WLtL4/1/
I'd love to know the source code that produced this picture from https://github.com/mrdoob/three.js/pull/3291 by West Langley. It obviously is working fine in that case.
So I must be doing something obviously wrong, but I can't figure it out.
Some of the code from the jfiddle, it doesn't get much simpler than this:
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.x = 100;
camera.position.y = 100;
camera.position.z = 200;
camera.lookAt({x: 0,y: 0,z: 0});
scene = new THREE.Scene();
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var floorMaterial = new THREE.MeshLambertMaterial({ color: 0x222222, side:THREE.DoubleSide });
floor = new THREE.Mesh(new THREE.PlaneGeometry(2000,2000,10,10), floorMaterial);
floor.rotation.x = Math.PI / 2;
floor.position.y = -40;
scene.add(floor);
var light;
light = new THREE.SpotLight(0x008888);
light.position.set(0, 40, 0);
light.lookAt(floor);
light.angle = Math.PI/4;
light.intensity = 30;
light.distance=0;
scene.add(light);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
container.appendChild(webglRenderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
This is subtle.
You are using MeshLambertMaterial for the plane. You need to change it to MeshPhongMaterial, so the lighting is rendered properly.
As explained here, for MeshLambertMaterial, the illumination calculation is performed only at each vertex.
For MeshPhongMaterial, the illumination calculation is performed at each texel.
So make these changes
floorGeometry = new THREE.PlaneGeometry( 1000, 1000 ); // no need to tessellate it now
var floorMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } ); // 0x222222 is too dark
light.intensity = 1; // a reasonable value
Updated fiddle: http://jsfiddle.net/WLtL4/5/
three.js r.63
Also try to disable target for testing.
I'm getting really weird behavior from it. Sometimes it makes it not render the light at all, no idea why yet. I'll make a demo of the problem later.

Isometric cube, size does not match up with tilesize 128x128

I've been trying for bigger parts of the night to make a export code that quickly will let me texture cubes and export them to a game i'm making, but for some reason I can't make my cube to cover the entire 128x128 width and height that I want it to have.
I have the following code:
function init(){
if( Detector.webgl ){
renderer = new THREE.WebGLRenderer({
antialias : false, // to get smoother output
preserveDrawingBuffer : true // to allow screenshot
});
renderer.setClearColorHex( 0xBBBBBB, 1 );
// uncomment if webgl is required
//}else{
// Detector.addGetWebGLMessage();
// return true;
}else{
renderer = new THREE.CanvasRenderer();
}
renderer.setSize(128,128);
document.getElementById('container').appendChild(renderer.domElement);
// add Stats.js - https://github.com/mrdoob/stats.js
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
document.body.appendChild( stats.domElement );
var zoom = 1.0;
// create a scene
scene = new THREE.Scene();
// put a camera in the scene
camera = new THREE.OrthographicCamera(WIDTH / -zoom, HEIGHT / zoom, WIDTH / zoom, HEIGHT / -zoom, -2000, 1000);
//camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(0.45,0.45,0.45);
camera.lookAt(scene.position);
//camera.position.set(0, 0, 5);
scene.add(camera);
// create a camera contol
//cameraControls = new THREEx.DragPanControls(camera)
// transparently support window resize
THREEx.WindowResize.bind(renderer, camera);
// allow 'p' to make screenshot
THREEx.Screenshot.bindKey(renderer);
// allow 'f' to go fullscreen where this feature is supported
//if( THREEx.FullScreen.available() ){
// THREEx.FullScreen.bindKey();
// document.getElementById('inlineDoc').innerHTML += "- <i>f</i> for fullscreen";
//}
// here you add your objects
// - you will most likely replace this part by your own
//var geometry = new THREE.TorusGeometry( 1, 0.42 );
var cubeSize = 128;
var geometry = new THREE.CubeGeometry( cubeSize, cubeSize, cubeSize );
var material = new THREE.MeshNormalMaterial();
mesh= new THREE.Mesh( geometry, material );
mesh.rotation.x = 0;
mesh.rotation.y = 0;
mesh.rotation.z = 0;
scene.add( mesh );
}
I've been trying out different "zooms" but it still ends up either too big or too small.
The point with all this is to end up with a code that can generate something like this:
https://dl.dropboxusercontent.com/u/5256694/cube_ex.png
What am I doing wrong?
Kind Regards
Hiam
Instead of thinking about the parameters of THREE.OrthographicCamera as "zoom" levels, you should think of them as coordinates of boundary planes for what the camera is able to see.
Also see the answer to Three.js - Orthographic camera for more details about using orthographic cameras in Three.js

Resources