232 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			232 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									Clock,
							 | 
						||
| 
								 | 
							
									HalfFloatType,
							 | 
						||
| 
								 | 
							
									NoBlending,
							 | 
						||
| 
								 | 
							
									Vector2,
							 | 
						||
| 
								 | 
							
									WebGLRenderTarget
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								import { CopyShader } from '../shaders/CopyShader.js';
							 | 
						||
| 
								 | 
							
								import { ShaderPass } from './ShaderPass.js';
							 | 
						||
| 
								 | 
							
								import { MaskPass } from './MaskPass.js';
							 | 
						||
| 
								 | 
							
								import { ClearMaskPass } from './MaskPass.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class EffectComposer {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( renderer, renderTarget ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderer = renderer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this._pixelRatio = renderer.getPixelRatio();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( renderTarget === undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const size = renderer.getSize( new Vector2() );
							 | 
						||
| 
								 | 
							
											this._width = size.width;
							 | 
						||
| 
								 | 
							
											this._height = size.height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderTarget = new WebGLRenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
											renderTarget.texture.name = 'EffectComposer.rt1';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this._width = renderTarget.width;
							 | 
						||
| 
								 | 
							
											this._height = renderTarget.height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTarget1 = renderTarget;
							 | 
						||
| 
								 | 
							
										this.renderTarget2 = renderTarget.clone();
							 | 
						||
| 
								 | 
							
										this.renderTarget2.texture.name = 'EffectComposer.rt2';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.writeBuffer = this.renderTarget1;
							 | 
						||
| 
								 | 
							
										this.readBuffer = this.renderTarget2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderToScreen = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.passes = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.copyPass = new ShaderPass( CopyShader );
							 | 
						||
| 
								 | 
							
										this.copyPass.material.blending = NoBlending;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.clock = new Clock();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									swapBuffers() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const tmp = this.readBuffer;
							 | 
						||
| 
								 | 
							
										this.readBuffer = this.writeBuffer;
							 | 
						||
| 
								 | 
							
										this.writeBuffer = tmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									addPass( pass ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.passes.push( pass );
							 | 
						||
| 
								 | 
							
										pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									insertPass( pass, index ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.passes.splice( index, 0, pass );
							 | 
						||
| 
								 | 
							
										pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									removePass( pass ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const index = this.passes.indexOf( pass );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( index !== - 1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.passes.splice( index, 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									isLastEnabledPass( passIndex ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = passIndex + 1; i < this.passes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( this.passes[ i ].enabled ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									render( deltaTime ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// deltaTime value is in seconds
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( deltaTime === undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											deltaTime = this.clock.getDelta();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const currentRenderTarget = this.renderer.getRenderTarget();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let maskActive = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0, il = this.passes.length; i < il; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const pass = this.passes[ i ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( pass.enabled === false ) continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											pass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );
							 | 
						||
| 
								 | 
							
											pass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( pass.needsSwap ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( maskActive ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const context = this.renderer.getContext();
							 | 
						||
| 
								 | 
							
													const stencil = this.renderer.state.buffers.stencil;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													//context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
							 | 
						||
| 
								 | 
							
													stencil.setFunc( context.NOTEQUAL, 1, 0xffffffff );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													//context.stencilFunc( context.EQUAL, 1, 0xffffffff );
							 | 
						||
| 
								 | 
							
													stencil.setFunc( context.EQUAL, 1, 0xffffffff );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												this.swapBuffers();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( MaskPass !== undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( pass instanceof MaskPass ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													maskActive = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												} else if ( pass instanceof ClearMaskPass ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													maskActive = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderer.setRenderTarget( currentRenderTarget );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									reset( renderTarget ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( renderTarget === undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const size = this.renderer.getSize( new Vector2() );
							 | 
						||
| 
								 | 
							
											this._pixelRatio = this.renderer.getPixelRatio();
							 | 
						||
| 
								 | 
							
											this._width = size.width;
							 | 
						||
| 
								 | 
							
											this._height = size.height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderTarget = this.renderTarget1.clone();
							 | 
						||
| 
								 | 
							
											renderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTarget1.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTarget2.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTarget1 = renderTarget;
							 | 
						||
| 
								 | 
							
										this.renderTarget2 = renderTarget.clone();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.writeBuffer = this.renderTarget1;
							 | 
						||
| 
								 | 
							
										this.readBuffer = this.renderTarget2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setSize( width, height ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this._width = width;
							 | 
						||
| 
								 | 
							
										this._height = height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const effectiveWidth = this._width * this._pixelRatio;
							 | 
						||
| 
								 | 
							
										const effectiveHeight = this._height * this._pixelRatio;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTarget1.setSize( effectiveWidth, effectiveHeight );
							 | 
						||
| 
								 | 
							
										this.renderTarget2.setSize( effectiveWidth, effectiveHeight );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0; i < this.passes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.passes[ i ].setSize( effectiveWidth, effectiveHeight );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setPixelRatio( pixelRatio ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this._pixelRatio = pixelRatio;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.setSize( this._width, this._height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dispose() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTarget1.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTarget2.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.copyPass.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { EffectComposer };
							 |