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

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.

Related

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 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);

how to apply shadow on full object in threejs

i want to apply shadow on full object using threejs, if i rotate the object the shadow must be with the object, meaning that i want to apply the shadow for the hole object, i tried with Spotlight, but no luck i doesn't get any changes on my object, so here below is my code
light = new THREE.SpotLight( 0xffffff );
light.position.set( 200, 200, -200 );
light.castShadow = true;
light.shadowMapWidth = 1024; // power of 2
light.shadowMapHeight = 1024;
light.shadowCameraNear = 200; // keep near and far planes as tight as possible
light.shadowCameraFar = 500; // shadows not cast past the far plane
light.shadowCameraFov = 20;
light.shadowBias = -0.00022; // a parameter you can tweak if there are artifacts
light.shadowDarkness = 0.5;
light.shadowCameraVisible = true;
scene.add( light );
Did you tried to set object.receiveShadow = true; on the object on which shadows should be rendered ?

SpotLight in Three.js. Wrong lightened area and shadows

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.

Can a plane cast shadow on another plane in Three.js?

I have a plane with a transparent PNG (a world map).
Can I cast shadows from one plane onto another plane?
I am having no success with this code:
plane = new THREE.Mesh(new THREE.PlaneGeometry(200,200), new THREE.MeshLambertMaterial({color: 0xcccccc}));
var mapTexture = new THREE.ImageUtils.loadTexture("img/map_transp2.png");
mapTexture.needsUpdate = true;
var mapMaterial = new THREE.MeshBasicMaterial({
color:0xaaaaaa,
transparent:true,
map:mapTexture,
side:THREE.DoubleSide
});
mapPlane = new THREE.Mesh(new THREE.PlaneGeometry(800/5,370/5), mapMaterial);
plane.receiveShadow = true;
mapPlane.castShadow = true;
Transparent parts of the mesh should be handled differently if they're written in texture.
Take a look at this example: http://threejs.org/examples/webgl_animation_cloth.html
Your two planes are on the same z value. Give them some distance with:
mapPlane.position.z = 100;
// You need also to set this:
renderer.shadowMapEnabled = true;
// and also you need to add a light and enable its shadow, for example,
sLight = new THREE.SpotLight(0xFFF4E5,1);
sLight.position.set( 250, 250, 250);
sLight.castShadow = true;
sLight.shadowMapWidth = 1024;
sLight.shadowMapHeight = 1024;
sLight.shadowCameraNear = 300;
sLight.shadowCameraFar = 600;
sLight.shadowCameraFov = 45;
scene.add(sLight);
I have had a similar problem.
I don't know why this happens, but I solved it changing the planeGeometry to a cubeGeometry (in the plane casting the shadow)
See https://github.com/mrdoob/three.js/issues/9315
Set
renderer.shadowMap.renderReverseSided = false
or/and
renderer.shadowMap.renderSingleSided = false
can solve the problem.
When disabled, an appropriate shadow.bias must be set on the light source for surfaces that can both cast and receive shadows at the same time to render correctly:
let dl = new THREE.DirectionalLight()
dl.shadow.bias = -0.0001
three.js r.85

Resources