ThreeJS shadow not rendering - three.js

I've looked through a number of other S.O. questions, followed all of the advice, but I'm still clueless as to why I can't get shadows to render on this very basic scene.
http://jsfiddle.net/4Txgp/
[Updated] Code:
var SCREEN_WIDTH = window.innerWidth - 25;
var SCREEN_HEIGHT = window.innerHeight - 25;
var camera, scene;
var canvasRenderer, webglRenderer;
var container, mesh, geometry, plane;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.x = 1200;
camera.position.y = 1000;
camera.lookAt({
x: 0,
y: 0,
z: 0
});
scene = new THREE.Scene();
var groundMaterial = new THREE.MeshLambertMaterial({
color: 0x6C6C6C
});
plane = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000, 100, 100), groundMaterial);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);
// LIGHTS
// scene.add(new THREE.AmbientLight(0x666666));
/*
var light;
light = new THREE.DirectionalLight(0xdfebff, 1.75);
light.position.set(600, 800, 100);
//light.position.multiplyScalar(1.3);
light.castShadow = true;
light.shadowCameraVisible = true;
light.shadowMapWidth = light.shadowMapHeight = 2048;
var d = 50;
light.shadowCameraLeft = -d;
light.shadowCameraRight = d;
light.shadowCameraTop = d;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 500;
light.shadowDarkness = 0.5;
scene.add(light);
*/
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 700, 1000, 100 );
spotLight.castShadow = true;
spotLight.shadowCameraVisible = true;
spotLight.shadowMapWidth = 2048;
spotLight.shadowMapHeight = 2048;
spotLight.shadowCameraNear = 100;
spotLight.shadowCameraFar = 2000;
spotLight.shadowCameraFov = 30;
scene.add( spotLight );
var boxgeometry = new THREE.CubeGeometry(100, 200, 100);
var boxmaterial = new THREE.MeshLambertMaterial({
color: 0x0aeedf
});
var cube = new THREE.Mesh(boxgeometry, boxmaterial);
cube.position.x = 0;
cube.position.y = 100;
cube.position.z = 0;
scene.add(cube);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
//webglRenderer.domElement.style.position = "relative";
webglRenderer.shadowMapEnabled = true;
webglRenderer.shadowMapSoft = true;
container.appendChild(webglRenderer.domElement);
}
function animate() {
var timer = Date.now() * 0.0002;
camera.position.x = Math.cos(timer) * 1000;
camera.position.z = Math.sin(timer) * 1000;
requestAnimationFrame(animate);
render();
}
function render() {
camera.lookAt(scene.position);
webglRenderer.render(scene, camera);
}
I have a scene with a plane, an object (cube), a spotlight (copied directly from http://threejs.org/docs/58/#Reference/Lights/SpotLight for testing purposes) , and a camera. It renders fine, except that the cube is not casting a shadow on the "ground" (plane), and the shading looks like everything has been done in a basic material. I'm using a combo of Phongs and Lamberts.
My directional light is set to castShadow = true;, and my plane is set with receiveShadow = true, along with shadow map settings. The renderer itself has shadowMapEnabled = true.
I've tried various solutions, I remember with previous versions of ThreeJS there would be external library calls depending on what you wanted to do, but I've also seen other examples on JSFiddle just calling ThreeJS by itself, as well as examples from the official site, that work fine.
Any hints/info/constructive remarks about overlooking something simple and small?

You need to set
cube.castShadow = true;
and make sure the shadow camera far plane reaches the cube.
three.js r.144

Related

Selfshadow plane affected by a displacement map not working

Working on some kind of fictional treasure map. I'm cutting a large displacement map intosmaller tiles as I don't yet how wide the final terrain is going to be -- right now it's 5*5, but it could be wider in the future
For some reasons, I am having issues projecting shadows on the displaced planes.
I don't know where the problem is coming from. Maybe it's the way I push meshes into an array through a function, i'm afraid i'm not doing this the right way.
I'd like to achieve the result using a directional light
Here is a c4d draft of what i'm trying to achieve
and here is what i'm able to do in the browser (didnt manage to tile them properly yet :^)
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
var material = [];
var texture = [];
var tile = [];
var planeRes = 128;
var planesize = 1;
var dim = 5;
var size = dim * dim;
var DispScale = 2;
var geometry = new THREE.PlaneBufferGeometry(planesize,planesize,planeRes, planeRes);
function tileGenerator(inc) {
if (inc < 10) {
texture[inc] = new THREE.TextureLoader().load('cut25lowres/image_part_00' + inc + '.jpg');
} else {
texture[inc] = new THREE.TextureLoader().load('cut25lowres/image_part_0' + inc + '.jpg');
}
material[inc] = new THREE.MeshPhongMaterial({
color: 0xffffff,
displacementMap: texture[inc],
side: THREE.DoubleSide,
receiveShadow : true,
castShadow : true
});
tile[inc] = new THREE.Mesh(geometry, material[inc]);
}
for (var i = 1; i < size + 1; i++) {
tileGenerator(i);
}
for (var i = 1; i < size + 1; i++) {
tile[i].position.set(-planesize * (i % dim)+1, 0, -planesize * Math.ceil(i / dim)+1 );
tile[i].rotation.x = Math.PI / 2 + Math.PI;
tile[i].rotation.z = Math.PI / 2;
scene.add(tile[i]);
}
var dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.castShadow = true;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 6;
dirLight.shadow.mapSize.set( 1024, 1024 );
var targetObject = new THREE.Object3D();
targetObject.position.x = -10;
targetObject.position.z = -10;
dirLight.position.y = 3;
scene.add(targetObject);
dirLight.target = targetObject;
scene.add( dirLight );
Edit : Here is a cleaner version without the array as it's not part of the problem
jsfiddle.net/clemtre/3y9tqc6j/34
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var scene = new THREE.Scene();
var heightmap = new THREE.TextureLoader().load('https://i.imgur.com/MVYhfd7.jpeg');
var geometry = new THREE.PlaneGeometry(20, 20, 100, 100);
var material = new THREE.MeshPhongMaterial({
color: 0xffffff,
displacementMap: heightmap,
displacementScale: 10
});
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 1, 1).normalize();
light.castShadow = true;
scene.add(light);
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI/2;
scene.add(plane);
camera.position.z = -20;
camera.position.y = 5;
controls.update();
var animate = function() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
};
animate();
Many thanks!

overlapping semitransparent objects are not rendered as expected

I have two overlapping semitransparent boxes and I'd expect to see both of them independent of the viewing angle. The first image shows a rendering from aside and the small box is visible within the bigger box. The second image shows the same scene but form another viewing angle. As you can see, the smaller box is visible but the part which is with the bigger box is invisible. What am I missing?
var camera, scene, renderer;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 50);
camera.position.set(2, 2, 2);
camera.lookAt(new THREE.Vector3(0.0, 0.0, 0.0));
// Create scene.
scene = new THREE.Scene();
// Create material
var material = new THREE.MeshStandardMaterial();
material.transparent = true;
material.opacity = 0.5;
// Create cube and add to scene.
var geometry1 = new THREE.BoxGeometry(1, 1, 1);
var mesh1 = new THREE.Mesh(geometry1, material);
mesh1.position.set(0, 0, 0);
//mesh1.castShadow = true;
scene.add(mesh1);
// Create cube and add to scene.
var geometry2 = new THREE.BoxGeometry(0.5, 0.5, 0.5);
var mesh2 = new THREE.Mesh(geometry2, material);
mesh2.position.set(0.0, 0, 0.5);
//mesh2.castShadow = true;
scene.add(mesh2);
var spotLight = new THREE.SpotLight(0xffffff, 0.32);
spotLight.position.set(0, 5, 0);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.shadow.camera.near = 0.1;
spotLight.shadow.camera.far = 20;
scene.add(spotLight);
let hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 0.8);
scene.add(hemiLight);
// Ground plane
var groundGeo = new THREE.PlaneBufferGeometry(50, 50);
var groundMat = new THREE.MeshStandardMaterial({color: 0xffffff});
var ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -0.5;
ground.receiveShadow = true;
scene.add(ground);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
let controls = new THREE.OrbitControls(camera);
controls.enableZoom = true;
controls.enablePan = false;
controls.maxDistance = 20.0;
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI / 2;
controls.target.set(0, 0, 0);
controls.update();
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Transparent objects in WebGL are sometimes rather problematic. It's all about the rendering order: If the small cube is rendered after the large cube, how should the rendering behave? This question has some information you might find useful.
In your particular case (though not necessarily always), one solution could be to disable renderer object sorting:
renderer.sortObjects = false;
and(!) make sure you add your objects in the correct order, i.e. the small cube first and the large one second. Here is an updated version of your snippet:
var camera, scene, renderer;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.sortObjects = false;
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 50);
camera.position.set(2, 2, 2);
camera.lookAt(new THREE.Vector3(0.0, 0.0, 0.0));
// Create scene.
scene = new THREE.Scene();
// Create material
var material = new THREE.MeshStandardMaterial();
material.transparent = true;
material.opacity = 0.5;
// Create cube and add to scene.
var geometry2 = new THREE.BoxGeometry(0.5, 0.5, 0.5);
var mesh2 = new THREE.Mesh(geometry2, material);
mesh2.position.set(0.0, 0, 0.5);
//mesh2.castShadow = true;
scene.add(mesh2);
// Create cube and add to scene.
var geometry1 = new THREE.BoxGeometry(1, 1, 1);
var mesh1 = new THREE.Mesh(geometry1, material);
mesh1.position.set(0, 0, 0);
//mesh1.castShadow = true;
scene.add(mesh1);
var spotLight = new THREE.SpotLight(0xffffff, 0.32);
spotLight.position.set(0, 5, 0);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.shadow.camera.near = 0.1;
spotLight.shadow.camera.far = 20;
scene.add(spotLight);
let hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 0.8);
scene.add(hemiLight);
// Ground plane
var groundGeo = new THREE.PlaneBufferGeometry(50, 50);
var groundMat = new THREE.MeshStandardMaterial({color: 0xffffff});
var ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -0.5;
ground.receiveShadow = true;
scene.add(ground);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
let controls = new THREE.OrbitControls(camera);
controls.enableZoom = true;
controls.enablePan = false;
controls.maxDistance = 20.0;
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI / 2;
controls.target.set(0, 0, 0);
controls.update();
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

ThreeJS shadows do not function as expected

I am having a simple three.js scene and have added some spheres. I want to achieve a simple lighting and shadowing effect but I get strange dark shapes on my spheres.
I guess something is wrong with my settings : jsFiddle
this is the core of this simple piece of code :
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.physicallyBasedShading = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowCameraNear = 0.1;
renderer.shadowCameraFar = 1000;
renderer.shadowCameraFov = 100;
renderer.shadowMapBias = 0.0039;
renderer.shadowMapDarkness = 0.5;
renderer.shadowMapWidth = 1024;
renderer.shadowMapHeight = 1024;
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 150, 50, 150 );
// controls
controls = new THREE.OrbitControls( camera );
// lights
var light = new THREE.SpotLight( 0xF5F6CE, 1 );
light.position.set( 300, 300, 60 );
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.8;
light.shadowCameraVisible = true;
scene.add( light );
// axes
scene.add( new THREE.AxisHelper( 200 ) );
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
for (var z = 0; z < 3; z++) {
var sphere = new THREE.Mesh(new THREE.SphereGeometry(10,32, 32), new THREE.MeshPhongMaterial({ color: "#FFFF00", side: THREE.DoubleSide, })); // with MeshLambertMaterial still not working
sphere.position.set(20*x, 20*y, 20*z);
castShadow = true;
sphere.castShadow = true;
sphere.receiveShadow = true ;
scene.add(sphere);
}
}
}
The blackish artifacts are coming from the two-sidedness of the spheres combined with shadow mapping.
Remove side: THREE.DoubleSide from their material definition and you should be good.
http://jsfiddle.net/Us54P/331/
You can also get different results with tweaking the shading parameters, for example, you can add renderer.shadowMapType = THREE.PCFSoftShadowMap;. See here: http://jsfiddle.net/Us54P/332/
Could also be a bug (or a debugging feature), because it disappears when you disable light.shadowCameraVisible = true;: http://jsfiddle.net/Us54P/334/

Is it possible to rotate shadow map in Three.js?

I have plane ground rectangle rotated by 90 degrees. And I have DirectionalLight which cast shadow on this plane. Look at this simple code example:
var Three = new function () {
var scene = new THREE.Scene()
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000)
camera.position.set(-380, 252, 420);
camera.rotation.order = 'YXZ';
camera.rotation.y = -Math.PI / 4;
camera.rotation.x = Math.atan(-1 / Math.sqrt(2));
var renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true
var light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(150, 100, 100)
light.castShadow = true
light.shadowDarkness = 0.3
light.shadowCameraVisible = true
light.shadowCameraRight = 50;
light.shadowCameraLeft = -50;
light.shadowCameraTop = 50;
light.shadowCameraBottom = -50;
scene.add(light);
var ground = new THREE.Mesh(
new THREE.PlaneBufferGeometry(436, 624),
new THREE.MeshLambertMaterial({color: '#808080'})
);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true
scene.add(ground);
this.init = function () {
$('body').append(renderer.domElement);
Three.render();
}
this.render = function () {
requestAnimationFrame(Three.render);
renderer.render(scene, camera);
};
}
$(document).ready(function () {
Three.init();
});
Ground mesh is rotated by 90 degree. Can I rotate light shadow map? I would like to match it to the rotation of the ground?
Fiddle: http://jsfiddle.net/95t964o0/33/

ThreeJs strange shadows

I have simple scene with one cube and one directional light with shadows enabled.
Cube cast and receive shadow. But shadows on right side of the cube ara strange. In middle of shadowcamera shadow gets darker. Why?
Here is example:
code below:
var SCREEN_WIDTH = window.innerWidth - 100;
var SCREEN_HEIGHT = window.innerHeight - 100;
var camera, scene;
var canvasRenderer, webglRenderer;
var container, mesh, geometry, plane;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.set(500, 500, -1000);
camera.lookAt({ x: 0, y: 0, z: 0 });
scene = new THREE.Scene();
// LIGHTS
scene.add(new THREE.AmbientLight(0x666666));
var light;
light = new THREE.DirectionalLight(0xdfebff, 1.75);
light.position.set(100, 50, 20);
light.position.multiplyScalar(1.3);
light.castShadow = true;
light.shadowCameraVisible = true;
light.shadowMapWidth = light.shadowMapHeight = 2048;
var d = 200;
light.shadowCameraLeft = -d;
light.shadowCameraRight = d;
light.shadowCameraTop = d;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 500;
light.shadowDarkness = 0.5;
//light.shadowBias = 0.001;
scene.add(light);
var box = new THREE.Mesh(new THREE.CubeGeometry(1000, 500, 100), new THREE.MeshLambertMaterial({ color: 0xFF0000 }));
box.castShadow = true;
box.receiveShadow = true;
scene.add(box);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
webglRenderer.shadowMapEnabled = true;
//webglRenderer.shadowMapSoft = true;
webglRenderer.shadowMapType = THREE.PCFSoftShadowMap;
//webglRenderer.sortObjects = false;
//webglRenderer.setFaceCulling(THREE.CullFaceNone);
//webglRenderer.autoClear = false;
//webglRenderer.shadowMapCullFace = THREE.CullFaceNone;
container.appendChild(webglRenderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
webglRenderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
var timer = Date.now() * 0.0002;
//camera.position.x = Math.cos(timer) * 1000;
//camera.position.z = Math.sin(timer) * 1000;
requestAnimationFrame(animate);
render();
}
function render() {
camera.lookAt(scene.position);
webglRenderer.render(scene, camera);
}
UPDATE:
changed fiddler code, now light is outside cube, and light is rotating around cube.
Now my problem is even more visible. When light direction vector is almost perpendicular to cube normal on shadow there is sharp line in the middle of light shadowCamera.
new fiddler code: http://jsfiddle.net/gbwojcg6/2/
The way you have your scene set up currently, the light source is inside the object.
So there are several things you can do.
move the light outside the object
reduce the very big value of camera far
use a negative shadow bias light.shadowBias = -0.01;
updated fiddle
It seams to be an issue with three.js prior r67, new version fix my problem (darker shadow in the middle of shadowcamera)

Resources