UNPKG

55.5 kBJavaScriptView Raw
1/**
2 * @author alteredq / http://alteredqualia.com/
3 * @author MPanknin / http://www.redplant.de/
4 * @author takahiro / https://github.com/takahirox
5 *
6 * WebGLDeferredRenderer supports two types of Deferred Renderings.
7 * One is Classic Deferred Rendering and the other one is
8 * Light Pre-Pass (Deferred Lighting).
9 * Classic Deferred Rendering is default. You can use Light Pre-Pass
10 * by calling .enableLightPrePass( true ) method.
11 *
12 * Dependencies
13 * - THREE.CopyShader
14 * - THREE.RenderPass
15 * - THREE.ShaderPass
16 * - THREE.EffectComposer
17 * - THREE.FXAAShader
18 *
19 * TODO
20 * - reuse existing glsl
21 * - shadow
22 * - optimization
23 * - MRT (when it's available on Three.js)
24 * - AmbientLight
25 * - HemisphereLight
26 * - PointLight (distance < 0)
27 * - morphNormals
28 * - BumpMap
29 * - ToneMap
30 * - envMap
31 * - wrapAround
32 * - addEffect
33 */
34
35THREE.WebGLDeferredRenderer = function ( parameters ) {
36
37 parameters = parameters || {};
38
39 // private properties
40
41 var _this = this;
42
43 var _context;
44 var _state;
45
46 var _width, _height;
47
48 // for Classic Deferred Rendering
49 var _compColor;
50 var _passColor, _passForward, _passCopy;
51
52 // for Light Pre-Pass
53 var _compReconstruction;
54 var _passReconstruction;
55
56 // for Common
57 var _compNormalDepth, _compLight, _compFinal;
58 var _passNormalDepth, _passLight, _passLightFullscreen, _passFinal, _passFXAA;
59
60 var _depthTexture;
61
62 var _currentCamera;
63
64 var _lightScene, _lightFullscreenScene;
65
66 var _antialias = false;
67 var _hasTransparentObject = false;
68 var _lightPrePass = false;
69 var _cacheKeepAlive = false;
70
71 var _tmpMaterial = new THREE.ShaderMaterial( { visible: false } );
72 var _tmpVector3 = new THREE.Vector3();
73
74 // scene/material/light cache for deferred rendering.
75 // save them at the creation and release
76 // if they're unused removeThresholdCount frames
77 // unless _cacheKeepAlive is true.
78
79 // scene.uuid -> lightScene, lightFullscreenScene
80 var _lightScenesCache = {};
81 var _lightFullscreenScenesCache = {};
82
83 // object.material.uuid -> deferredMaterial or
84 // object.material[ n ].uuid -> deferredMaterial
85 var _normalDepthMaterialsCache = {};
86 var _normalDepthShininessMaterialsCache = {};
87 var _colorMaterialsCache = {};
88 var _reconstructionMaterialsCache = {};
89
90 // originalLight.uuid -> deferredLight
91 var _deferredLightsCache = {};
92
93 // deferredLight.uuid -> deferredLightMaterial
94 var _classicDeferredLightMaterialsCache = {};
95 var _lightPrePassMaterialsCache = {};
96
97 var _removeThresholdCount = 60;
98
99 // deferredMaterials.uuid -> object.material or
100 // deferredMaterials.uuid -> object.material[ n ]
101 // save before render and release after render.
102 var _originalMaterialsTable = {};
103
104 // object.uuid -> originalOnBeforeRender
105 // save before render and release after render.
106 var _originalOnBeforeRendersTable = {};
107
108 // object.material.uuid -> object.material.visible or
109 // object.material[ i ].uuid -> object.material[ i ].visible or
110 // save before render and release after render.
111 var _originalVisibleTable = {};
112
113 // external properties
114
115 this.renderer = undefined;
116 this.domElement = undefined;
117
118 this.forwardRendering = false; // for debug
119
120 // private methods
121
122 function init( parameters ) {
123
124 _this.renderer = parameters.renderer !== undefined ? parameters.renderer : new THREE.WebGLRenderer();
125 _this.domElement = _this.renderer.domElement;
126
127 _context = _this.renderer.getContext();
128 _state = _this.renderer.state;
129
130 _width = parameters.width !== undefined ? parameters.width : _this.renderer.getSize( new THREE.Vector2() ).width;
131 _height = parameters.height !== undefined ? parameters.height : _this.renderer.getSize( new THREE.Vector2() ).height;
132
133 var antialias = parameters.antialias !== undefined ? parameters.antialias : false;
134
135 if ( parameters.cacheKeepAlive !== undefined ) _cacheKeepAlive = parameters.cacheKeepAlive;
136
137 initDepthTexture();
138
139 initPassNormalDepth();
140 initPassColor();
141 initPassLight();
142 initPassReconstruction();
143 initPassFinal();
144
145 _this.setSize( _width, _height );
146 _this.setAntialias( antialias );
147 _this.enableLightPrePass( false );
148
149 }
150
151 function initDepthTexture() {
152
153 _depthTexture = new THREE.DepthTexture(
154 _width,
155 _height,
156 THREE.UnsignedInt248Type,
157 undefined,
158 undefined,
159 undefined,
160 undefined,
161 undefined,
162 undefined,
163 THREE.DepthStencilFormat
164 );
165
166 }
167
168 function initPassNormalDepth() {
169
170 _passNormalDepth = new THREE.RenderPass();
171 _passNormalDepth.clear = true;
172
173 var rt = new THREE.WebGLRenderTarget( _width, _height, {
174 minFilter: THREE.NearestFilter,
175 magFilter: THREE.NearestFilter,
176 format: THREE.RGBAFormat,
177 type: THREE.FloatType,
178 stencilBuffer: true,
179 depthTexture: _depthTexture
180 } );
181
182 rt.texture.generateMipamps = false;
183
184 _compNormalDepth = new THREE.EffectComposer( _this.renderer, rt );
185 _compNormalDepth.renderToScreen = false;
186 _compNormalDepth.addPass( _passNormalDepth );
187
188 }
189
190 function initPassColor() {
191
192 _passColor = new THREE.RenderPass();
193 _passColor.clear = true;
194
195 var rt = new THREE.WebGLRenderTarget( _width, _height, {
196 minFilter: THREE.NearestFilter,
197 magFilter: THREE.NearestFilter,
198 format: THREE.RGBAFormat,
199 type: THREE.FloatType,
200 depthTexture: _depthTexture
201 } );
202
203 rt.texture.generateMipamps = false;
204
205 _compColor = new THREE.EffectComposer( _this.renderer, rt );
206 _compColor.renderToScreen = false;
207 _compColor.addPass( _passColor );
208
209 }
210
211 function initPassLight() {
212
213 _passLightFullscreen = new THREE.RenderPass();
214 _passLightFullscreen.clear = true;
215 _passLightFullscreen.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
216
217 _passLight = new THREE.RenderPass();
218 _passLight.clear = false;
219
220 var rt = new THREE.WebGLRenderTarget( _width, _height, {
221 minFilter: THREE.NearestFilter,
222 magFilter: THREE.NearestFilter,
223 format: THREE.RGBAFormat,
224 type: THREE.FloatType,
225 depthTexture: _depthTexture
226 } );
227
228 rt.texture.generateMipamps = false;
229
230 _compLight = new THREE.EffectComposer( _this.renderer, rt );
231 _compLight.renderToScreen = false;
232 _compLight.addPass( _passLightFullscreen );
233 _compLight.addPass( _passLight );
234
235 }
236
237 function initPassReconstruction() {
238
239 _passReconstruction = new THREE.RenderPass();
240 _passReconstruction.clear = true;
241
242 var rt = new THREE.WebGLRenderTarget( _width, _height, {
243 minFilter: THREE.NearestFilter,
244 magFilter: THREE.NearestFilter,
245 format: THREE.RGBAFormat,
246 type: THREE.FloatType,
247 depthTexture: _depthTexture
248 } );
249
250 rt.texture.generateMipamps = false;
251
252 _compReconstruction = new THREE.EffectComposer( _this.renderer, rt );
253 _compReconstruction.renderToScreen = false;
254 _compReconstruction.addPass( _passReconstruction );
255
256 }
257
258 function initPassFinal() {
259
260 _passFinal = new THREE.ShaderPass( THREE.ShaderDeferred[ 'final' ] );
261 _passFinal.clear = true;
262 _passFinal.uniforms.samplerResult.value = _compLight.renderTarget2.texture;
263 _passFinal.material.blending = THREE.NoBlending;
264 _passFinal.material.depthWrite = false;
265 _passFinal.material.depthTest = false;
266
267 _passForward = new THREE.RenderPass();
268 _passForward.clear = false;
269
270 _passCopy = new THREE.ShaderPass( THREE.CopyShader );
271
272 _passFXAA = new THREE.ShaderPass( THREE.FXAAShader );
273
274 var rt = new THREE.WebGLRenderTarget( _width, _height, {
275 minFilter: THREE.NearestFilter,
276 magFilter: THREE.LinearFilter,
277 format: THREE.RGBFormat,
278 type: THREE.UnsignedByteType,
279 depthTexture: _depthTexture
280 } );
281
282 rt.texture.generateMipamps = false;
283
284 _compFinal = new THREE.EffectComposer( _this.renderer, rt );
285 _compFinal.addPass( _passFinal );
286 _compFinal.addPass( _passForward );
287 _compFinal.addPass( _passCopy );
288 _compFinal.addPass( _passFXAA );
289
290 }
291
292 function initLightScene( scene ) {
293
294 var lightSceneData = _lightScenesCache[ scene.uuid ];
295 var lightFullscreenSceneData = _lightFullscreenScenesCache[ scene.uuid ];
296
297 if ( lightSceneData === undefined ) {
298
299 var s = new THREE.Scene();
300 s.userData.lights = {};
301
302 lightSceneData = createCacheData();
303 lightSceneData.scene = s;
304
305 _lightScenesCache[ scene.uuid ] = lightSceneData;
306
307 }
308
309 if ( lightFullscreenSceneData === undefined ) {
310
311 var s = new THREE.Scene();
312 s.userData.lights = {};
313
314 var emissiveLight = createDeferredEmissiveLight();
315
316 s.userData.emissiveLight = emissiveLight;
317 s.add( emissiveLight );
318
319 lightFullscreenSceneData = createCacheData();
320 lightFullscreenSceneData.scene = s;
321
322 _lightFullscreenScenesCache[ scene.uuid ] = lightFullscreenSceneData;
323
324 }
325
326 lightSceneData.used = true;
327 lightFullscreenSceneData.used = true;
328
329 var lightScene = lightSceneData.scene;
330 var lightFullscreenScene = lightFullscreenSceneData.scene;
331
332 // emissiveLight is only for Classic Deferred Rendering
333 lightFullscreenScene.userData.emissiveLight.visible = ! _lightPrePass;
334
335 _lightScene = lightScene;
336 _lightFullscreenScene = lightFullscreenScene;
337
338 }
339
340 function getMaterialFromCacheOrCreate( originalMaterial, cache, createFunc, updateFunc ) {
341
342 var data = cache[ originalMaterial.uuid ];
343
344 if ( data === undefined ) {
345
346 data = createCacheData();
347 data.material = createFunc( originalMaterial );
348 cache[ originalMaterial.uuid ] = data;
349
350 }
351
352 data.used = true;
353
354 updateFunc( data.material, originalMaterial );
355
356 _originalMaterialsTable[ data.material.uuid ] = originalMaterial;
357
358 return data.material;
359
360 }
361
362 function overrideMaterialAndOnBeforeRender( object, getMaterialFunc, onBeforeRender ) {
363
364 if ( object.material === undefined ) return;
365
366 if ( Array.isArray( object.material ) ) {
367
368 for ( var i = 0, il = object.material.length; i < il; i ++ ) {
369
370 object.material[ i ] = getMaterialFunc( object.material[ i ] );
371
372 }
373
374 } else {
375
376 object.material = getMaterialFunc( object.material );
377
378 }
379
380 object.onBeforeRender = onBeforeRender;
381
382 }
383
384 function restoreOriginalMaterial( object ) {
385
386 if ( object.material === undefined ) return;
387
388 if ( Array.isArray( object.material ) ) {
389
390 for ( var i = 0, il = object.material.length; i < il; i ++ ) {
391
392 object.material[ i ] = _originalMaterialsTable[ object.material[ i ].uuid ];
393
394 }
395
396 } else {
397
398 object.material = _originalMaterialsTable[ object.material.uuid ];
399
400 }
401
402 }
403
404 function setMaterialNormalDepth( object ) {
405
406 overrideMaterialAndOnBeforeRender( object, getNormalDepthMaterial, updateDeferredNormalDepthUniforms );
407
408 }
409
410 function getNormalDepthMaterial( originalMaterial ) {
411
412 return getMaterialFromCacheOrCreate(
413 originalMaterial,
414 ( _lightPrePass ) ? _normalDepthShininessMaterialsCache : _normalDepthMaterialsCache,
415 createDeferredNormalDepthMaterial,
416 updateDeferredNormalDepthMaterial
417 );
418
419 }
420
421 function createDeferredNormalDepthMaterial() {
422
423 var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'normalDepthShininess' ] : THREE.ShaderDeferred[ 'normalDepth' ];
424
425 return new THREE.ShaderMaterial( {
426 uniforms: Object.assign( {}, shader.uniforms ),
427 fragmentShader: shader.fragmentShader,
428 vertexShader: shader.vertexShader,
429 blending: THREE.NoBlending
430 } );
431
432 }
433
434 function updateDeferredNormalDepthMaterial( material, originalMaterial ) {
435
436 if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
437 if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
438
439 if ( originalMaterial.visible === true ) {
440
441 material.visible = ! originalMaterial.transparent;
442
443 } else {
444
445 material.visible = false;
446
447 }
448
449 }
450
451 function updateDeferredNormalDepthUniforms( renderer, scene, camera, geometry, material ) {
452
453 if ( ! _lightPrePass ) return;
454
455 var originalMaterial = _originalMaterialsTable[ material.uuid ];
456
457 if ( originalMaterial === undefined || originalMaterial.shininess === undefined ) return;
458
459 material.uniforms.shininess.value = originalMaterial.shininess;
460
461 }
462
463 function setMaterialColor( object ) {
464
465 overrideMaterialAndOnBeforeRender( object, getColorMaterial, updateDeferredColorUniforms );
466
467 }
468
469 function getColorMaterial( originalMaterial ) {
470
471 return getMaterialFromCacheOrCreate(
472 originalMaterial,
473 _colorMaterialsCache,
474 createDeferredColorMaterial,
475 updateDeferredColorMaterial
476 );
477
478 }
479
480 function createDeferredColorMaterial( originalMaterial ) {
481
482 var shader = THREE.ShaderDeferred[ 'color' ];
483
484 var material = new THREE.ShaderMaterial( {
485 uniforms: Object.assign( {}, shader.uniforms ),
486 fragmentShader: shader.fragmentShader,
487 vertexShader: shader.vertexShader,
488 blending: THREE.NoBlending
489 } );
490
491 if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
492
493 return material;
494
495 }
496
497 function updateDeferredColorMaterial( material, originalMaterial ) {
498
499 if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
500 if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
501 if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
502
503 if ( originalMaterial.visible === true ) {
504
505 material.visible = ! originalMaterial.transparent;
506
507 } else {
508
509 material.visible = false;
510
511 }
512
513 }
514
515 function updateDeferredColorUniforms( renderer, scene, camera, geometry, material ) {
516
517 var originalMaterial = _originalMaterialsTable[ material.uuid ];
518 var uniforms = material.uniforms;
519
520 var diffuse, emissive;
521
522 if ( originalMaterial.isMeshBasicMaterial === true ) {
523
524 emissive = originalMaterial.color;
525
526 } else {
527
528 diffuse = originalMaterial.color;
529 emissive = originalMaterial.emissive;
530
531 }
532
533 var specular = originalMaterial.specular;
534 var shininess = originalMaterial.shininess;
535 var map = originalMaterial.map;
536
537 if ( diffuse !== undefined ) uniforms.diffuse.value.copy( diffuse );
538 if ( emissive !== undefined ) uniforms.emissive.value.copy( emissive );
539 if ( specular !== undefined ) uniforms.specular.value.copy( specular );
540 if ( shininess !== undefined && uniforms.shininess !== undefined ) uniforms.shininess.value = shininess;
541 if ( map !== undefined ) uniforms.map.value = map;
542
543 }
544
545 function setMaterialReconstruction( object ) {
546
547 overrideMaterialAndOnBeforeRender( object, getReconstructionMaterial, updateDeferredReconstructionUniforms );
548
549 }
550
551 function getReconstructionMaterial( originalMaterial ) {
552
553 if ( originalMaterial.transparent === true ) {
554
555 _originalMaterialsTable[ originalMaterial.uuid ] = originalMaterial;
556 return originalMaterial;
557
558 }
559
560 return getMaterialFromCacheOrCreate(
561 originalMaterial,
562 _reconstructionMaterialsCache,
563 createDeferredReconstructionMaterial,
564 updateDeferredReconstructionMaterial
565 );
566
567 }
568
569 function createDeferredReconstructionMaterial( originalMaterial ) {
570
571 var shader = THREE.ShaderDeferred[ 'reconstruction' ];
572
573 var material = new THREE.ShaderMaterial( {
574 uniforms: Object.assign( {}, shader.uniforms ),
575 fragmentShader: shader.fragmentShader,
576 vertexShader: shader.vertexShader,
577 blending: THREE.NoBlending
578 } );
579
580 if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
581
582 return material;
583
584 }
585
586 function updateDeferredReconstructionMaterial( material, originalMaterial ) {
587
588 updateDeferredColorMaterial( material, originalMaterial );
589
590 }
591
592 function updateDeferredReconstructionUniforms( renderer, scene, camera, geometry, material, group ) {
593
594 if ( material.transparent === true ) {
595
596 // 'this' is object here because this method is set as object.onBefore()
597 var onBeforeRender = _originalOnBeforeRendersTable[ this.uuid ];
598
599 if ( onBeforeRender ) {
600
601 onBeforeRender.call( this, renderer, scene, camera, geometry, material, group );
602
603 }
604
605 return;
606
607 }
608
609 updateDeferredColorUniforms( renderer, scene, camera, geometry, material );
610
611 material.uniforms.samplerLight.value = _compLight.renderTarget2.texture;
612
613 }
614
615 function setVisibleForForwardRendering( object ) {
616
617 if ( object.material === undefined ) return;
618
619 if ( Array.isArray( object.material ) ) {
620
621 for ( var i = 0, il = object.material.length; i < il; i ++ ) {
622
623 if ( _originalVisibleTable[ object.material[ i ].uuid ] === undefined ) {
624
625 _originalVisibleTable[ object.material[ i ].uuid ] = object.material[ i ].visible;
626 object.material[ i ].visible = object.material[ i ].transparent && object.material[ i ].visible;
627
628 }
629
630 }
631
632 } else {
633
634 if ( _originalVisibleTable[ object.material.uuid ] === undefined ) {
635
636 _originalVisibleTable[ object.material.uuid ] = object.material.visible;
637 object.material.visible = object.material.transparent && object.material.visible;
638
639 }
640
641 }
642
643 }
644
645 function restoreVisible( object ) {
646
647 if ( object.material === undefined ) return;
648
649 if ( Array.isArray( object.material ) ) {
650
651 for ( var i = 0, il = object.material.length; i < il; i ++ ) {
652
653 object.material[ i ].visible = _originalVisibleTable[ object.material[ i ].uuid ];
654
655 }
656
657 } else {
658
659 object.material.visible = _originalVisibleTable[ object.material.uuid ];
660
661 }
662
663 }
664
665 function createDeferredEmissiveLight() {
666
667 var shader = THREE.ShaderDeferred[ 'emissiveLight' ];
668
669 var material = new THREE.ShaderMaterial( {
670 uniforms: Object.assign( {}, shader.uniforms ),
671 vertexShader: shader.vertexShader,
672 fragmentShader: shader.fragmentShader,
673 blending: THREE.NoBlending,
674 depthWrite: false
675 } );
676
677 var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
678 var mesh = new THREE.Mesh( geometry, material );
679
680 mesh.onBeforeRender = function ( renderer, scene, camera, geometry, material ) {
681
682 material.uniforms.samplerColor.value = _compColor.renderTarget2.texture;
683
684 };
685
686 return mesh;
687
688 }
689
690 function createDeferredLight( originalLight ) {
691
692 if ( originalLight.isPointLight ) {
693
694 return createDeferredPointLight( originalLight );
695
696 } else if ( originalLight.isSpotLight ) {
697
698 return createDeferredSpotLight( originalLight );
699
700 } else if ( originalLight.isDirectionalLight ) {
701
702 return createDeferredDirectionalLight( originalLight );
703
704 }
705
706 return null;
707
708 }
709
710 function createDeferredLightMaterial( originalLight ) {
711
712 if ( originalLight.isPointLight ) {
713
714 return createDeferredPointLightMaterial();
715
716 } else if ( originalLight.isSpotLight ) {
717
718 return createDeferredSpotLightMaterial();
719
720 } else if ( originalLight.isDirectionalLight ) {
721
722 return createDeferredDirectionalLightMaterial();
723
724 }
725
726 return null;
727
728 }
729
730 function getDeferredLightMaterial( light ) {
731
732 var cache = ( _lightPrePass ) ? _lightPrePassMaterialsCache : _classicDeferredLightMaterialsCache;
733
734 var data = cache[ light.uuid ];
735
736 if ( data === undefined ) {
737
738 data = createCacheData();
739 data.material = createDeferredLightMaterial( light.userData.originalLight );
740 cache[ light.uuid ] = data;
741
742 }
743
744 data.used = true;
745
746 return data.material;
747
748 }
749
750 function updateDeferredLight( light ) {
751
752 var originalLight = light.userData.originalLight;
753
754 if ( originalLight.isPointLight ) {
755
756 updateDeferredPointLight( light );
757
758 }
759
760 }
761
762 function createDeferredLightMesh( light, geometry ) {
763
764 var mesh = new THREE.Mesh( geometry, _tmpMaterial );
765
766 mesh.userData.originalLight = light;
767
768 return mesh;
769
770 }
771
772 function createDeferredLightShaderMaterial( shader ) {
773
774 var material = new THREE.ShaderMaterial( {
775 uniforms: Object.assign( {}, shader.uniforms ),
776 vertexShader: shader.vertexShader,
777 fragmentShader: shader.fragmentShader,
778 transparent: true,
779 blending: THREE.AdditiveBlending,
780 depthWrite: false
781 } );
782
783 if ( _lightPrePass ) material.premultipliedAlpha = true;
784
785 return material;
786
787 }
788
789 function updateDeferredLightCommonUniforms( uniforms ) {
790
791 if ( _lightPrePass ) {
792
793 uniforms.samplerNormalDepthShininess.value = _compNormalDepth.renderTarget2.texture;
794
795 } else {
796
797 uniforms.samplerNormalDepth.value = _compNormalDepth.renderTarget2.texture;
798 uniforms.samplerColor.value = _compColor.renderTarget2.texture;
799
800 }
801
802 }
803
804 function createDeferredPointLight( light ) {
805
806 var mesh = createDeferredLightMesh( light, new THREE.SphereBufferGeometry( 1, 16, 8 ) );
807 mesh.onBeforeRender = updateDeferredPointLightUniforms;
808 return mesh;
809
810 }
811
812 /*
813 * optimization:
814 * Renders PointLight only back face with stencil test.
815 */
816 function createDeferredPointLightMaterial() {
817
818 var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'pointLightPre' ] : THREE.ShaderDeferred[ 'pointLight' ];
819
820 var material = createDeferredLightShaderMaterial( shader );
821
822 material.side = THREE.BackSide;
823 material.depthFunc = THREE.GreaterEqualDepth;
824
825 return material;
826
827 }
828
829 function updateDeferredPointLight( light ) {
830
831 var originalLight = light.userData.originalLight;
832 var distance = originalLight.distance;
833
834 if ( distance > 0 ) {
835
836 light.scale.set( 1, 1, 1 ).multiplyScalar( distance );
837 light.position.setFromMatrixPosition( originalLight.matrixWorld );
838
839 }
840
841 }
842
843 function updateDeferredPointLightUniforms( renderer, scene, camera, geometry, material ) {
844
845 var light = this;
846
847 var originalLight = light.userData.originalLight;
848 var distance = originalLight.distance;
849 var uniforms = material.uniforms;
850
851 uniforms.lightColor.value.copy( originalLight.color );
852
853 if ( distance > 0 ) {
854
855 uniforms.lightRadius.value = distance;
856 uniforms.lightIntensity.value = originalLight.intensity;
857 uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( _currentCamera.matrixWorldInverse );
858
859 } else {
860
861 uniforms.lightRadius.value = Infinity;
862
863 }
864
865 updateDeferredLightCommonUniforms( uniforms );
866
867 }
868
869 function createDeferredSpotLight( light ) {
870
871 var mesh = createDeferredLightMesh( light, new THREE.PlaneBufferGeometry( 2, 2 ) );
872 mesh.onBeforeRender = updateDeferredSpotLightUniforms;
873 return mesh;
874
875 }
876
877 function createDeferredSpotLightMaterial() {
878
879 var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'spotLightPre' ] : THREE.ShaderDeferred[ 'spotLight' ];
880
881 var material = createDeferredLightShaderMaterial( shader );
882
883 material.depthTest = false;
884
885 return material;
886
887 }
888
889 function updateDeferredSpotLightUniforms() {
890
891 var light = this;
892
893 var originalLight = light.userData.originalLight;
894 var uniforms = light.material.uniforms;
895
896 uniforms.lightAngle.value = originalLight.angle;
897 uniforms.lightColor.value.copy( originalLight.color );
898 uniforms.lightIntensity.value = originalLight.intensity;
899 uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( _currentCamera.matrixWorldInverse );
900
901 var vec = uniforms.lightDirectionVS.value;
902 var vec2 = _tmpVector3;
903
904 vec.setFromMatrixPosition( originalLight.matrixWorld );
905 vec2.setFromMatrixPosition( originalLight.target.matrixWorld );
906 vec.sub( vec2 ).normalize().transformDirection( _currentCamera.matrixWorldInverse );
907
908 updateDeferredLightCommonUniforms( uniforms );
909
910 }
911
912 function createDeferredDirectionalLight( light ) {
913
914 var mesh = createDeferredLightMesh( light, new THREE.PlaneBufferGeometry( 2, 2 ) );
915 mesh.onBeforeRender = updateDeferredDirectionalLightUniforms;
916 return mesh;
917
918 }
919
920 function createDeferredDirectionalLightMaterial() {
921
922 var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'directionalLightPre' ] : THREE.ShaderDeferred[ 'directionalLight' ];
923
924 var material = createDeferredLightShaderMaterial( shader );
925
926 material.depthTest = false;
927
928 return material;
929
930 }
931
932 function updateDeferredDirectionalLightUniforms() {
933
934 var light = this;
935
936 var originalLight = light.userData.originalLight;
937 var uniforms = light.material.uniforms;
938
939 uniforms.lightColor.value.copy( originalLight.color );
940 uniforms.lightIntensity.value = originalLight.intensity;
941
942 var vec = uniforms.lightDirectionVS.value;
943 var vec2 = _tmpVector3;
944
945 vec.setFromMatrixPosition( originalLight.matrixWorld );
946 vec2.setFromMatrixPosition( originalLight.target.matrixWorld );
947 vec.sub( vec2 ).normalize().transformDirection( _currentCamera.matrixWorldInverse );
948
949 updateDeferredLightCommonUniforms( uniforms );
950
951 }
952
953 function saveOriginalOnBeforeRenderAndCheckTransparency( object ) {
954
955 if ( object.material === undefined ) return;
956
957 _originalOnBeforeRendersTable[ object.uuid ] = object.onBeforeRender;
958
959 // _hasTransparentObject is used only for Classic Deferred Rendering
960 if ( _hasTransparentObject || _lightPrePass ) return;
961
962 if ( ! object.visible ) return;
963
964 if ( Array.isArray( object.material ) ) {
965
966 for ( var i = 0, il = object.material.length; i < il; i ++ ) {
967
968 if ( object.material[ i ].visible === true && object.material[ i ].transparent === true ) {
969
970 _hasTransparentObject = true;
971 break;
972
973 }
974
975 }
976
977 } else {
978
979 if ( object.material.visible === true && object.material.transparent === true ) _hasTransparentObject = true;
980
981 }
982
983 }
984
985 function restoreOriginalOnBeforeRender( object ) {
986
987 if ( object.material === undefined ) return;
988
989 object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
990
991 }
992
993 function addDeferredLightsToLightScene( object ) {
994
995 if ( object.isLight !== true ) return;
996
997 var data = _deferredLightsCache[ object.uuid ];
998
999 if ( data === undefined ) {
1000
1001 data = createCacheData();
1002 data.light = createDeferredLight( object );
1003 _deferredLightsCache[ object.uuid ] = data;
1004
1005 }
1006
1007 data.used = true;
1008
1009 var light = data.light;
1010
1011 if ( light === null ) return;
1012
1013 var scene = ( object.isPointLight === true ) ? _lightScene : _lightFullscreenScene;
1014
1015 var lights = scene.userData.lights;
1016
1017 if ( lights[ light.uuid ] === undefined ) {
1018
1019 scene.add( light );
1020
1021 lights[ light.uuid ] = {
1022 light: light,
1023 found: true
1024 };
1025
1026 }
1027
1028 lights[ light.uuid ].found = true;
1029
1030 }
1031
1032 function updateDeferredLightsInLightScene( scene ) {
1033
1034 var lights = scene.userData.lights;
1035 var keys = Object.keys( lights );
1036
1037 for ( var i = 0, il = keys.length; i < il; i ++ ) {
1038
1039 var key = keys[ i ];
1040
1041 if ( lights[ key ].found === false ) {
1042
1043 scene.remove( lights[ key ].light );
1044 delete lights[ key ];
1045
1046 } else {
1047
1048 var light = lights[ key ].light;
1049 light.material = getDeferredLightMaterial( light );
1050
1051 updateDeferredLight( light );
1052 lights[ key ].found = false;
1053
1054 }
1055
1056 }
1057
1058 }
1059
1060 function updateDeferredCommonUniforms( camera ) {
1061
1062 var uniforms = THREE.ShaderDeferredCommon[ 'commonUniforms' ];
1063
1064 uniforms.viewWidth.value = _width;
1065 uniforms.viewHeight.value = _height;
1066
1067 uniforms.matProjInverse.value.getInverse( camera.projectionMatrix );
1068
1069 }
1070
1071 function enableFinalPasses() {
1072
1073 if ( _lightPrePass ) {
1074
1075 _passForward.enabled = false;
1076 _passCopy.enabled = false;
1077
1078 if ( _antialias ) {
1079
1080 _passFXAA.enabled = true;
1081
1082 } else {
1083
1084 _passFXAA.enabled = false;
1085
1086 }
1087
1088 } else {
1089
1090 if ( _hasTransparentObject ) {
1091
1092 if ( _antialias ) {
1093
1094 _passForward.enabled = true;
1095 _passCopy.enabled = false;
1096 _passFXAA.enabled = true;
1097
1098 } else {
1099
1100 _passForward.enabled = true;
1101 _passCopy.enabled = true;
1102 _passFXAA.enabled = false;
1103
1104 }
1105
1106 } else {
1107
1108 if ( _antialias ) {
1109
1110 _passForward.enabled = false;
1111 _passCopy.enabled = false;
1112 _passFXAA.enabled = true;
1113
1114 } else {
1115
1116 _passForward.enabled = false;
1117 _passCopy.enabled = false;
1118 _passFXAA.enabled = false;
1119
1120 }
1121
1122 }
1123
1124 }
1125
1126 }
1127
1128 function createCacheData() {
1129
1130 return {
1131 used: true,
1132 keepAlive: _cacheKeepAlive,
1133 count: 0
1134 };
1135
1136 }
1137
1138 function cleanupCache( cache ) {
1139
1140 var keys = Object.keys( cache );
1141
1142 for ( var i = 0, il = keys.length; i < il; i ++ ) {
1143
1144 var key = keys[ i ];
1145
1146 if ( cache[ key ].used === false ) {
1147
1148 cache[ key ].count ++;
1149
1150 if ( cache[ key ].keepAlive === false && cache[ key ].count > _removeThresholdCount ) {
1151
1152 delete cache[ key ];
1153
1154 }
1155
1156 } else {
1157
1158 cache[ key ].used = false;
1159 cache[ key ].count = 0;
1160
1161 }
1162
1163 }
1164
1165 }
1166
1167 function cleanupTable( table ) {
1168
1169 var keys = Object.keys( table );
1170
1171 for ( var i = 0, il = keys.length; i < il; i ++ ) {
1172
1173 var key = keys[ i ];
1174
1175 table[ key ] = undefined;
1176
1177 }
1178
1179 }
1180
1181 function cleanupCaches() {
1182
1183 cleanupCache( _lightScenesCache );
1184 cleanupCache( _lightFullscreenScenesCache );
1185 cleanupCache( _normalDepthMaterialsCache );
1186 cleanupCache( _normalDepthShininessMaterialsCache );
1187 cleanupCache( _colorMaterialsCache );
1188 cleanupCache( _reconstructionMaterialsCache );
1189 cleanupCache( _classicDeferredLightMaterialsCache );
1190 cleanupCache( _lightPrePassMaterialsCache );
1191 cleanupCache( _deferredLightsCache );
1192
1193 cleanupTable( _originalMaterialsTable );
1194 cleanupTable( _originalOnBeforeRendersTable );
1195 cleanupTable( _originalVisibleTable );
1196
1197 }
1198
1199 /*
1200 * Classic Deferred Rendering
1201 *
1202 * 1) g-buffer normal + depth pass
1203 *
1204 * RGB: normal
1205 * A: depth
1206 *
1207 *
1208 * Light Pre-Pass Rendering
1209 *
1210 * 1') g-buffer normal + depth pass + shininess
1211 *
1212 * RG: normal
1213 * B: shininess
1214 * A: depth
1215 */
1216
1217 function renderNormalDepth( scene, camera ) {
1218
1219 scene.traverse( setMaterialNormalDepth );
1220
1221 _passNormalDepth.scene = scene;
1222 _passNormalDepth.camera = camera;
1223
1224 _this.renderer.autoClearDepth = true;
1225 _this.renderer.autoClearStencil = true;
1226
1227 _state.buffers.stencil.setTest( true );
1228 _state.buffers.stencil.setFunc( _context.ALWAYS, 1, 0xffffffff );
1229 _state.buffers.stencil.setOp( _context.REPLACE, _context.REPLACE, _context.REPLACE );
1230
1231 _compNormalDepth.render();
1232
1233 scene.traverse( restoreOriginalMaterial );
1234
1235 }
1236
1237 /*
1238 * Classic Deferred Rendering
1239 *
1240 * 2) g-buffer color pass
1241 *
1242 * R: diffuse
1243 * G: emissive
1244 * B: specular
1245 * A: shininess
1246 */
1247
1248 function renderColor( scene, camera ) {
1249
1250 scene.traverse( setMaterialColor );
1251
1252 _passColor.scene = scene;
1253 _passColor.camera = camera;
1254
1255 _this.renderer.autoClearDepth = false;
1256 _this.renderer.autoClearStencil = false;
1257
1258 _state.buffers.stencil.setFunc( _context.EQUAL, 1, 0xffffffff );
1259 _state.buffers.stencil.setOp( _context.KEEP, _context.KEEP, _context.KEEP );
1260
1261 _compColor.render();
1262
1263 scene.traverse( restoreOriginalMaterial );
1264
1265 }
1266
1267 /*
1268 * Classic Deferred Rendering
1269 *
1270 * 3) light pass
1271 */
1272
1273 function renderLight( scene, camera ) {
1274
1275 scene.traverse( addDeferredLightsToLightScene );
1276
1277 updateDeferredLightsInLightScene( _lightScene );
1278 updateDeferredLightsInLightScene( _lightFullscreenScene );
1279
1280 _passLight.scene = _lightScene;
1281 _passLight.camera = camera;
1282
1283 _passLightFullscreen.scene = _lightFullscreenScene;
1284
1285 _this.renderer.autoClearDepth = false;
1286 _this.renderer.autoClearStencil = false;
1287
1288 _compLight.render();
1289
1290 _state.buffers.stencil.setTest( false );
1291
1292 }
1293
1294 /*
1295 * Light Pre-Pass Rendering
1296 *
1297 * 2') Light pre pass
1298 */
1299
1300 function renderLightPre( scene, camera ) {
1301
1302 scene.traverse( addDeferredLightsToLightScene );
1303
1304 updateDeferredLightsInLightScene( _lightScene );
1305 updateDeferredLightsInLightScene( _lightFullscreenScene );
1306
1307 _passLight.scene = _lightScene;
1308 _passLight.camera = camera;
1309
1310 _passLightFullscreen.scene = _lightFullscreenScene;
1311
1312 _this.renderer.autoClearDepth = false;
1313 _this.renderer.autoClearStencil = false;
1314
1315 _state.buffers.stencil.setFunc( _context.EQUAL, 1, 0xffffffff );
1316 _state.buffers.stencil.setOp( _context.KEEP, _context.KEEP, _context.KEEP );
1317
1318 _compLight.render();
1319
1320 }
1321
1322 /*
1323 * Light Pre-Pass Rendering
1324 *
1325 * 3') Reconstruction pass
1326 *
1327 * Transprency handling:
1328 * Here renders transparent objects with normal forward rendering.
1329 */
1330
1331 function renderReconstruction( scene, camera ) {
1332
1333 scene.traverse( setMaterialReconstruction );
1334
1335 _passReconstruction.scene = scene;
1336 _passReconstruction.camera = camera;
1337
1338 _this.renderer.autoClearDepth = false;
1339 _this.renderer.autoClearStencil = false;
1340
1341 _compReconstruction.render();
1342
1343 _state.buffers.stencil.setTest( false );
1344
1345 scene.traverse( restoreOriginalMaterial );
1346
1347 }
1348
1349 /*
1350 * Classic Deferred Rendering
1351 *
1352 * 4) Final pass
1353 *
1354 * transparency handling:
1355 * If there's any transparent objects, here renders them on the deferred rendering result
1356 * with normal forward rendering. This may be the easist way but heavy.
1357 * We should consider any better ways someday.
1358 *
1359 *
1360 * Light Pre-Pass Rendering
1361 *
1362 * 4') Final pass
1363 *
1364 *
1365 * Common
1366 *
1367 * antialias handling:
1368 * Here uses postprocessing FXAA for antialias.
1369 *
1370 */
1371
1372 function renderFinal( scene, camera ) {
1373
1374 if ( ! _lightPrePass && _hasTransparentObject ) {
1375
1376 scene.traverse( setVisibleForForwardRendering );
1377 scene.traverse( restoreOriginalOnBeforeRender );
1378
1379 _passForward.scene = scene;
1380 _passForward.camera = camera;
1381
1382 }
1383
1384 enableFinalPasses();
1385
1386 _this.renderer.autoClearDepth = false;
1387 _this.renderer.autoClearStencil = false;
1388
1389 _compFinal.render();
1390
1391 if ( ! _lightPrePass && _hasTransparentObject ) {
1392
1393 scene.traverse( restoreVisible );
1394
1395 }
1396
1397 }
1398
1399 // external APIs
1400
1401 this.setSize = function ( width, height ) {
1402
1403 _width = width;
1404 _height = height;
1405
1406 this.renderer.setSize( _width, _height );
1407
1408 _compNormalDepth.setSize( _width, _height );
1409 _compColor.setSize( _width, _height );
1410 _compLight.setSize( _width, _height );
1411 _compReconstruction.setSize( _width, _height );
1412 _compFinal.setSize( _width, _height );
1413
1414 _depthTexture.image.width = _width;
1415 _depthTexture.image.height = _height;
1416 _depthTexture.needsUpdate = true;
1417
1418 _passFXAA.uniforms.resolution.value.set( 1 / _width, 1 / _height );
1419
1420 };
1421
1422 this.setAntialias = function ( enabled ) {
1423
1424 _antialias = enabled;
1425
1426 };
1427
1428 this.enableLightPrePass = function ( enabled ) {
1429
1430 _lightPrePass = enabled;
1431
1432 _passFinal.uniforms.samplerResult.value = ( _lightPrePass ) ? _compReconstruction.renderTarget2.texture : _compLight.renderTarget2.texture;
1433
1434 };
1435
1436 this.render = function ( scene, camera ) {
1437
1438 // for debug to compare with normal forward rendering
1439
1440 if ( this.forwardRendering ) {
1441
1442 this.renderer.render( scene, camera );
1443 return;
1444
1445 }
1446
1447 var currentSceneAutoUpdate = scene.autoUpdate;
1448 var currentAutoClearColor = this.renderer.autoClearColor;
1449 var currentAutoClearDepth = this.renderer.autoClearDepth;
1450 var currentAutoClearStencil = this.renderer.autoClearStencil;
1451
1452 _currentCamera = camera;
1453
1454 initLightScene( scene );
1455
1456 scene.autoUpdate = false;
1457 scene.updateMatrixWorld();
1458
1459 _hasTransparentObject = false;
1460
1461 scene.traverse( saveOriginalOnBeforeRenderAndCheckTransparency );
1462
1463 updateDeferredCommonUniforms( camera );
1464
1465 renderNormalDepth( scene, camera );
1466
1467 if ( _lightPrePass ) {
1468
1469 renderLightPre( scene, camera );
1470 renderReconstruction( scene, camera );
1471
1472 } else {
1473
1474 renderColor( scene, camera );
1475 renderLight( scene, camera );
1476
1477 }
1478
1479 renderFinal( scene, camera );
1480
1481 scene.traverse( restoreOriginalOnBeforeRender );
1482
1483 cleanupCaches();
1484
1485 scene.autoUpdate = currentSceneAutoUpdate;
1486 this.renderer.autoClearColor = currentAutoClearColor;
1487 this.renderer.autoClearDepth = currentAutoClearDepth;
1488 this.renderer.autoClearStencil = currentAutoClearStencil;
1489
1490 };
1491
1492 // initialize
1493
1494 init( parameters );
1495
1496};
1497
1498THREE.DeferredShaderChunk = {
1499
1500 packVector3: [
1501
1502 "float vec3_to_float( vec3 data ) {",
1503
1504 " const float unit = 255.0/256.0;",
1505 " highp float compressed = fract( data.x * unit ) + floor( data.y * unit * 255.0 ) + floor( data.z * unit * 255.0 ) * 255.0;",
1506 " return compressed;",
1507
1508 "}"
1509
1510 ].join( "\n" ),
1511
1512 unpackFloat: [
1513
1514 "vec3 float_to_vec3( float data ) {",
1515
1516 " const float unit = 255.0;",
1517 " vec3 uncompressed;",
1518 " uncompressed.x = fract( data );",
1519 " float zInt = floor( data / unit );",
1520 " uncompressed.z = fract( zInt / unit );",
1521 " uncompressed.y = fract( floor( data - ( zInt * unit ) ) / unit );",
1522 " return uncompressed;",
1523
1524 "}"
1525
1526 ].join( "\n" ),
1527
1528 // Refer to http://aras-p.info/texts/CompactNormalStorage.html
1529 packNormal: [
1530
1531 "vec2 normal_to_vec2( vec3 normal ) {",
1532
1533 " return normal.xy / sqrt( normal.z * 8.0 + 8.0 ) + 0.5;",
1534
1535 "}"
1536
1537 ].join( "\n" ),
1538
1539 unpackVector2: [
1540
1541 "vec3 vec2_to_normal( vec2 data ) {",
1542
1543 " vec2 fenc = data * 4.0 - 2.0;",
1544 " float f = dot( fenc, fenc );",
1545 " float g = sqrt( 1.0 - f / 4.0 );",
1546 " vec3 normal;",
1547 " normal.xy = fenc * g;",
1548 " normal.z = 1.0 - f / 2.0;",
1549 " return normal;",
1550
1551 "}"
1552
1553 ].join( "\n" ),
1554
1555 computeTextureCoord: [
1556
1557 "vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );"
1558
1559 ].join( "\n" ),
1560
1561 packNormalDepth: [
1562
1563 "vec4 packedNormalDepth;",
1564 "packedNormalDepth.xyz = normal * 0.5 + 0.5;",
1565 "packedNormalDepth.w = position.z / position.w;"
1566
1567 ].join( "\n" ),
1568
1569 unpackNormalDepth: [
1570
1571 "vec4 normalDepthMap = texture2D( samplerNormalDepth, texCoord );",
1572 "float depth = normalDepthMap.w;",
1573
1574 "if ( depth == 0.0 ) discard;",
1575
1576 "vec3 normal = normalDepthMap.xyz * 2.0 - 1.0;"
1577
1578 ].join( "\n" ),
1579
1580 packNormalDepthShininess: [
1581
1582 "vec4 packedNormalDepthShininess;",
1583 "packedNormalDepthShininess.xy = normal_to_vec2( normal );",
1584 "packedNormalDepthShininess.z = shininess;",
1585 "packedNormalDepthShininess.w = position.z / position.w;"
1586
1587 ].join( "\n" ),
1588
1589 unpackNormalDepthShininess: [
1590
1591 "vec4 normalDepthMap = texture2D( samplerNormalDepthShininess, texCoord );",
1592 "float depth = normalDepthMap.w;",
1593
1594 "if ( depth == 0.0 ) discard;",
1595
1596 "vec3 normal = vec2_to_normal( normalDepthMap.xy );",
1597 "float shininess = normalDepthMap.z;"
1598
1599 ].join( "\n" ),
1600
1601 packColor: [
1602
1603 "vec4 packedColor;",
1604 "packedColor.x = vec3_to_float( diffuseColor.rgb );",
1605 "packedColor.y = vec3_to_float( emissiveColor );",
1606 "packedColor.z = vec3_to_float( specularColor );",
1607 "packedColor.w = shininess;"
1608
1609 ].join( "\n" ),
1610
1611 unpackColor: [
1612
1613 "vec4 colorMap = texture2D( samplerColor, texCoord );",
1614 "vec3 diffuseColor = float_to_vec3( colorMap.x );",
1615 "vec3 emissiveColor = float_to_vec3( colorMap.y );",
1616 "vec3 specularColor = float_to_vec3( colorMap.z );",
1617 "float shininess = colorMap.w;"
1618
1619 ].join( "\n" ),
1620
1621 packLight: [
1622
1623 "vec4 packedLight;",
1624 "packedLight.xyz = lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * attenuation;",
1625 "packedLight.w = lightIntensity * specular * max( dot( lightVector, normal ), 0.0 ) * attenuation;"
1626
1627 ].join( "\n" ),
1628
1629 computeVertexPositionVS: [
1630
1631 "vec2 xy = texCoord * 2.0 - 1.0;",
1632 "vec4 vertexPositionProjected = vec4( xy, depth, 1.0 );",
1633 "vec4 vertexPositionVS = matProjInverse * vertexPositionProjected;",
1634 "vertexPositionVS.xyz /= vertexPositionVS.w;",
1635 "vertexPositionVS.w = 1.0;"
1636
1637 ].join( "\n" ),
1638
1639 // TODO: calculate schlick
1640 computeSpecular: [
1641
1642 "vec3 halfVector = normalize( lightVector - normalize( vertexPositionVS.xyz ) );",
1643 "float dotNormalHalf = max( dot( normal, halfVector ), 0.0 );",
1644 "float specular = 0.31830988618 * ( shininess * 0.5 + 1.0 ) * pow( dotNormalHalf, shininess );"
1645
1646 ].join( "\n" ),
1647
1648 combine: [
1649
1650 "gl_FragColor = vec4( lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * ( diffuseColor + specular * specularColor ) * attenuation, 1.0 );"
1651
1652 ].join( "\n" )
1653
1654};
1655
1656THREE.ShaderDeferredCommon = {
1657
1658 commonUniforms: {
1659
1660 matProjInverse: new THREE.Uniform( new THREE.Matrix4() ),
1661
1662 viewWidth: new THREE.Uniform( 800 ),
1663 viewHeight: new THREE.Uniform( 600 )
1664
1665 }
1666
1667};
1668
1669THREE.ShaderDeferred = {
1670
1671 normalDepth: {
1672
1673 uniforms: {},
1674
1675 vertexShader: [
1676
1677 "varying vec3 vNormal;",
1678 "varying vec4 vPosition;",
1679
1680 "#include <morphtarget_pars_vertex>",
1681 "#include <skinning_pars_vertex>",
1682
1683 "void main() {",
1684
1685 "#include <begin_vertex>",
1686 "#include <beginnormal_vertex>",
1687 "#include <skinbase_vertex>",
1688 "#include <skinnormal_vertex>",
1689 "#include <defaultnormal_vertex>",
1690 "#include <morphtarget_vertex>",
1691 "#include <skinning_vertex>",
1692 "#include <project_vertex>",
1693
1694 " vNormal = normalize( transformedNormal );",
1695 " vPosition = gl_Position;",
1696
1697 "}"
1698
1699 ].join( "\n" ),
1700
1701 fragmentShader: [
1702
1703 "varying vec3 vNormal;",
1704 "varying vec4 vPosition;",
1705
1706 "void main() {",
1707
1708 " vec3 normal = vNormal;",
1709 " vec4 position = vPosition;",
1710
1711 THREE.DeferredShaderChunk[ "packNormalDepth" ],
1712
1713 " gl_FragColor = packedNormalDepth;",
1714
1715 "}"
1716
1717 ].join( "\n" )
1718
1719 },
1720
1721 color: {
1722
1723 uniforms: {
1724
1725 map: new THREE.Uniform( null ),
1726 offsetRepeat: new THREE.Uniform( new THREE.Vector4( 0, 0, 1, 1 ) ),
1727
1728 diffuse: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
1729 emissive: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
1730 specular: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
1731 shininess: new THREE.Uniform( 30.0 )
1732
1733 },
1734
1735 vertexShader: [
1736
1737 "#include <uv_pars_vertex>",
1738 "#include <morphtarget_pars_vertex>",
1739 "#include <skinning_pars_vertex>",
1740
1741 "void main() {",
1742
1743 "#include <uv_vertex>",
1744 "#include <begin_vertex>",
1745 "#include <beginnormal_vertex>",
1746 "#include <skinbase_vertex>",
1747 "#include <skinnormal_vertex>",
1748 "#include <defaultnormal_vertex>",
1749 "#include <morphtarget_vertex>",
1750 "#include <skinning_vertex>",
1751 "#include <project_vertex>",
1752
1753 "}"
1754
1755 ].join( "\n" ),
1756
1757 fragmentShader: [
1758
1759 "uniform vec3 diffuse;",
1760 "uniform vec3 emissive;",
1761 "uniform vec3 specular;",
1762 "uniform float shininess;",
1763
1764 "#include <uv_pars_fragment>",
1765 "#include <map_pars_fragment>",
1766 THREE.DeferredShaderChunk[ "packVector3" ],
1767
1768 "void main() {",
1769
1770 " vec4 diffuseColor = vec4( diffuse, 1.0 );",
1771 " vec3 emissiveColor = emissive;",
1772 " vec3 specularColor = specular;",
1773
1774 "#include <map_fragment>",
1775 THREE.DeferredShaderChunk[ "packColor" ],
1776
1777 " gl_FragColor = packedColor;",
1778
1779 "}"
1780
1781 ].join( "\n" )
1782
1783 },
1784
1785 emissiveLight: {
1786
1787 uniforms: Object.assign(
1788
1789 {
1790
1791 samplerColor: new THREE.Uniform( null )
1792
1793 },
1794
1795 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
1796
1797 ),
1798
1799 vertexShader: [
1800
1801 "void main() { ",
1802
1803 " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
1804
1805 "}"
1806
1807 ].join( '\n' ),
1808
1809 fragmentShader: [
1810
1811 "uniform sampler2D samplerColor;",
1812
1813 "uniform float viewHeight;",
1814 "uniform float viewWidth;",
1815
1816 THREE.DeferredShaderChunk[ "unpackFloat" ],
1817
1818 "void main() {",
1819
1820 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
1821 THREE.DeferredShaderChunk[ "unpackColor" ],
1822
1823 " gl_FragColor = vec4( emissiveColor, 1.0 );",
1824
1825 "}"
1826
1827 ].join( '\n' )
1828
1829 },
1830
1831 pointLight: {
1832
1833 uniforms: Object.assign(
1834
1835 {
1836
1837 samplerNormalDepth: new THREE.Uniform( null ),
1838 samplerColor: new THREE.Uniform( null ),
1839
1840 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
1841 lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
1842 lightIntensity: new THREE.Uniform( 1.0 ),
1843 lightRadius: new THREE.Uniform( 1.0 )
1844
1845 },
1846
1847 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
1848
1849 ),
1850
1851 vertexShader: [
1852
1853 "void main() {",
1854
1855 " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
1856
1857 "}"
1858
1859 ].join( "\n" ),
1860
1861 fragmentShader: [
1862
1863 "uniform sampler2D samplerNormalDepth;",
1864 "uniform sampler2D samplerColor;",
1865
1866 "uniform float viewHeight;",
1867 "uniform float viewWidth;",
1868
1869 "uniform vec3 lightColor;",
1870 "uniform vec3 lightPositionVS;",
1871 "uniform float lightIntensity;",
1872 "uniform float lightRadius;",
1873
1874 "uniform mat4 matProjInverse;",
1875
1876 THREE.DeferredShaderChunk[ "unpackFloat" ],
1877
1878 "void main() {",
1879
1880 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
1881 THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
1882 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
1883
1884 " vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;",
1885 " float distance = length( lightVector );",
1886
1887 " if ( distance > lightRadius ) discard;",
1888
1889 " lightVector = normalize( lightVector );",
1890
1891 THREE.DeferredShaderChunk[ "unpackColor" ],
1892 THREE.DeferredShaderChunk[ "computeSpecular" ],
1893
1894 " //float cutoff = 0.3;",
1895 " //float denom = distance / lightRadius + 1.0;",
1896 " //float attenuation = 1.0 / ( denom * denom );",
1897 " //attenuation = ( attenuation - cutoff ) / ( 1.0 - cutoff );",
1898 " //attenuation = max( attenuation, 0.0 );",
1899 " //attenuation *= attenuation;",
1900
1901 " //diffuseColor *= saturate( -distance / lightRadius + 1.0 );",
1902 " //float attenuation = 1.0;",
1903
1904 " float attenuation = saturate( -distance / lightRadius + 1.0 );",
1905
1906 THREE.DeferredShaderChunk[ "combine" ],
1907
1908 "}"
1909
1910 ].join( "\n" )
1911
1912 },
1913
1914 spotLight: {
1915
1916 uniforms: Object.assign(
1917
1918 {
1919
1920 samplerNormalDepth: new THREE.Uniform( null ),
1921 samplerColor: new THREE.Uniform( null ),
1922
1923 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
1924 lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
1925 lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
1926 lightAngle: new THREE.Uniform( 1.0 ),
1927 lightIntensity: new THREE.Uniform( 1.0 )
1928
1929 },
1930
1931 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
1932
1933 ),
1934
1935 vertexShader: [
1936
1937 "void main() { ",
1938
1939 " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
1940
1941 "}"
1942
1943 ].join( "\n" ),
1944
1945 fragmentShader: [
1946
1947 "uniform sampler2D samplerNormalDepth;",
1948 "uniform sampler2D samplerColor;",
1949
1950 "uniform float viewHeight;",
1951 "uniform float viewWidth;",
1952
1953 "uniform vec3 lightColor;",
1954 "uniform vec3 lightPositionVS;",
1955 "uniform vec3 lightDirectionVS;",
1956 "uniform float lightAngle;",
1957 "uniform float lightIntensity;",
1958
1959 "uniform mat4 matProjInverse;",
1960
1961 THREE.DeferredShaderChunk[ "unpackFloat" ],
1962
1963 "void main() {",
1964
1965 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
1966 THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
1967 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
1968 THREE.DeferredShaderChunk[ "unpackColor" ],
1969
1970 " vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );",
1971
1972 " float rho = dot( lightDirectionVS, lightVector );",
1973 " float rhoMax = cos( lightAngle );",
1974
1975 " if ( rho <= rhoMax ) discard;",
1976
1977 " float theta = rhoMax + 0.0001;",
1978 " float phi = rhoMax + 0.05;",
1979 " float falloff = 4.0;",
1980
1981 " float spot = 0.0;",
1982
1983 " if ( rho >= phi ) {",
1984
1985 " spot = 1.0;",
1986
1987 " } else if ( rho <= theta ) {",
1988
1989 " spot = 0.0;",
1990
1991 " } else { ",
1992
1993 " spot = pow( ( rho - theta ) / ( phi - theta ), falloff );",
1994
1995 " }",
1996
1997 " diffuseColor *= spot;",
1998
1999 THREE.DeferredShaderChunk[ "computeSpecular" ],
2000
2001 " const float attenuation = 1.0;",
2002
2003 THREE.DeferredShaderChunk[ "combine" ],
2004
2005 "}"
2006
2007 ].join( "\n" )
2008
2009 },
2010
2011 directionalLight: {
2012
2013 uniforms: Object.assign(
2014
2015 {
2016
2017 samplerNormalDepth: new THREE.Uniform( null ),
2018 samplerColor: new THREE.Uniform( null ),
2019
2020 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2021 lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
2022 lightIntensity: new THREE.Uniform( 1.0 )
2023 },
2024
2025 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
2026
2027 ),
2028
2029 vertexShader: [
2030
2031 "void main() { ",
2032
2033 " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
2034
2035 "}"
2036
2037 ].join( '\n' ),
2038
2039 fragmentShader: [
2040
2041 "uniform sampler2D samplerNormalDepth;",
2042 "uniform sampler2D samplerColor;",
2043
2044 "uniform float viewHeight;",
2045 "uniform float viewWidth;",
2046
2047 "uniform vec3 lightColor;",
2048 "uniform vec3 lightDirectionVS;",
2049 "uniform float lightIntensity;",
2050
2051 "uniform mat4 matProjInverse;",
2052
2053 THREE.DeferredShaderChunk[ "unpackFloat" ],
2054
2055 "void main() {",
2056
2057 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
2058 THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
2059 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
2060 THREE.DeferredShaderChunk[ "unpackColor" ],
2061
2062 " vec3 lightVector = normalize( lightDirectionVS );",
2063
2064 THREE.DeferredShaderChunk[ "computeSpecular" ],
2065
2066 " const float attenuation = 1.0;",
2067
2068 THREE.DeferredShaderChunk[ "combine" ],
2069
2070 "}"
2071
2072 ].join( '\n' )
2073
2074 },
2075
2076 normalDepthShininess: {
2077
2078 uniforms: {
2079
2080 shininess: new THREE.Uniform( 30.0 )
2081
2082 },
2083
2084 vertexShader: [
2085
2086 "varying vec3 vNormal;",
2087 "varying vec4 vPosition;",
2088
2089 "#include <morphtarget_pars_vertex>",
2090 "#include <skinning_pars_vertex>",
2091
2092 "void main() {",
2093
2094 "#include <begin_vertex>",
2095 "#include <beginnormal_vertex>",
2096 "#include <skinbase_vertex>",
2097 "#include <skinnormal_vertex>",
2098 "#include <defaultnormal_vertex>",
2099 "#include <morphtarget_vertex>",
2100 "#include <skinning_vertex>",
2101 "#include <project_vertex>",
2102
2103 " vNormal = normalize( transformedNormal );",
2104 " vPosition = gl_Position;",
2105
2106 "}"
2107
2108 ].join( "\n" ),
2109
2110 fragmentShader: [
2111
2112 "varying vec3 vNormal;",
2113 "varying vec4 vPosition;",
2114
2115 "uniform float shininess;",
2116
2117 THREE.DeferredShaderChunk[ "packNormal" ],
2118
2119 "void main() {",
2120
2121 " vec3 normal = vNormal;",
2122 " vec4 position = vPosition;",
2123
2124 THREE.DeferredShaderChunk[ "packNormalDepthShininess" ],
2125
2126 " gl_FragColor = packedNormalDepthShininess;",
2127
2128 "}"
2129
2130 ].join( "\n" )
2131
2132 },
2133
2134 pointLightPre: {
2135
2136 uniforms: Object.assign(
2137
2138 {
2139
2140 samplerNormalDepthShininess: new THREE.Uniform( null ),
2141
2142 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2143 lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
2144 lightIntensity: new THREE.Uniform( 1.0 ),
2145 lightRadius: new THREE.Uniform( 1.0 )
2146 },
2147
2148 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
2149
2150 ),
2151
2152
2153 vertexShader: [
2154
2155 "void main() {",
2156
2157 " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
2158
2159 "}"
2160
2161 ].join( "\n" ),
2162
2163 fragmentShader: [
2164
2165 "uniform sampler2D samplerNormalDepthShininess;",
2166
2167 "uniform float viewHeight;",
2168 "uniform float viewWidth;",
2169
2170 "uniform vec3 lightColor;",
2171 "uniform vec3 lightPositionVS;",
2172 "uniform float lightIntensity;",
2173 "uniform float lightRadius;",
2174
2175 "uniform mat4 matProjInverse;",
2176
2177 THREE.DeferredShaderChunk[ "unpackFloat" ],
2178 THREE.DeferredShaderChunk[ "unpackVector2" ],
2179
2180 "void main() {",
2181
2182 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
2183 THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
2184 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
2185
2186 " vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;",
2187 " float distance = length( lightVector );",
2188
2189 " if ( distance > lightRadius ) discard;",
2190
2191 " lightVector = normalize( lightVector );",
2192
2193 THREE.DeferredShaderChunk[ "computeSpecular" ],
2194
2195 " float attenuation = saturate( -distance / lightRadius + 1.0 );",
2196
2197 THREE.DeferredShaderChunk[ "packLight" ],
2198
2199 " gl_FragColor = packedLight;",
2200
2201 "}"
2202
2203 ].join( "\n" )
2204
2205 },
2206
2207 spotLightPre: {
2208
2209 uniforms: Object.assign(
2210
2211 {
2212
2213 samplerNormalDepthShininess: new THREE.Uniform( null ),
2214
2215 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2216 lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
2217 lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
2218 lightAngle: new THREE.Uniform( 1.0 ),
2219 lightIntensity: new THREE.Uniform( 1.0 )
2220
2221 },
2222
2223 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
2224
2225 ),
2226
2227 vertexShader: [
2228
2229 "void main() { ",
2230
2231 " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
2232
2233 "}"
2234
2235 ].join( "\n" ),
2236
2237 fragmentShader: [
2238
2239 "uniform sampler2D samplerNormalDepthShininess;",
2240
2241 "uniform float viewHeight;",
2242 "uniform float viewWidth;",
2243
2244 "uniform vec3 lightColor;",
2245 "uniform vec3 lightPositionVS;",
2246 "uniform vec3 lightDirectionVS;",
2247 "uniform float lightAngle;",
2248 "uniform float lightIntensity;",
2249
2250 "uniform mat4 matProjInverse;",
2251
2252 THREE.DeferredShaderChunk[ "unpackFloat" ],
2253 THREE.DeferredShaderChunk[ "unpackVector2" ],
2254
2255 "void main() {",
2256
2257 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
2258 THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
2259 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
2260
2261 " vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );",
2262
2263 " float rho = dot( lightDirectionVS, lightVector );",
2264 " float rhoMax = cos( lightAngle );",
2265
2266 " if ( rho <= rhoMax ) discard;",
2267
2268 " float theta = rhoMax + 0.0001;",
2269 " float phi = rhoMax + 0.05;",
2270 " float falloff = 4.0;",
2271
2272 " float spot = 0.0;",
2273
2274 " if ( rho >= phi ) {",
2275
2276 " spot = 1.0;",
2277
2278 " } else if ( rho <= theta ) {",
2279
2280 " spot = 0.0;",
2281
2282 " } else { ",
2283
2284 " spot = pow( ( rho - theta ) / ( phi - theta ), falloff );",
2285
2286 " }",
2287
2288 THREE.DeferredShaderChunk[ "computeSpecular" ],
2289
2290 " const float attenuation = 1.0;",
2291
2292 THREE.DeferredShaderChunk[ "packLight" ],
2293
2294 " gl_FragColor = spot * packedLight;",
2295
2296 "}"
2297
2298 ].join( "\n" )
2299
2300 },
2301
2302 directionalLightPre: {
2303
2304 uniforms: Object.assign(
2305
2306 {
2307
2308 samplerNormalDepthShininess: new THREE.Uniform( null ),
2309
2310 lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2311 lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ),
2312 lightIntensity: new THREE.Uniform( 1.0 )
2313
2314 },
2315
2316 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
2317
2318 ),
2319
2320 vertexShader: [
2321
2322 "void main() { ",
2323
2324 " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
2325
2326 "}"
2327
2328 ].join( '\n' ),
2329
2330 fragmentShader: [
2331
2332 "uniform sampler2D samplerNormalDepthShininess;",
2333
2334 "uniform float viewHeight;",
2335 "uniform float viewWidth;",
2336
2337 "uniform vec3 lightColor;",
2338 "uniform vec3 lightDirectionVS;",
2339 "uniform float lightIntensity;",
2340
2341 "uniform mat4 matProjInverse;",
2342
2343 THREE.DeferredShaderChunk[ "unpackFloat" ],
2344 THREE.DeferredShaderChunk[ "unpackVector2" ],
2345
2346 "void main() {",
2347
2348 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
2349 THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
2350 THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
2351
2352 " vec3 lightVector = normalize( lightDirectionVS );",
2353
2354 THREE.DeferredShaderChunk[ "computeSpecular" ],
2355
2356 " const float attenuation = 1.0;",
2357
2358 THREE.DeferredShaderChunk[ "packLight" ],
2359
2360 " gl_FragColor = packedLight;",
2361
2362 "}"
2363
2364 ].join( '\n' )
2365
2366 },
2367
2368 reconstruction: {
2369
2370 uniforms: Object.assign(
2371
2372 {
2373
2374 samplerLight: new THREE.Uniform( null ),
2375
2376 map: new THREE.Uniform( null ),
2377 offsetRepeat: new THREE.Uniform( new THREE.Vector4( 0, 0, 1, 1 ) ),
2378
2379 diffuse: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2380 emissive: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2381 specular: new THREE.Uniform( new THREE.Color( 0x000000 ) ),
2382 shininess: new THREE.Uniform( 30.0 )
2383
2384 },
2385
2386 THREE.ShaderDeferredCommon[ 'commonUniforms' ]
2387
2388 ),
2389
2390 vertexShader: [
2391
2392 "#include <uv_pars_vertex>",
2393 "#include <morphtarget_pars_vertex>",
2394 "#include <skinning_pars_vertex>",
2395
2396 "void main() {",
2397
2398 "#include <uv_vertex>",
2399 "#include <begin_vertex>",
2400 "#include <beginnormal_vertex>",
2401 "#include <skinbase_vertex>",
2402 "#include <skinnormal_vertex>",
2403 "#include <defaultnormal_vertex>",
2404 "#include <morphtarget_vertex>",
2405 "#include <skinning_vertex>",
2406 "#include <project_vertex>",
2407
2408 "}"
2409
2410 ].join( "\n" ),
2411
2412 fragmentShader: [
2413
2414 "uniform sampler2D samplerLight;",
2415
2416 "uniform vec3 diffuse;",
2417 "uniform vec3 emissive;",
2418 "uniform vec3 specular;",
2419 "uniform float shininess;",
2420
2421 "uniform float viewHeight;",
2422 "uniform float viewWidth;",
2423
2424 "#include <uv_pars_fragment>",
2425 "#include <map_pars_fragment>",
2426
2427 THREE.DeferredShaderChunk[ "unpackFloat" ],
2428
2429 "void main() {",
2430
2431 " vec4 diffuseColor = vec4( diffuse, 1.0 );",
2432 " vec3 emissiveColor = emissive;",
2433 " vec3 specularColor = specular;",
2434
2435 THREE.DeferredShaderChunk[ "computeTextureCoord" ],
2436
2437 " vec4 light = texture2D( samplerLight, texCoord );",
2438
2439 "#include <map_fragment>",
2440
2441 " vec3 diffuseFinal = diffuseColor.rgb * light.rgb;",
2442 " vec3 emissiveFinal = emissiveColor;",
2443 " vec3 specularFinal = specularColor * light.rgb * light.a;",
2444
2445 " gl_FragColor = vec4( diffuseFinal + emissiveFinal + specularFinal, 1.0 );",
2446
2447 "}"
2448
2449 ].join( "\n" )
2450
2451 },
2452
2453 // TODO: implement tone mapping
2454 final: {
2455
2456 uniforms: {
2457
2458 samplerResult: new THREE.Uniform( null )
2459
2460 },
2461
2462 vertexShader: [
2463
2464 "varying vec2 texCoord;",
2465
2466 "void main() {",
2467
2468 " vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );",
2469 " texCoord = pos.xy * vec2( 0.5 ) + 0.5;",
2470 " gl_Position = pos;",
2471
2472 "}"
2473
2474 ].join( "\n" ),
2475
2476 fragmentShader: [
2477
2478 "varying vec2 texCoord;",
2479 "uniform sampler2D samplerResult;",
2480
2481 "void main() {",
2482
2483 " gl_FragColor = texture2D( samplerResult, texCoord );",
2484
2485 "}"
2486
2487 ].join( "\n" )
2488
2489 }
2490
2491};