Bladeren bron

Moved shadow map into separate plugin.

This is still pretty rough, will need to clean it more.
alteredq 13 jaren geleden
bovenliggende
commit
c16ce4b26a
2 gewijzigde bestanden met toevoegingen van 303 en 0 verwijderingen
  1. 59 0
      src/core/Frustum.js
  2. 244 0
      src/extras/plugins/ShadowMapPlugin.js

+ 59 - 0
src/core/Frustum.js

@@ -0,0 +1,59 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.Frustum = function ( ) {
+
+	this.planes = [
+
+		new THREE.Vector4(),
+		new THREE.Vector4(),
+		new THREE.Vector4(),
+		new THREE.Vector4(),
+		new THREE.Vector4(),
+		new THREE.Vector4()
+
+	];
+
+};
+
+THREE.Frustum.prototype.setFromMatrix = function ( m ) {
+
+	var i, plane,
+	planes = this.planes;
+
+	planes[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 );
+	planes[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 );
+	planes[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 );
+	planes[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 );
+	planes[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 );
+	planes[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 );
+
+	for ( i = 0; i < 6; i ++ ) {
+
+		plane = planes[ i ];
+		plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) );
+
+	}
+
+};
+
+THREE.Frustum.prototype.contains = function ( object ) {
+
+	var distance,
+	planes = this.planes,
+	matrix = object.matrixWorld,
+	radius = - object.geometry.boundingSphere.radius * Math.max( object.scale.x, Math.max( object.scale.y, object.scale.z ) );
+
+	for ( var i = 0; i < 6; i ++ ) {
+
+		distance = planes[ i ].x * matrix.n14 + planes[ i ].y * matrix.n24 + planes[ i ].z * matrix.n34 + planes[ i ].w;
+		if ( distance <= radius ) return false;
+
+	}
+
+	return true;
+
+};
+

+ 244 - 0
src/extras/plugins/ShadowMapPlugin.js

@@ -0,0 +1,244 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.ShadowMapPlugin = function ( ) {
+
+	var _gl, _renderer,
+
+	_depthMaterial, _depthMaterialMorph,
+
+	_cameraLight,
+
+	_frustum = new THREE.Frustum(),
+
+	_projScreenMatrix = new THREE.Matrix4();
+
+	this.shadowMatrix = [];
+	this.shadowMap = [];
+
+	this.init = function ( renderer ) {
+
+		_gl = renderer.context;
+		_renderer = renderer;
+
+		var depthShader = THREE.ShaderLib[ "depthRGBA" ];
+		var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
+
+		_depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
+		_depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
+
+		_depthMaterial._shadowPass = true;
+		_depthMaterialMorph._shadowPass = true;
+
+	};
+
+	this.render = function ( scene, camera ) {
+
+		if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return;
+
+		this.update( scene, camera );
+
+	};
+
+	this.update = function ( scene, camera ) {
+
+		var i, il, j, jl,
+
+		shadowMap, shadowMatrix,
+		program, buffer, material,
+		webglObject, object, light,
+
+		shadowIndex = 0,
+
+		lights = scene.lights,
+		fog = null;
+
+		if ( ! _cameraLight ) {
+
+			_cameraLight = new THREE.PerspectiveCamera( _renderer.shadowCameraFov, _renderer.shadowMapWidth / _renderer.shadowMapHeight, _renderer.shadowCameraNear, _renderer.shadowCameraFar );
+
+		}
+
+		for ( i = 0, il = lights.length; i < il; i ++ ) {
+
+			light = lights[ i ];
+
+			if ( light.castShadow && light instanceof THREE.SpotLight ) {
+
+				if ( ! this.shadowMap[ shadowIndex ] ) {
+
+					var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
+
+					this.shadowMap[ shadowIndex ] = new THREE.WebGLRenderTarget( _renderer.shadowMapWidth, _renderer.shadowMapHeight, pars );
+					this.shadowMatrix[ shadowIndex ] = new THREE.Matrix4();
+
+				}
+
+				shadowMap = this.shadowMap[ shadowIndex ];
+				shadowMatrix = this.shadowMatrix[ shadowIndex ];
+
+				_cameraLight.position.copy( light.position );
+				_cameraLight.lookAt( light.target.position );
+
+				if ( _cameraLight.parent == null ) {
+
+					console.warn( "Camera is not on the Scene. Adding it..." );
+					scene.add( _cameraLight );
+
+					if ( _renderer.autoUpdateScene ) scene.updateMatrixWorld();
+
+				}
+
+				_cameraLight.matrixWorldInverse.getInverse( _cameraLight.matrixWorld );
+
+				// 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.multiplySelf( _cameraLight.projectionMatrix );
+				shadowMatrix.multiplySelf( _cameraLight.matrixWorldInverse );
+
+				// render shadow map
+
+				if ( ! _cameraLight._viewMatrixArray ) _cameraLight._viewMatrixArray = new Float32Array( 16 );
+				_cameraLight.matrixWorldInverse.flattenToArray( _cameraLight._viewMatrixArray );
+
+				if ( ! _cameraLight._projectionMatrixArray ) _cameraLight._projectionMatrixArray = new Float32Array( 16 );
+				_cameraLight.projectionMatrix.flattenToArray( _cameraLight._projectionMatrixArray );
+
+				_projScreenMatrix.multiply( _cameraLight.projectionMatrix, _cameraLight.matrixWorldInverse );
+				_frustum.setFromMatrix( _projScreenMatrix );
+
+				_renderer.setRenderTarget( shadowMap );
+
+				// using arbitrary clear color in depth pass
+				// creates variance in shadows
+
+				_gl.clearColor( 1, 0, 1, 1 );
+				//_gl.clearColor( 0, 0, 0, 1 );
+
+				_renderer.clear();
+
+				var clearColor = _renderer.getClearColor(),
+					clearAlpha = _renderer.getClearAlpha();
+
+				_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
+
+				// set matrices & frustum culling
+
+				jl = scene.__webglObjects.length;
+
+				for ( j = 0; j < jl; j ++ ) {
+
+					webglObject = scene.__webglObjects[ j ];
+					object = webglObject.object;
+
+					webglObject.render = false;
+
+					if ( object.visible && object.castShadow ) {
+
+						if ( ! ( object instanceof THREE.Mesh ) || ! ( object.frustumCulled ) || _frustum.contains( object ) ) {
+
+							object.matrixWorld.flattenToArray( object._objectMatrixArray );
+							object._modelViewMatrix.multiplyToArray( _cameraLight.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
+
+							webglObject.render = true;
+
+						}
+
+					}
+
+				}
+
+				// render regular objects
+
+				_renderer.setDepthTest( true );
+				_renderer.setBlending( THREE.NormalBlending ); // maybe blending should be just disabled?
+
+				//_gl.cullFace( _gl.FRONT );
+
+				for ( j = 0; j < jl; j ++ ) {
+
+					webglObject = scene.__webglObjects[ j ];
+
+					if ( webglObject.render ) {
+
+						object = webglObject.object;
+						buffer = webglObject.buffer;
+
+						_renderer.setObjectFaces( object );
+
+						if ( object.customDepthMaterial ) {
+
+							material = object.customDepthMaterial;
+
+						} else if ( object.geometry.morphTargets.length ) {
+
+							material = _depthMaterialMorph;
+
+						} else {
+
+							material = _depthMaterial;
+
+						}
+
+						_renderer.renderBuffer( _cameraLight, lights, fog, material, buffer, object );
+
+					}
+
+				}
+
+				// set matrices and render immediate objects
+
+				jl = scene.__webglObjectsImmediate.length;
+
+				for ( j = 0; j < jl; j ++ ) {
+
+					webglObject = scene.__webglObjectsImmediate[ j ];
+					object = webglObject.object;
+
+					if ( object.visible && object.castShadow ) {
+
+						_currentGeometryGroupHash = -1;
+
+						if( object.matrixAutoUpdate ) {
+
+							object.matrixWorld.flattenToArray( object._objectMatrixArray );
+
+						}
+
+						object._modelViewMatrix.multiplyToArray( _cameraLight.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
+
+						_renderer.setObjectFaces( object );
+
+						program = _renderer.setProgram( _cameraLight, lights, fog, _depthMaterial, object );
+
+						if ( object.immediateRenderCallback ) {
+
+							object.immediateRenderCallback( program, _gl, _frustum );
+
+						} else {
+
+							object.render( function( object ) { _renderer.renderBufferImmediate( object, program, _depthMaterial.shading ); } );
+
+						}
+
+					}
+
+				}
+
+				//_gl.cullFace( _gl.BACK );
+
+				shadowIndex ++;
+
+			}
+
+		}
+
+	};
+
+};