text: /**
   * @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
  
  		_gl.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.setClearColor( clearColor, 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.Points ) {
  
  			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 );
  
  		}
  
  	}
  
  };
  