Three.js DoubleSided material doesn't cast shadow on both sides of planar parametric geometry
shadow, three.js
Solution
Yes, this is a feature.
`WebGLRenderer`, by default, culls front faces when rendering shadows. This is OK, because it is assumed that objects have depth. You can cull back faces, instead, if you want:
renderer.shadowMapCullFace = THREE.CullFaceBack;
... but culling neither is not an option.
The `material.side` property is not taken into consideration when casting shadows.
three.js r.63
Problem
See this jfiddle: http://jsfiddle.net/blwoodley/5Tr4D/1/ I have a blue spot light that shines on a rotating rotating square. This casts a shadow to the underlying ground. Except that it only casts a shadow on one side of the square. I saw this discussion: https://github.com/mrdoob/three.js/issues/3544 which indicates that face culling on planar surfaces is the cause. the recommendation is to give my square some depth, i.e. make it a cube. I can do that with this simple example, but I'm encountering the same problem with a parametric geometry that is a surface. Is there a way to get both sides to cast a shadow without having to give my geometry a depth in doesn't have or need? Here is the main function in the fiddle that replicates the problem with a plane: ``` 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 = 100; camera.lookAt({x: 0,y: 0,z: 0}); scene = new THREE.Scene(); var groundMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, side:THREE.DoubleSide }); plane = new THREE.Mesh(new THREE.PlaneGeometry(2000,2000,10,10), groundMaterial); plane.rotation.x = Math.PI / 2; plane.position.y = -40; plane.receiveShadow = true; scene.add(plane); var light; light = new THREE.SpotLight(0x0000ff); light.position.set(40, 40, 0); light.castShadow = true; light.shadowCameraVisible = true; light.shadowMapWidth = 2048; light.shadowMapHeight = 2048; light.position.set(24, 20, 0); light.lookAt(plane); light.castShadow = true; light.angle = .8; light.intensity = 30; light.distance=0; light.shadowCameraNear = 2; light.shadowCameraFar = 100; light.shadowCameraFov = 100; light.shadowDarkness = 1; light.shadowCameraVisible = true; scene.add(light); var planeGeo = new THREE.PlaneGeometry(20,20,20,20) _planeMesh = new THREE.Mesh(planeGeo, new THREE.MeshLambertMaterial( { color: 0x00ff00, side:THREE.DoubleSide } ) ); _planeMesh.castShadow = true; scene.add( _planeMesh ); // 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); window.addEventListener('resize', onWindowResize, false); ``` }