/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var _gl = _renderer.context, _state = _renderer.state, _frustum = new THREE.Frustum(), _projScreenMatrix = new THREE.Matrix4(), _min = new THREE.Vector3(), _max = new THREE.Vector3(), _matrixPosition = new THREE.Vector3(), _renderList = []; // init var depthShader = THREE.ShaderLib[ "depthRGBA" ]; var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); var _depthMaterial = new THREE.ShaderMaterial( { uniforms: depthUniforms, vertexShader: depthShader.vertexShader, fragmentShader: depthShader.fragmentShader } ); var _depthMaterialMorph = new THREE.ShaderMaterial( { uniforms: depthUniforms, vertexShader: depthShader.vertexShader, fragmentShader: depthShader.fragmentShader, morphTargets: true } ); var _depthMaterialSkin = new THREE.ShaderMaterial( { uniforms: depthUniforms, vertexShader: depthShader.vertexShader, fragmentShader: depthShader.fragmentShader, skinning: true } ); var _depthMaterialMorphSkin = new THREE.ShaderMaterial( { uniforms: depthUniforms, vertexShader: depthShader.vertexShader, fragmentShader: depthShader.fragmentShader, morphTargets: true, skinning: true } ); _depthMaterial._shadowPass = true; _depthMaterialMorph._shadowPass = true; _depthMaterialSkin._shadowPass = true; _depthMaterialMorphSkin._shadowPass = true; // var scope = this; this.enabled = false; this.autoUpdate = true; this.needsUpdate = false; this.type = THREE.PCFShadowMap; this.cullFace = THREE.CullFaceFront; this.render = function ( scene, camera ) { if ( scope.enabled === false ) return; if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; // set GL state for depth map _renderer.clearColor( 1, 1, 1, 1 ); _state.disable( _gl.BLEND ); _state.enable( _gl.CULL_FACE ); _gl.frontFace( _gl.CCW ); if ( scope.cullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.FRONT ); } else { _gl.cullFace( _gl.BACK ); } _state.setDepthTest( true ); // render depth map for ( var i = 0, il = _lights.length; i < il; i ++ ) { var light = _lights[ i ]; if ( ! light.castShadow ) continue; if ( ! light.shadowMap ) { var shadowFilter = THREE.LinearFilter; if ( scope.type === THREE.PCFSoftShadowMap ) { shadowFilter = THREE.NearestFilter; } var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); light.shadowMatrix = new THREE.Matrix4(); } if ( ! light.shadowCamera ) { if ( light instanceof THREE.SpotLight ) { light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); } else if ( light instanceof THREE.DirectionalLight ) { light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); } else { console.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); continue; } scene.add( light.shadowCamera ); if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); } if ( light.shadowCameraVisible && ! light.cameraHelper ) { light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); scene.add( light.cameraHelper ); } var shadowMap = light.shadowMap; var shadowMatrix = light.shadowMatrix; var shadowCamera = light.shadowCamera; // shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); shadowCamera.lookAt( _matrixPosition ); shadowCamera.updateMatrixWorld(); shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); // if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; if ( light.shadowCameraVisible ) light.cameraHelper.update(); // compute shadow matrix shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 ); shadowMatrix.multiply( shadowCamera.projectionMatrix ); shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); // update camera matrices and frustum _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); // render shadow map _renderer.setRenderTarget( shadowMap ); _renderer.clear(); // set object matrices & frustum culling _renderList.length = 0; projectObject( scene, shadowCamera ); // render regular objects for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { var object = _renderList[ j ]; var geometry = _objects.update( object ); var material = object.material; if ( material instanceof THREE.MeshFaceMaterial ) { var groups = geometry.groups; var materials = material.materials; for ( var k = 0, kl = groups.length; k < kl; k ++ ) { var group = groups[ k ]; var groupMaterial = materials[ group.materialIndex ]; if ( groupMaterial.visible === true ) { _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, getDepthMaterial( object, groupMaterial ), object, group ); } } } else { _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, getDepthMaterial( object, material ), object ); } } } // restore GL state var clearColor = _renderer.getClearColor(), clearAlpha = _renderer.getClearAlpha(); _renderer.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); _state.enable( _gl.BLEND ); if ( scope.cullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.BACK ); } _renderer.resetGLState(); scope.needsUpdate = false; }; function getDepthMaterial( object, material ) { var geometry = object.geometry; var useMorphing = geometry.morphTargets !== undefined && geometry.morphTargets.length > 0 && material.morphTargets; var useSkinning = object instanceof THREE.SkinnedMesh && material.skinning; var depthMaterial; if ( object.customDepthMaterial ) { depthMaterial = object.customDepthMaterial; } else if ( useSkinning ) { depthMaterial = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; } else if ( useMorphing ) { depthMaterial = _depthMaterialMorph; } else { depthMaterial = _depthMaterial; } depthMaterial.visible = material.visible; depthMaterial.wireframe = material.wireframe; depthMaterial.wireframeLinewidth = material.wireframeLinewidth; return depthMaterial; } function projectObject( object, camera ) { if ( object.visible === false ) return; if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { var material = object.material; if ( material.visible === true ) { object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); _renderList.push( object ); } } } var children = object.children; for ( var i = 0, l = children.length; i < l; i ++ ) { projectObject( children[ i ], camera ); } } };