WebGLShadowMap.js 9.7 KB
Newer Older
A
alteredq 已提交
1 2
/**
 * @author alteredq / http://alteredqualia.com/
M
Mr.doob 已提交
3
 * @author mrdoob / http://mrdoob.com/
A
alteredq 已提交
4 5
 */

M
Mr.doob 已提交
6
THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) {
A
alteredq 已提交
7

8
	var _gl = _renderer.context,
M
Mr.doob 已提交
9
	_state = _renderer.state,
A
alteredq 已提交
10
	_frustum = new THREE.Frustum(),
A
alteredq 已提交
11
	_projScreenMatrix = new THREE.Matrix4(),
A
alteredq 已提交
12

13
	_lookTarget = new THREE.Vector3(),
14
	_lightPositionWorld = new THREE.Vector3(),
M
Mr.doob 已提交
15

T
tschw 已提交
16
	_renderList = [],
17

T
tschw 已提交
18 19 20
	_MorphingFlag = 1,
	_SkinningFlag = 2,

21
	_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
T
tschw 已提交
22 23 24

	_depthMaterials = new Array( _NumberOfMaterialVariants ),
	_distanceMaterials = new Array( _NumberOfMaterialVariants );
25

M
Mr.doob 已提交
26 27 28 29
	var cubeDirections = [
		new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( - 1, 0, 0 ), new THREE.Vector3( 0, 0, 1 ),
		new THREE.Vector3( 0, 0, - 1 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, - 1, 0 )
	];
30

M
Mr.doob 已提交
31 32 33 34
	var cubeUps = [
		new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ),
		new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ),	new THREE.Vector3( 0, 0, - 1 )
	];
35

M
Mr.doob 已提交
36 37 38 39
	var cube2DViewPorts = [
		new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(),
		new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4()
	];
40

M
Mr.doob 已提交
41 42 43 44 45
	// init

	var depthShader = THREE.ShaderLib[ "depthRGBA" ];
	var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

46 47 48
	var distanceShader = THREE.ShaderLib[ "distanceRGBA" ];
	var distanceUniforms = THREE.UniformsUtils.clone( distanceShader.uniforms );

T
tschw 已提交
49 50 51
	for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {

		var useMorphing = ( i & _MorphingFlag ) !== 0;
M
Mr.doob 已提交
52
		var useSkinning = ( i & _SkinningFlag ) !== 0;
T
tschw 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

		var depthMaterial = new THREE.ShaderMaterial( {
			uniforms: depthUniforms,
			vertexShader: depthShader.vertexShader,
			fragmentShader: depthShader.fragmentShader,
			morphTargets: useMorphing,
			skinning: useSkinning
		} );

		depthMaterial._shadowPass = true;

		_depthMaterials[ i ] = depthMaterial;

		var distanceMaterial = new THREE.ShaderMaterial( {
			uniforms: distanceUniforms,
			vertexShader: distanceShader.vertexShader,
			fragmentShader: distanceShader.fragmentShader,
			morphTargets: useMorphing,
			skinning: useSkinning
		} );

		distanceMaterial._shadowPass = true;

		_distanceMaterials[ i ] = distanceMaterial;

	}
79

80 81 82 83 84
	//

	var scope = this;

	this.enabled = false;
85 86 87 88

	this.autoUpdate = true;
	this.needsUpdate = false;

89 90 91
	this.type = THREE.PCFShadowMap;
	this.cullFace = THREE.CullFaceFront;

M
Mr.doob 已提交
92
	this.render = function ( scene, camera ) {
A
alteredq 已提交
93

94
		var faceCount, isPointLight;
95

96
		if ( scope.enabled === false ) return;
M
Mr.doob 已提交
97
		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
A
alteredq 已提交
98

M
Mr.doob 已提交
99
		// Set GL state for depth map.
100
		_state.clearColor( 1, 1, 1, 1 );
101 102
		_state.disable( _gl.BLEND );
		_state.enable( _gl.CULL_FACE );
103
		_gl.frontFace( _gl.CCW );
104
		_gl.cullFace( scope.cullFace === THREE.CullFaceFront ? _gl.FRONT : _gl.BACK );
M
Mr.doob 已提交
105
		_state.setDepthTest( true );
106
		_state.setScissorTest( false );
107

108
		// render depth map
109

M
Mr.doob 已提交
110 111 112 113
		var shadows = _lights.shadows;

		for ( var i = 0, il = shadows.length; i < il; i ++ ) {

114
			var light = shadows[ i ];
M
Mr.doob 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

			var shadow = light.shadow;
			var shadowCamera = shadow.camera;
			var shadowMapSize = shadow.mapSize;

			if ( light instanceof THREE.PointLight ) {

				faceCount = 6;
				isPointLight = true;

				var vpWidth = shadowMapSize.x / 4.0;
				var vpHeight = shadowMapSize.y / 2.0;

				// These viewports map a cube-map onto a 2D texture with the
				// following orientation:
				//
				//  xzXZ
				//   y Y
				//
				// X - Positive x direction
				// x - Negative x direction
				// Y - Positive y direction
				// y - Negative y direction
				// Z - Positive z direction
				// z - Negative z direction

				// positive X
				cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
				// negative X
				cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
				// positive Z
				cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
				// negative Z
				cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
				// positive Y
				cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
				// negative Y
				cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );

			} else {

				faceCount = 1;
				isPointLight = false;
M
Mark Kellogg 已提交
158

M
Mr.doob 已提交
159
			}
160

M
Mr.doob 已提交
161
			if ( shadow.map === null ) {
162

M
Mr.doob 已提交
163
				var shadowFilter = THREE.LinearFilter;
A
alteredq 已提交
164

M
Mr.doob 已提交
165
				if ( scope.type === THREE.PCFSoftShadowMap ) {
A
alteredq 已提交
166

M
Mr.doob 已提交
167
					shadowFilter = THREE.NearestFilter;
A
alteredq 已提交
168

M
Mr.doob 已提交
169
				}
170

M
Mr.doob 已提交
171
				var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
172

M
Mr.doob 已提交
173 174
				shadow.map = new THREE.WebGLRenderTarget( shadowMapSize.x, shadowMapSize.y, pars );
				shadow.matrix = new THREE.Matrix4();
175

M
Mr.doob 已提交
176
				//
M
Mr.doob 已提交
177

M
Mr.doob 已提交
178
				if ( light instanceof THREE.SpotLight ) {
A
alteredq 已提交
179

M
Mr.doob 已提交
180
					shadowCamera.aspect = shadowMapSize.x / shadowMapSize.y;
A
alteredq 已提交
181

M
Mr.doob 已提交
182
				}
183

M
Mr.doob 已提交
184
				shadowCamera.updateProjectionMatrix();
185

M
Mr.doob 已提交
186
			}
M
Mr.doob 已提交
187

M
Mr.doob 已提交
188 189
			var shadowMap = shadow.map;
			var shadowMatrix = shadow.matrix;
190

M
Mr.doob 已提交
191 192
			_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
			shadowCamera.position.copy( _lightPositionWorld );
M
Mark Kellogg 已提交
193

M
Mr.doob 已提交
194 195
			_renderer.setRenderTarget( shadowMap );
			_renderer.clear();
M
Mark Kellogg 已提交
196

M
Mr.doob 已提交
197 198
			// render shadow map for each cube face (if omni-directional) or
			// run a single pass if not
M
Mark Kellogg 已提交
199

M
Mr.doob 已提交
200
			for ( var face = 0; face < faceCount; face ++ ) {
M
Mark Kellogg 已提交
201

M
Mr.doob 已提交
202
				if ( isPointLight ) {
M
Mr.doob 已提交
203

M
Mr.doob 已提交
204 205 206 207
					_lookTarget.copy( shadowCamera.position );
					_lookTarget.add( cubeDirections[ face ] );
					shadowCamera.up.copy( cubeUps[ face ] );
					shadowCamera.lookAt( _lookTarget );
208

M
Mr.doob 已提交
209
					var vpDimensions = cube2DViewPorts[ face ];
210
					_state.viewport( vpDimensions );
M
Mr.doob 已提交
211

M
Mr.doob 已提交
212
				} else {
M
Mr.doob 已提交
213

M
Mr.doob 已提交
214 215 216 217
					_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
					shadowCamera.lookAt( _lookTarget );

				}
A
alteredq 已提交
218

M
Mr.doob 已提交
219 220
				shadowCamera.updateMatrixWorld();
				shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
A
alteredq 已提交
221

M
Mr.doob 已提交
222
				// compute shadow matrix
A
alteredq 已提交
223

M
Mr.doob 已提交
224 225 226 227 228 229
				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
				);
A
alteredq 已提交
230

M
Mr.doob 已提交
231 232
				shadowMatrix.multiply( shadowCamera.projectionMatrix );
				shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
A
alteredq 已提交
233

M
Mr.doob 已提交
234
				// update camera matrices and frustum
A
alteredq 已提交
235

M
Mr.doob 已提交
236 237
				_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
				_frustum.setFromMatrix( _projScreenMatrix );
A
alteredq 已提交
238

M
Mr.doob 已提交
239
				// set object matrices & frustum culling
A
alteredq 已提交
240

M
Mr.doob 已提交
241
				_renderList.length = 0;
M
Mr.doob 已提交
242

M
Mr.doob 已提交
243
				projectObject( scene, camera, shadowCamera );
A
alteredq 已提交
244

M
Mr.doob 已提交
245 246
				// render shadow map
				// render regular objects
A
alteredq 已提交
247

M
Mr.doob 已提交
248
				for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) {
A
alteredq 已提交
249

M
Mr.doob 已提交
250 251 252
					var object = _renderList[ j ];
					var geometry = _objects.update( object );
					var material = object.material;
A
alteredq 已提交
253

M
Mugen87 已提交
254
					if ( material instanceof THREE.MultiMaterial ) {
255

M
Mr.doob 已提交
256 257
						var groups = geometry.groups;
						var materials = material.materials;
258

M
Mr.doob 已提交
259
						for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
260

M
Mr.doob 已提交
261 262
							var group = groups[ k ];
							var groupMaterial = materials[ group.materialIndex ];
263

M
Mr.doob 已提交
264
							if ( groupMaterial.visible === true ) {
265

M
Mr.doob 已提交
266
								var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
267
								_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
268

269
							}
270

M
Mr.doob 已提交
271
						}
272

M
Mr.doob 已提交
273
					} else {
M
Mark Kellogg 已提交
274

M
Mr.doob 已提交
275
						var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
276
						_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
M
Mark Kellogg 已提交
277

278
					}
A
alteredq 已提交
279

O
OpenShift guest 已提交
280
				}
281

M
Mr.doob 已提交
282
			}
283

M
Mr.doob 已提交
284 285 286 287
			// We must call _renderer.resetGLState() at the end of each iteration of
			// the light loop in order to force material updates for each light.
			_renderer.resetGLState();

A
alteredq 已提交
288 289
		}

M
Mr.doob 已提交
290
		// Restore GL state.
A
alteredq 已提交
291 292
		var clearColor = _renderer.getClearColor(),
		clearAlpha = _renderer.getClearAlpha();
S
fix  
Steven Lu (PuTTY Win7 on rMBP[tmux]) 已提交
293
		_renderer.setClearColor( clearColor, clearAlpha );
294

295
		_state.enable( _gl.BLEND );
296

297
		if ( scope.cullFace === THREE.CullFaceFront ) {
298 299 300 301

			_gl.cullFace( _gl.BACK );

		}
A
alteredq 已提交
302

M
Mr.doob 已提交
303
		_renderer.resetGLState();
304

305 306
		scope.needsUpdate = false;

A
alteredq 已提交
307
	};
M
Mr.doob 已提交
308

309
	function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {
310

311
		var geometry = object.geometry;
312

T
tschw 已提交
313
		var newMaterial = null;
314

T
tschw 已提交
315 316
		var materialVariants = _depthMaterials;
		var customMaterial = object.customDepthMaterial;
317

318
		if ( isPointLight ) {
M
Mark Kellogg 已提交
319

T
tschw 已提交
320 321
			materialVariants = _distanceMaterials;
			customMaterial = object.customDistanceMaterial;
322

323
		}
324

T
tschw 已提交
325
		if ( ! customMaterial ) {
M
Mark Kellogg 已提交
326

T
tschw 已提交
327 328
			var useMorphing = geometry.morphTargets !== undefined &&
					geometry.morphTargets.length > 0 && material.morphTargets;
329

T
tschw 已提交
330
			var useSkinning = object instanceof THREE.SkinnedMesh && material.skinning;
331

T
tschw 已提交
332
			var variantIndex = 0;
M
Mr.doob 已提交
333

T
tschw 已提交
334 335
			if ( useMorphing ) variantIndex |= _MorphingFlag;
			if ( useSkinning ) variantIndex |= _SkinningFlag;
336

T
tschw 已提交
337
			newMaterial = materialVariants[ variantIndex ];
338 339 340

		} else {

T
tschw 已提交
341
			newMaterial = customMaterial;
342 343 344

		}

345 346 347
		newMaterial.visible = material.visible;
		newMaterial.wireframe = material.wireframe;
		newMaterial.wireframeLinewidth = material.wireframeLinewidth;
348

T
tschw 已提交
349
		if ( isPointLight && newMaterial.uniforms.lightPos !== undefined ) {
350

T
tschw 已提交
351
			newMaterial.uniforms.lightPos.value.copy( lightPositionWorld );
352

353 354 355
		}

		return newMaterial;
356 357 358

	}

M
Mr.doob 已提交
359
	function projectObject( object, camera, shadowCamera ) {
M
Mr.doob 已提交
360

M
Mr.doob 已提交
361
		if ( object.visible === false ) return;
M
Mr.doob 已提交
362

M
Mr.doob 已提交
363
		if ( object.layers.test( camera.layers ) && ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) ) {
M
Mr.doob 已提交
364

365
			if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
M
Mr.doob 已提交
366

367
				var material = object.material;
368

369
				if ( material.visible === true ) {
370

M
Mr.doob 已提交
371
					object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
372 373 374
					_renderList.push( object );

				}
375 376

			}
M
Mr.doob 已提交
377

M
Mr.doob 已提交
378
		}
M
Mr.doob 已提交
379

M
Mr.doob 已提交
380
		var children = object.children;
M
Mr.doob 已提交
381

M
Mr.doob 已提交
382
		for ( var i = 0, l = children.length; i < l; i ++ ) {
M
Mr.doob 已提交
383

M
Mr.doob 已提交
384
			projectObject( children[ i ], camera, shadowCamera );
M
Mr.doob 已提交
385

O
OpenShift guest 已提交
386
		}
M
Mr.doob 已提交
387

O
OpenShift guest 已提交
388
	}
A
alteredq 已提交
389

390
};