source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/extras/renderers/plugins/ShadowMapPlugin.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 12.8 KB
Line 
1/**
2 * @author alteredq / http://alteredqualia.com/
3 */
4
5THREE.ShadowMapPlugin = function () {
6
7 var _gl,
8 _renderer,
9 _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
10
11 _frustum = new THREE.Frustum(),
12 _projScreenMatrix = new THREE.Matrix4(),
13
14 _min = new THREE.Vector3(),
15 _max = new THREE.Vector3(),
16
17 _matrixPosition = new THREE.Vector3();
18
19 this.init = function ( renderer ) {
20
21 _gl = renderer.context;
22 _renderer = renderer;
23
24 var depthShader = THREE.ShaderLib[ "depthRGBA" ];
25 var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
26
27 _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
28 _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } );
29 _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } );
30 _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } );
31
32 _depthMaterial._shadowPass = true;
33 _depthMaterialMorph._shadowPass = true;
34 _depthMaterialSkin._shadowPass = true;
35 _depthMaterialMorphSkin._shadowPass = true;
36
37 };
38
39 this.render = function ( scene, camera ) {
40
41 if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return;
42
43 this.update( scene, camera );
44
45 };
46
47 this.update = function ( scene, camera ) {
48
49 var i, il, j, jl, n,
50
51 shadowMap, shadowMatrix, shadowCamera,
52 program, buffer, material,
53 webglObject, object, light,
54 renderList,
55
56 lights = [],
57 k = 0,
58
59 fog = null;
60
61 // set GL state for depth map
62
63 _gl.clearColor( 1, 1, 1, 1 );
64 _gl.disable( _gl.BLEND );
65
66 _gl.enable( _gl.CULL_FACE );
67 _gl.frontFace( _gl.CCW );
68
69 if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
70
71 _gl.cullFace( _gl.FRONT );
72
73 } else {
74
75 _gl.cullFace( _gl.BACK );
76
77 }
78
79 _renderer.setDepthTest( true );
80
81 // preprocess lights
82 // - skip lights that are not casting shadows
83 // - create virtual lights for cascaded shadow maps
84
85 for ( i = 0, il = scene.__lights.length; i < il; i ++ ) {
86
87 light = scene.__lights[ i ];
88
89 if ( ! light.castShadow ) continue;
90
91 if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {
92
93 for ( n = 0; n < light.shadowCascadeCount; n ++ ) {
94
95 var virtualLight;
96
97 if ( ! light.shadowCascadeArray[ n ] ) {
98
99 virtualLight = createVirtualLight( light, n );
100 virtualLight.originalCamera = camera;
101
102 var gyro = new THREE.Gyroscope();
103 gyro.position = light.shadowCascadeOffset;
104
105 gyro.add( virtualLight );
106 gyro.add( virtualLight.target );
107
108 camera.add( gyro );
109
110 light.shadowCascadeArray[ n ] = virtualLight;
111
112 console.log( "Created virtualLight", virtualLight );
113
114 } else {
115
116 virtualLight = light.shadowCascadeArray[ n ];
117
118 }
119
120 updateVirtualLight( light, n );
121
122 lights[ k ] = virtualLight;
123 k ++;
124
125 }
126
127 } else {
128
129 lights[ k ] = light;
130 k ++;
131
132 }
133
134 }
135
136 // render depth map
137
138 for ( i = 0, il = lights.length; i < il; i ++ ) {
139
140 light = lights[ i ];
141
142 if ( ! light.shadowMap ) {
143
144 var shadowFilter = THREE.LinearFilter;
145
146 if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) {
147
148 shadowFilter = THREE.NearestFilter;
149
150 }
151
152 var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
153
154 light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
155 light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
156
157 light.shadowMatrix = new THREE.Matrix4();
158
159 }
160
161 if ( ! light.shadowCamera ) {
162
163 if ( light instanceof THREE.SpotLight ) {
164
165 light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
166
167 } else if ( light instanceof THREE.DirectionalLight ) {
168
169 light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );
170
171 } else {
172
173 console.error( "Unsupported light type for shadow" );
174 continue;
175
176 }
177
178 scene.add( light.shadowCamera );
179
180 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
181
182 }
183
184 if ( light.shadowCameraVisible && ! light.cameraHelper ) {
185
186 light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
187 light.shadowCamera.add( light.cameraHelper );
188
189 }
190
191 if ( light.isVirtual && virtualLight.originalCamera == camera ) {
192
193 updateShadowCamera( camera, light );
194
195 }
196
197 shadowMap = light.shadowMap;
198 shadowMatrix = light.shadowMatrix;
199 shadowCamera = light.shadowCamera;
200
201 shadowCamera.position.setFromMatrixPosition( light.matrixWorld );
202 _matrixPosition.setFromMatrixPosition( light.target.matrixWorld );
203 shadowCamera.lookAt( _matrixPosition );
204 shadowCamera.updateMatrixWorld();
205
206 shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
207
208 if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
209 if ( light.shadowCameraVisible ) light.cameraHelper.update();
210
211 // compute shadow matrix
212
213 shadowMatrix.set( 0.5, 0.0, 0.0, 0.5,
214 0.0, 0.5, 0.0, 0.5,
215 0.0, 0.0, 0.5, 0.5,
216 0.0, 0.0, 0.0, 1.0 );
217
218 shadowMatrix.multiply( shadowCamera.projectionMatrix );
219 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
220
221 // update camera matrices and frustum
222
223 _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
224 _frustum.setFromMatrix( _projScreenMatrix );
225
226 // render shadow map
227
228 _renderer.setRenderTarget( shadowMap );
229 _renderer.clear();
230
231 // set object matrices & frustum culling
232
233 renderList = scene.__webglObjects;
234
235 for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
236
237 webglObject = renderList[ j ];
238 object = webglObject.object;
239
240 webglObject.render = false;
241
242 if ( object.visible && object.castShadow ) {
243
244 if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
245
246 object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
247
248 webglObject.render = true;
249
250 }
251
252 }
253
254 }
255
256 // render regular objects
257
258 var objectMaterial, useMorphing, useSkinning;
259
260 for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
261
262 webglObject = renderList[ j ];
263
264 if ( webglObject.render ) {
265
266 object = webglObject.object;
267 buffer = webglObject.buffer;
268
269 // culling is overriden globally for all objects
270 // while rendering depth map
271
272 // need to deal with MeshFaceMaterial somehow
273 // in that case just use the first of material.materials for now
274 // (proper solution would require to break objects by materials
275 // similarly to regular rendering and then set corresponding
276 // depth materials per each chunk instead of just once per object)
277
278 objectMaterial = getObjectMaterial( object );
279
280 useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
281 useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
282
283 if ( object.customDepthMaterial ) {
284
285 material = object.customDepthMaterial;
286
287 } else if ( useSkinning ) {
288
289 material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
290
291 } else if ( useMorphing ) {
292
293 material = _depthMaterialMorph;
294
295 } else {
296
297 material = _depthMaterial;
298
299 }
300
301 if ( buffer instanceof THREE.BufferGeometry ) {
302
303 _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );
304
305 } else {
306
307 _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );
308
309 }
310
311 }
312
313 }
314
315 // set matrices and render immediate objects
316
317 renderList = scene.__webglObjectsImmediate;
318
319 for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
320
321 webglObject = renderList[ j ];
322 object = webglObject.object;
323
324 if ( object.visible && object.castShadow ) {
325
326 object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
327
328 _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object );
329
330 }
331
332 }
333
334 }
335
336 // restore GL state
337
338 var clearColor = _renderer.getClearColor(),
339 clearAlpha = _renderer.getClearAlpha();
340
341 _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
342 _gl.enable( _gl.BLEND );
343
344 if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
345
346 _gl.cullFace( _gl.BACK );
347
348 }
349
350 };
351
352 function createVirtualLight( light, cascade ) {
353
354 var virtualLight = new THREE.DirectionalLight();
355
356 virtualLight.isVirtual = true;
357
358 virtualLight.onlyShadow = true;
359 virtualLight.castShadow = true;
360
361 virtualLight.shadowCameraNear = light.shadowCameraNear;
362 virtualLight.shadowCameraFar = light.shadowCameraFar;
363
364 virtualLight.shadowCameraLeft = light.shadowCameraLeft;
365 virtualLight.shadowCameraRight = light.shadowCameraRight;
366 virtualLight.shadowCameraBottom = light.shadowCameraBottom;
367 virtualLight.shadowCameraTop = light.shadowCameraTop;
368
369 virtualLight.shadowCameraVisible = light.shadowCameraVisible;
370
371 virtualLight.shadowDarkness = light.shadowDarkness;
372
373 virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
374 virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];
375 virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];
376
377 virtualLight.pointsWorld = [];
378 virtualLight.pointsFrustum = [];
379
380 var pointsWorld = virtualLight.pointsWorld,
381 pointsFrustum = virtualLight.pointsFrustum;
382
383 for ( var i = 0; i < 8; i ++ ) {
384
385 pointsWorld[ i ] = new THREE.Vector3();
386 pointsFrustum[ i ] = new THREE.Vector3();
387
388 }
389
390 var nearZ = light.shadowCascadeNearZ[ cascade ];
391 var farZ = light.shadowCascadeFarZ[ cascade ];
392
393 pointsFrustum[ 0 ].set( -1, -1, nearZ );
394 pointsFrustum[ 1 ].set( 1, -1, nearZ );
395 pointsFrustum[ 2 ].set( -1, 1, nearZ );
396 pointsFrustum[ 3 ].set( 1, 1, nearZ );
397
398 pointsFrustum[ 4 ].set( -1, -1, farZ );
399 pointsFrustum[ 5 ].set( 1, -1, farZ );
400 pointsFrustum[ 6 ].set( -1, 1, farZ );
401 pointsFrustum[ 7 ].set( 1, 1, farZ );
402
403 return virtualLight;
404
405 }
406
407 // Synchronize virtual light with the original light
408
409 function updateVirtualLight( light, cascade ) {
410
411 var virtualLight = light.shadowCascadeArray[ cascade ];
412
413 virtualLight.position.copy( light.position );
414 virtualLight.target.position.copy( light.target.position );
415 virtualLight.lookAt( virtualLight.target );
416
417 virtualLight.shadowCameraVisible = light.shadowCameraVisible;
418 virtualLight.shadowDarkness = light.shadowDarkness;
419
420 virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
421
422 var nearZ = light.shadowCascadeNearZ[ cascade ];
423 var farZ = light.shadowCascadeFarZ[ cascade ];
424
425 var pointsFrustum = virtualLight.pointsFrustum;
426
427 pointsFrustum[ 0 ].z = nearZ;
428 pointsFrustum[ 1 ].z = nearZ;
429 pointsFrustum[ 2 ].z = nearZ;
430 pointsFrustum[ 3 ].z = nearZ;
431
432 pointsFrustum[ 4 ].z = farZ;
433 pointsFrustum[ 5 ].z = farZ;
434 pointsFrustum[ 6 ].z = farZ;
435 pointsFrustum[ 7 ].z = farZ;
436
437 }
438
439 // Fit shadow camera's ortho frustum to camera frustum
440
441 function updateShadowCamera( camera, light ) {
442
443 var shadowCamera = light.shadowCamera,
444 pointsFrustum = light.pointsFrustum,
445 pointsWorld = light.pointsWorld;
446
447 _min.set( Infinity, Infinity, Infinity );
448 _max.set( -Infinity, -Infinity, -Infinity );
449
450 for ( var i = 0; i < 8; i ++ ) {
451
452 var p = pointsWorld[ i ];
453
454 p.copy( pointsFrustum[ i ] );
455 THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera );
456
457 p.applyMatrix4( shadowCamera.matrixWorldInverse );
458
459 if ( p.x < _min.x ) _min.x = p.x;
460 if ( p.x > _max.x ) _max.x = p.x;
461
462 if ( p.y < _min.y ) _min.y = p.y;
463 if ( p.y > _max.y ) _max.y = p.y;
464
465 if ( p.z < _min.z ) _min.z = p.z;
466 if ( p.z > _max.z ) _max.z = p.z;
467
468 }
469
470 shadowCamera.left = _min.x;
471 shadowCamera.right = _max.x;
472 shadowCamera.top = _max.y;
473 shadowCamera.bottom = _min.y;
474
475 // can't really fit near/far
476 //shadowCamera.near = _min.z;
477 //shadowCamera.far = _max.z;
478
479 shadowCamera.updateProjectionMatrix();
480
481 }
482
483 // For the moment just ignore objects that have multiple materials with different animation methods
484 // Only the first material will be taken into account for deciding which depth material to use for shadow maps
485
486 function getObjectMaterial( object ) {
487
488 return object.material instanceof THREE.MeshFaceMaterial
489 ? object.material.materials[ 0 ]
490 : object.material;
491
492 };
493
494};
495
496THREE.ShadowMapPlugin.__projector = new THREE.Projector();
Note: See TracBrowser for help on using the repository browser.