SpotLight in Three.js. Wrong lightened area and shadows - three.js

I'm newbie at Three.js and OpenGL at all. So I can't understand lighting. I add SpotLight to my scene as follow:
var light = new THREE.SpotLight(0xffff00);
light.position.set( 1.5, 5.5, 0.9 );
light.shadowCameraVisible = true;
light.shadowDarkness = 1;
light.intensity = 2;
light.castShadow = true;
light.shadowCameraNear = 0.1;
light.shadowCameraFar = 50;
light.target = new THREE.Object3D();
light.target.position.set(5.5, 5.5, 0);
scene.add(light);
I turn on shadow map debug at WebGLRenderer and see following picture on my screen:
If I fly behind crates I see shadows only on 'red' zone of light source frustum. In 'yellow' zone there are no shadows and it looks very bad (look at next screenshot). '.castShadow' and '.receiveShadow' properties set to 'true'.
Help me understand what I'm doing wrong. Maybe I don't understand SpotLight source or shadow mechanism. I will be grateful for any advice. Thanks.

Related

Trouble using toonshader in three js on objects that cast a shadow

I'm creating a sphere that casts and receives shadows with MeshToonMaterial but this is giving me an irregular shadow at the darkest section.
Sphere with irregular shadow:
Closer look at the sphere:
The light is:
light = new THREE.PointLight(0xffffff, 0.8, 18);
light.position.set(-3,6,-3);
light.castShadow = true;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 25;
light.shadowBias = 0.0015;
scene.add(light);
The sphere is:
mesh = new THREE.Mesh
(
new THREE.SphereBufferGeometry( 1, 32, 16 ),
new THREE.MeshToonMaterial({color:0xff4444})
);
mesh.position.y += 1;
mesh.receiveShadow = true;
mesh.castShadow = true;
mesh.position.set(-2.5, 3/2, 2.5);
scene.add(mesh);
The renderer:
renderer = new THREE.WebGLRenderer();
renderer.setSize(800,400);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
I've tried with other models and shadow map types with similar results.
If I set:
mesh.castShadow = false;
Then what I get is:
That's pretty much the style I'm looking for, but I'm also needing it to casts shadows.
I would like to avoid using an extra sphere for casting the shadow.
How can I achieve this?
Disabling receiving shadows on the sphere mesh will prevent it from being rendered with the cast shadows, but it will still cast a shadow on the plane.
mesh.receiveShadow = false
However, that means that the sphere won't have any shadows cast on it from other objects, either.
Other than that, it seems like an issue with the way the toon shader handles cast shadows.

Adding three.js compound object into A-Frame causing unexpected flickering of child objects

I am adding augmented reality experience to my web app which originally created using threejs
I have a compound object(which is an Object3D instance with multiple meshes). but placing it into A-Frame giving unexpected flickering s shown in below
Pic of the original web app with threejs is given below
I have the three.js code like below
scene = new THREE.Scene();
mainObj = new THREE.Object3D();
scene.add(mainObj);
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
renderer.sortObjects = false
container = document.getElementById("canvas-container");
width = $(container).innerWidth();
height = $(container).innerHeight();
renderer.setSize(width, height);
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(75, width / height, 10, 2000);
camera.position.set(0, 67, 100);
controls = new THREE.OrbitControls( camera , container);
controls.dampingFactor = 0.2;
controls.enableDamping = true;
controls.target.set( 0, 10, -20 );
controls.maxPolarAngle = (Math.PI/2) - 0.05;
controls.maxDistance = 800;
controls.minDistance = 2;
controls.target.set(0, buildingConfig.h/2, buildingConfig.l/-2)
controls.enableKeys = false;
controls.update();
scene.add(camera);
light = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.7);
light.position.set(1, 10000, 1);
light.castShadow = true
scene.add( light );
renderer.render(scene, camera);
// logic to add child meshes to mainObj
Which I changed to include in A-Frame.
<script type="text/javascript">
initmodels();
AFRAME.registerComponent('e1', {
init:function(){
this.el.setObject3D('building', mainObj);
}
});
</script>
<a-scene e1>
</a-scene>
I guess this issue is related to the scene or renderer. Can anyone help me with a proper scene or renderer setup in A-Frame
This looks like z-fighting. Is the three.js version running on a different system than your aframe version?
Different platforms have different z-buffer precision. It may require you to make changes to the geometry to compensate for the limited resolution.
Also, I don't know about AR.s, but the THREE renderer has a "logarithmicDepthBuffer" option that can increase the resolution of your z-buffer at near scales, but may have some side effects.
I had exactly the same issue. After a few trial and errors, I was able to fix it
Added recent version of aframe
Add <a-scene embedded artoolkit='sourceType: webcam;' renderer='logarithmicDepthBuffer: true;'>
Add <a-marker-camera camera="far:100000; near:0.01" >
Main reason was the light, Remove all lights and add only the hemisphere light into the scene and improvise upon other lights later on.
Hope this would resolve your issue too.

ThreeJS : objects don't cast shadow on others

I'm using three v0.85.2.
By default, all my objects are configured to cast and receive shadows :
const mesh = new Mesh(geometry, material)
mesh.castShadow = meshConfig.castShadow
mesh.receiveShadow = meshConfig.receiveShadow
shadowMap of the renderer is enabled.
Self shadows seem to be correctly rendered (green squares in the image below).
But shadows casted to other objects are missing (red squares).
The problem seems to occur with all my meshes.
I don't find a way to make them appear.
DirectionalLightShadow, there you can read how to work with shadows when you use THREE.DirectionalLight() in your scene.
Also you can play around with .left, .top, .right and .bottom properties of the shadow camera of your light source.
var light = new THREE.DirectionalLight(0xffffff,1);
light.position.set(50, 500, 22);
light.target.position.set(300, 400, 200);
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 5000;
light.shadow.camera.left = -500;
light.shadow.camera.bottom = -500;
light.shadow.camera.right = 500;
light.shadow.camera.top = 500;
light.castShadow = true;
scene.add(light);
three.js r85
jsfiddle example

Three.js light object3d and tween

I'm struggling in my attempt to light an object, make it tween towards camera and have the light follow the tween.
Basically I want to darken the background and tween a 3D object towards the camera, and set a directional light pointing at it so it has nice, smooth, uniform lighting.
Directional lights i add to the object don't show up, latest I've tried is:
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.position.set( 0, 0, -100);
directionalLight.lookAt(object);
directionalLight.shadowCameraVisible = true;
object.add( directionalLight );
I've also tried PointLights near the camera, these kind of work but it's a very sharp light, not smooth and doesn't seem to light all the objects the same.
Using something like this
hslight1 = new THREE.PointLight( 0xffffff,0.9,100 );
hslight1.position.set(0,10,0);
scene.add( hslight1 );
hslight2 = new THREE.PointLight( 0xffffff,0.9,100 );
hslight2.position.set(0,0,0);
scene.add( hslight2 );
Anyone get any ideas on any way to uniformly light an object3D that is tweening towards the camera using
var dist = (size/screen) * (object.scale.x * 2);
var pLocal = new THREE.Vector3( 0, 0, -dist );
var target = pLocal.applyMatrix4( camera.matrixWorld );
var tweenMove = new TWEEN.Tween(object.position).to(target, 1500).easing(TWEEN.Easing.Cubic.InOut);
tweenMove.onUpdate(function(){object.lookAt(camera.position);});
Fixed this by adding the light to the camera
camera.add( light );

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.

Resources