WebGLShadowMap.js 10.8 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
	_min = new THREE.Vector3(),
14 15
	_max = new THREE.Vector3(),

16
	_lookTarget = new THREE.Vector3(),
17
	_lightPositionWorld = new THREE.Vector3(),
M
Mr.doob 已提交
18

T
tschw 已提交
19
	_renderList = [],
20

T
tschw 已提交
21 22 23
	_MorphingFlag = 1,
	_SkinningFlag = 2,

24
	_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
T
tschw 已提交
25 26 27

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

M
Mr.doob 已提交
29 30 31 32
	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 )
	];
33

M
Mr.doob 已提交
34 35 36 37
	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 )
	];
38

M
Mr.doob 已提交
39 40 41 42
	var cube2DViewPorts = [
		new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(),
		new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4()
	];
43 44

	var _vector4 = new THREE.Vector4();
45

M
Mr.doob 已提交
46 47 48 49 50
	// init

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

51 52 53
	var distanceShader = THREE.ShaderLib[ "distanceRGBA" ];
	var distanceUniforms = THREE.UniformsUtils.clone( distanceShader.uniforms );

T
tschw 已提交
54 55 56
	for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {

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


		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;

	}
85

86 87 88 89 90
	//

	var scope = this;

	this.enabled = false;
91 92 93 94

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

95 96 97
	this.type = THREE.PCFShadowMap;
	this.cullFace = THREE.CullFaceFront;

98
	this.render = function ( scene ) {
A
alteredq 已提交
99

100
		var faceCount, isPointLight;
101

102
		if ( scope.enabled === false ) return;
103
		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
A
alteredq 已提交
104

A
alteredq 已提交
105 106
		// set GL state for depth map

107
		_gl.clearColor( 1, 1, 1, 1 );
108
		_state.disable( _gl.BLEND );
109

110
		_state.enable( _gl.CULL_FACE );
111
		_gl.frontFace( _gl.CCW );
112

113
		if ( scope.cullFace === THREE.CullFaceFront ) {
114 115 116 117 118 119 120 121

			_gl.cullFace( _gl.FRONT );

		} else {

			_gl.cullFace( _gl.BACK );

		}
A
alteredq 已提交
122

M
Mr.doob 已提交
123
		_state.setDepthTest( true );
A
alteredq 已提交
124

125 126 127
		// save the existing viewport so it can be restored later
		_renderer.getViewport( _vector4 );

128
		// render depth map
129

130
		for ( var i = 0, il = _lights.length; i < il; i ++ ) {
131

132
			var light = _lights[ i ];
133

134
			if ( light instanceof THREE.PointLight ) {
M
Mark Kellogg 已提交
135

136
				faceCount = 6;
137 138 139 140 141
				isPointLight = true;

				var vpWidth = light.shadowMapWidth / 4.0;
				var vpHeight = light.shadowMapHeight / 2.0;

142 143 144 145 146 147 148 149 150 151 152 153
				// 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
154

155
				// positive X
156
				cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
157
				// negative X
158
				cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
159
				// positive Z
160
				cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
161
				// negative Z
162
				cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
163
				// positive Y
M
Mr.doob 已提交
164
				cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
165
				// negative Y
166
				cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
M
Mark Kellogg 已提交
167

168
			} else {
M
Mark Kellogg 已提交
169

170
				faceCount = 1;
171
				isPointLight = false;
M
Mark Kellogg 已提交
172

173 174
			}

175 176
			if ( ! light.castShadow ) continue;

A
alteredq 已提交
177
			if ( ! light.shadowMap ) {
A
alteredq 已提交
178

179
				var shadowFilter = THREE.LinearFilter;
180

181
				if ( scope.type === THREE.PCFSoftShadowMap ) {
182

183
					shadowFilter = THREE.NearestFilter;
184

185
				}
186

187
				var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
A
alteredq 已提交
188

189 190
				light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
				light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
A
alteredq 已提交
191 192 193 194 195 196 197 198

				light.shadowMatrix = new THREE.Matrix4();

			}

			if ( ! light.shadowCamera ) {

				if ( light instanceof THREE.SpotLight ) {
199 200

					light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
A
alteredq 已提交
201

A
alteredq 已提交
202 203 204
				} else if ( light instanceof THREE.DirectionalLight ) {

					light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );
205

A
alteredq 已提交
206 207
				} else {

208
					light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, 1.0, light.shadowCameraNear, light.shadowCameraFar );
209 210 211

				}

A
alteredq 已提交
212
				scene.add( light.shadowCamera );
213

214
				if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
215

A
alteredq 已提交
216
			}
A
alteredq 已提交
217

A
alteredq 已提交
218
			if ( light.shadowCameraVisible && ! light.cameraHelper ) {
A
alteredq 已提交
219

A
alteredq 已提交
220
				light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
221
				scene.add( light.cameraHelper );
A
alteredq 已提交
222

A
alteredq 已提交
223
			}
A
alteredq 已提交
224

225 226 227
			var shadowMap = light.shadowMap;
			var shadowMatrix = light.shadowMatrix;
			var shadowCamera = light.shadowCamera;
A
alteredq 已提交
228

229
			_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
230 231 232
			shadowCamera.position.copy( _lightPositionWorld );

			_renderer.setRenderTarget( shadowMap );
233
			_renderer.clear();
234 235 236

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

238 239 240
			for ( var face = 0; face < faceCount; face ++ ) {

				if ( isPointLight ) {
M
Mark Kellogg 已提交
241 242

					_lookTarget.copy( shadowCamera.position );
243 244 245 246 247
					_lookTarget.add( cubeDirections[ face ] );
					shadowCamera.up.copy( cubeUps[ face ] );
					shadowCamera.lookAt( _lookTarget );
					var vpDimensions = cube2DViewPorts[ face ];
					_renderer.setViewport( vpDimensions.x, vpDimensions.y, vpDimensions.z, vpDimensions.w );
M
Mark Kellogg 已提交
248

249
				} else {
M
Mark Kellogg 已提交
250

251
					_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
M
Mark Kellogg 已提交
252 253
					shadowCamera.lookAt( _lookTarget );

254
				}
A
alteredq 已提交
255

256 257
				shadowCamera.updateMatrixWorld();
				shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
A
alteredq 已提交
258

259 260
				if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
				if ( light.shadowCameraVisible ) light.cameraHelper.update();
M
Mr.doob 已提交
261

262
				// compute shadow matrix
A
alteredq 已提交
263

264 265 266 267 268 269
				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 已提交
270

271 272
				shadowMatrix.multiply( shadowCamera.projectionMatrix );
				shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
A
alteredq 已提交
273

274
				// update camera matrices and frustum
A
alteredq 已提交
275

276 277
				_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
				_frustum.setFromMatrix( _projScreenMatrix );
A
alteredq 已提交
278

279
				// set object matrices & frustum culling
A
alteredq 已提交
280

281
				_renderList.length = 0;
M
Mr.doob 已提交
282

283
				projectObject( scene, shadowCamera );
A
alteredq 已提交
284

285
				// render shadow map
286
				// render regular objects
A
alteredq 已提交
287

288
				for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) {
A
alteredq 已提交
289

290 291 292
					var object = _renderList[ j ];
					var geometry = _objects.update( object );
					var material = object.material;
A
alteredq 已提交
293

294
					if ( material instanceof THREE.MeshFaceMaterial ) {
295

296 297
						var groups = geometry.groups;
						var materials = material.materials;
298

299
						for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
300

301 302
							var group = groups[ k ];
							var groupMaterial = materials[ group.materialIndex ];
303

304
							if ( groupMaterial.visible === true ) {
305

306 307
								var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
								_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, group );
308

309
							}
310

311
						}
312

313
					} else {
M
Mark Kellogg 已提交
314

315
						var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
316
						_renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, null );
M
Mark Kellogg 已提交
317

318
					}
A
alteredq 已提交
319

O
OpenShift guest 已提交
320
				}
321

A
alteredq 已提交
322
			}
323

324
			_renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w );
325

A
alteredq 已提交
326 327
		}

A
alteredq 已提交
328 329 330 331 332
		// restore GL state

		var clearColor = _renderer.getClearColor(),
		clearAlpha = _renderer.getClearAlpha();

S
fix  
Steven Lu (PuTTY Win7 on rMBP[tmux]) 已提交
333
		_renderer.setClearColor( clearColor, clearAlpha );
334
		_state.enable( _gl.BLEND );
335

336
		if ( scope.cullFace === THREE.CullFaceFront ) {
337 338 339 340

			_gl.cullFace( _gl.BACK );

		}
A
alteredq 已提交
341

342 343
		_renderer.resetGLState();

344 345
		scope.needsUpdate = false;

A
alteredq 已提交
346
	};
M
Mr.doob 已提交
347

348
	function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {
349

350
		var geometry = object.geometry;
351

T
tschw 已提交
352
		var newMaterial = null;
353

T
tschw 已提交
354 355
		var materialVariants = _depthMaterials;
		var customMaterial = object.customDepthMaterial;
356

357
		if ( isPointLight ) {
M
Mark Kellogg 已提交
358

T
tschw 已提交
359 360
			materialVariants = _distanceMaterials;
			customMaterial = object.customDistanceMaterial;
361

362
		}
363

T
tschw 已提交
364
		if ( ! customMaterial ) {
M
Mark Kellogg 已提交
365

T
tschw 已提交
366 367
			var useMorphing = geometry.morphTargets !== undefined &&
					geometry.morphTargets.length > 0 && material.morphTargets;
368

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

T
tschw 已提交
371
			var variantIndex = 0;
M
Mr.doob 已提交
372

T
tschw 已提交
373 374
			if ( useMorphing ) variantIndex |= _MorphingFlag;
			if ( useSkinning ) variantIndex |= _SkinningFlag;
375

T
tschw 已提交
376
			newMaterial = materialVariants[ variantIndex ];
377 378 379

		} else {

T
tschw 已提交
380
			newMaterial = customMaterial;
381 382 383

		}

384 385 386
		newMaterial.visible = material.visible;
		newMaterial.wireframe = material.wireframe;
		newMaterial.wireframeLinewidth = material.wireframeLinewidth;
387

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

T
tschw 已提交
390
			newMaterial.uniforms.lightPos.value.copy( lightPositionWorld );
391

392 393 394
		}

		return newMaterial;
395 396 397

	}

398
	function projectObject( object, camera ) {
M
Mr.doob 已提交
399

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

402
		if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) {
M
Mr.doob 已提交
403

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

406
				var material = object.material;
407

408
				if ( material.visible === true ) {
409

410 411 412 413
					object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
					_renderList.push( object );

				}
414 415

			}
M
Mr.doob 已提交
416

M
Mr.doob 已提交
417
		}
M
Mr.doob 已提交
418

M
Mr.doob 已提交
419
		var children = object.children;
M
Mr.doob 已提交
420

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

M
Mr.doob 已提交
423
			projectObject( children[ i ], camera );
M
Mr.doob 已提交
424

O
OpenShift guest 已提交
425
		}
M
Mr.doob 已提交
426

O
OpenShift guest 已提交
427
	}
A
alteredq 已提交
428

429
};