655 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			655 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									AdditiveBlending,
							 | 
						||
| 
								 | 
							
									Color,
							 | 
						||
| 
								 | 
							
									DoubleSide,
							 | 
						||
| 
								 | 
							
									HalfFloatType,
							 | 
						||
| 
								 | 
							
									Matrix4,
							 | 
						||
| 
								 | 
							
									MeshDepthMaterial,
							 | 
						||
| 
								 | 
							
									NoBlending,
							 | 
						||
| 
								 | 
							
									RGBADepthPacking,
							 | 
						||
| 
								 | 
							
									ShaderMaterial,
							 | 
						||
| 
								 | 
							
									UniformsUtils,
							 | 
						||
| 
								 | 
							
									Vector2,
							 | 
						||
| 
								 | 
							
									Vector3,
							 | 
						||
| 
								 | 
							
									WebGLRenderTarget
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								import { Pass, FullScreenQuad } from './Pass.js';
							 | 
						||
| 
								 | 
							
								import { CopyShader } from '../shaders/CopyShader.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class OutlinePass extends Pass {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( resolution, scene, camera, selectedObjects ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										super();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderScene = scene;
							 | 
						||
| 
								 | 
							
										this.renderCamera = camera;
							 | 
						||
| 
								 | 
							
										this.selectedObjects = selectedObjects !== undefined ? selectedObjects : [];
							 | 
						||
| 
								 | 
							
										this.visibleEdgeColor = new Color( 1, 1, 1 );
							 | 
						||
| 
								 | 
							
										this.hiddenEdgeColor = new Color( 0.1, 0.04, 0.02 );
							 | 
						||
| 
								 | 
							
										this.edgeGlow = 0.0;
							 | 
						||
| 
								 | 
							
										this.usePatternTexture = false;
							 | 
						||
| 
								 | 
							
										this.edgeThickness = 1.0;
							 | 
						||
| 
								 | 
							
										this.edgeStrength = 3.0;
							 | 
						||
| 
								 | 
							
										this.downSampleRatio = 2;
							 | 
						||
| 
								 | 
							
										this.pulsePeriod = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this._visibilityCache = new Map();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.resolution = ( resolution !== undefined ) ? new Vector2( resolution.x, resolution.y ) : new Vector2( 256, 256 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const resx = Math.round( this.resolution.x / this.downSampleRatio );
							 | 
						||
| 
								 | 
							
										const resy = Math.round( this.resolution.y / this.downSampleRatio );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskBuffer = new WebGLRenderTarget( this.resolution.x, this.resolution.y );
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskBuffer.texture.name = 'OutlinePass.mask';
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskBuffer.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.depthMaterial = new MeshDepthMaterial();
							 | 
						||
| 
								 | 
							
										this.depthMaterial.side = DoubleSide;
							 | 
						||
| 
								 | 
							
										this.depthMaterial.depthPacking = RGBADepthPacking;
							 | 
						||
| 
								 | 
							
										this.depthMaterial.blending = NoBlending;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.prepareMaskMaterial = this.getPrepareMaskMaterial();
							 | 
						||
| 
								 | 
							
										this.prepareMaskMaterial.side = DoubleSide;
							 | 
						||
| 
								 | 
							
										this.prepareMaskMaterial.fragmentShader = replaceDepthToViewZ( this.prepareMaskMaterial.fragmentShader, this.renderCamera );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetDepthBuffer = new WebGLRenderTarget( this.resolution.x, this.resolution.y, { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetDepthBuffer.texture.name = 'OutlinePass.depth';
							 | 
						||
| 
								 | 
							
										this.renderTargetDepthBuffer.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskDownSampleBuffer = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskDownSampleBuffer.texture.name = 'OutlinePass.depthDownSample';
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskDownSampleBuffer.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer1 = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer1.texture.name = 'OutlinePass.blur1';
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer1.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer2 = new WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer2.texture.name = 'OutlinePass.blur2';
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer2.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.edgeDetectionMaterial = this.getEdgeDetectionMaterial();
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer1 = new WebGLRenderTarget( resx, resy, { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer1.texture.name = 'OutlinePass.edge1';
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer1.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer2 = new WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), { type: HalfFloatType } );
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer2.texture.name = 'OutlinePass.edge2';
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer2.texture.generateMipmaps = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const MAX_EDGE_THICKNESS = 4;
							 | 
						||
| 
								 | 
							
										const MAX_EDGE_GLOW = 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial1 = this.getSeperableBlurMaterial( MAX_EDGE_THICKNESS );
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial1.uniforms[ 'texSize' ].value.set( resx, resy );
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial1.uniforms[ 'kernelRadius' ].value = 1;
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial2 = this.getSeperableBlurMaterial( MAX_EDGE_GLOW );
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial2.uniforms[ 'texSize' ].value.set( Math.round( resx / 2 ), Math.round( resy / 2 ) );
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial2.uniforms[ 'kernelRadius' ].value = MAX_EDGE_GLOW;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Overlay material
							 | 
						||
| 
								 | 
							
										this.overlayMaterial = this.getOverlayMaterial();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// copy material
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const copyShader = CopyShader;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.copyUniforms = UniformsUtils.clone( copyShader.uniforms );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.materialCopy = new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
											uniforms: this.copyUniforms,
							 | 
						||
| 
								 | 
							
											vertexShader: copyShader.vertexShader,
							 | 
						||
| 
								 | 
							
											fragmentShader: copyShader.fragmentShader,
							 | 
						||
| 
								 | 
							
											blending: NoBlending,
							 | 
						||
| 
								 | 
							
											depthTest: false,
							 | 
						||
| 
								 | 
							
											depthWrite: false
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.enabled = true;
							 | 
						||
| 
								 | 
							
										this.needsSwap = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this._oldClearColor = new Color();
							 | 
						||
| 
								 | 
							
										this.oldClearAlpha = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.fsQuad = new FullScreenQuad( null );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.tempPulseColor1 = new Color();
							 | 
						||
| 
								 | 
							
										this.tempPulseColor2 = new Color();
							 | 
						||
| 
								 | 
							
										this.textureMatrix = new Matrix4();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function replaceDepthToViewZ( string, camera ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const type = camera.isPerspectiveCamera ? 'perspective' : 'orthographic';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return string.replace( /DEPTH_TO_VIEW_Z/g, type + 'DepthToViewZ' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dispose() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskBuffer.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetDepthBuffer.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskDownSampleBuffer.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer1.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer2.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer1.dispose();
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer2.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.depthMaterial.dispose();
							 | 
						||
| 
								 | 
							
										this.prepareMaskMaterial.dispose();
							 | 
						||
| 
								 | 
							
										this.edgeDetectionMaterial.dispose();
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial1.dispose();
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial2.dispose();
							 | 
						||
| 
								 | 
							
										this.overlayMaterial.dispose();
							 | 
						||
| 
								 | 
							
										this.materialCopy.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.fsQuad.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setSize( width, height ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskBuffer.setSize( width, height );
							 | 
						||
| 
								 | 
							
										this.renderTargetDepthBuffer.setSize( width, height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let resx = Math.round( width / this.downSampleRatio );
							 | 
						||
| 
								 | 
							
										let resy = Math.round( height / this.downSampleRatio );
							 | 
						||
| 
								 | 
							
										this.renderTargetMaskDownSampleBuffer.setSize( resx, resy );
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer1.setSize( resx, resy );
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer1.setSize( resx, resy );
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial1.uniforms[ 'texSize' ].value.set( resx, resy );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										resx = Math.round( resx / 2 );
							 | 
						||
| 
								 | 
							
										resy = Math.round( resy / 2 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderTargetBlurBuffer2.setSize( resx, resy );
							 | 
						||
| 
								 | 
							
										this.renderTargetEdgeBuffer2.setSize( resx, resy );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.separableBlurMaterial2.uniforms[ 'texSize' ].value.set( resx, resy );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									changeVisibilityOfSelectedObjects( bVisible ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const cache = this._visibilityCache;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function gatherSelectedMeshesCallBack( object ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( object.isMesh ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( bVisible === true ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													object.visible = cache.get( object );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													cache.set( object, object.visible );
							 | 
						||
| 
								 | 
							
													object.visible = bVisible;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0; i < this.selectedObjects.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const selectedObject = this.selectedObjects[ i ];
							 | 
						||
| 
								 | 
							
											selectedObject.traverse( gatherSelectedMeshesCallBack );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									changeVisibilityOfNonSelectedObjects( bVisible ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const cache = this._visibilityCache;
							 | 
						||
| 
								 | 
							
										const selectedMeshes = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function gatherSelectedMeshesCallBack( object ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( object.isMesh ) selectedMeshes.push( object );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0; i < this.selectedObjects.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const selectedObject = this.selectedObjects[ i ];
							 | 
						||
| 
								 | 
							
											selectedObject.traverse( gatherSelectedMeshesCallBack );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function VisibilityChangeCallBack( object ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( object.isMesh || object.isSprite ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// only meshes and sprites are supported by OutlinePass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												let bFound = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( let i = 0; i < selectedMeshes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const selectedObjectId = selectedMeshes[ i ].id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( selectedObjectId === object.id ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														bFound = true;
							 | 
						||
| 
								 | 
							
														break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( bFound === false ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const visibility = object.visible;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( bVisible === false || cache.get( object ) === true ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														object.visible = bVisible;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													cache.set( object, visibility );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} else if ( object.isPoints || object.isLine ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												// the visibilty of points and lines is always set to false in order to
							 | 
						||
| 
								 | 
							
												// not affect the outline computation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( bVisible === true ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													object.visible = cache.get( object ); // restore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													cache.set( object, object.visible );
							 | 
						||
| 
								 | 
							
													object.visible = bVisible;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.renderScene.traverse( VisibilityChangeCallBack );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									updateTextureMatrix() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5,
							 | 
						||
| 
								 | 
							
											0.0, 0.5, 0.0, 0.5,
							 | 
						||
| 
								 | 
							
											0.0, 0.0, 0.5, 0.5,
							 | 
						||
| 
								 | 
							
											0.0, 0.0, 0.0, 1.0 );
							 | 
						||
| 
								 | 
							
										this.textureMatrix.multiply( this.renderCamera.projectionMatrix );
							 | 
						||
| 
								 | 
							
										this.textureMatrix.multiply( this.renderCamera.matrixWorldInverse );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( this.selectedObjects.length > 0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderer.getClearColor( this._oldClearColor );
							 | 
						||
| 
								 | 
							
											this.oldClearAlpha = renderer.getClearAlpha();
							 | 
						||
| 
								 | 
							
											const oldAutoClear = renderer.autoClear;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderer.autoClear = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( maskActive ) renderer.state.buffers.stencil.setTest( false );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderer.setClearColor( 0xffffff, 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Make selected objects invisible
							 | 
						||
| 
								 | 
							
											this.changeVisibilityOfSelectedObjects( false );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const currentBackground = this.renderScene.background;
							 | 
						||
| 
								 | 
							
											this.renderScene.background = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// 1. Draw Non Selected objects in the depth buffer
							 | 
						||
| 
								 | 
							
											this.renderScene.overrideMaterial = this.depthMaterial;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetDepthBuffer );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											renderer.render( this.renderScene, this.renderCamera );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Make selected objects visible
							 | 
						||
| 
								 | 
							
											this.changeVisibilityOfSelectedObjects( true );
							 | 
						||
| 
								 | 
							
											this._visibilityCache.clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Update Texture Matrix for Depth compare
							 | 
						||
| 
								 | 
							
											this.updateTextureMatrix();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Make non selected objects invisible, and draw only the selected objects, by comparing the depth buffer of non selected objects
							 | 
						||
| 
								 | 
							
											this.changeVisibilityOfNonSelectedObjects( false );
							 | 
						||
| 
								 | 
							
											this.renderScene.overrideMaterial = this.prepareMaskMaterial;
							 | 
						||
| 
								 | 
							
											this.prepareMaskMaterial.uniforms[ 'cameraNearFar' ].value.set( this.renderCamera.near, this.renderCamera.far );
							 | 
						||
| 
								 | 
							
											this.prepareMaskMaterial.uniforms[ 'depthTexture' ].value = this.renderTargetDepthBuffer.texture;
							 | 
						||
| 
								 | 
							
											this.prepareMaskMaterial.uniforms[ 'textureMatrix' ].value = this.textureMatrix;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetMaskBuffer );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											renderer.render( this.renderScene, this.renderCamera );
							 | 
						||
| 
								 | 
							
											this.renderScene.overrideMaterial = null;
							 | 
						||
| 
								 | 
							
											this.changeVisibilityOfNonSelectedObjects( true );
							 | 
						||
| 
								 | 
							
											this._visibilityCache.clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.renderScene.background = currentBackground;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// 2. Downsample to Half resolution
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.materialCopy;
							 | 
						||
| 
								 | 
							
											this.copyUniforms[ 'tDiffuse' ].value = this.renderTargetMaskBuffer.texture;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetMaskDownSampleBuffer );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.tempPulseColor1.copy( this.visibleEdgeColor );
							 | 
						||
| 
								 | 
							
											this.tempPulseColor2.copy( this.hiddenEdgeColor );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( this.pulsePeriod > 0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const scalar = ( 1 + 0.25 ) / 2 + Math.cos( performance.now() * 0.01 / this.pulsePeriod ) * ( 1.0 - 0.25 ) / 2;
							 | 
						||
| 
								 | 
							
												this.tempPulseColor1.multiplyScalar( scalar );
							 | 
						||
| 
								 | 
							
												this.tempPulseColor2.multiplyScalar( scalar );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// 3. Apply Edge Detection Pass
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.edgeDetectionMaterial;
							 | 
						||
| 
								 | 
							
											this.edgeDetectionMaterial.uniforms[ 'maskTexture' ].value = this.renderTargetMaskDownSampleBuffer.texture;
							 | 
						||
| 
								 | 
							
											this.edgeDetectionMaterial.uniforms[ 'texSize' ].value.set( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height );
							 | 
						||
| 
								 | 
							
											this.edgeDetectionMaterial.uniforms[ 'visibleEdgeColor' ].value = this.tempPulseColor1;
							 | 
						||
| 
								 | 
							
											this.edgeDetectionMaterial.uniforms[ 'hiddenEdgeColor' ].value = this.tempPulseColor2;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetEdgeBuffer1 );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// 4. Apply Blur on Half res
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.separableBlurMaterial1;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial1.uniforms[ 'colorTexture' ].value = this.renderTargetEdgeBuffer1.texture;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial1.uniforms[ 'direction' ].value = OutlinePass.BlurDirectionX;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial1.uniforms[ 'kernelRadius' ].value = this.edgeThickness;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetBlurBuffer1 );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial1.uniforms[ 'colorTexture' ].value = this.renderTargetBlurBuffer1.texture;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial1.uniforms[ 'direction' ].value = OutlinePass.BlurDirectionY;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetEdgeBuffer1 );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Apply Blur on quarter res
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.separableBlurMaterial2;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial2.uniforms[ 'colorTexture' ].value = this.renderTargetEdgeBuffer1.texture;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial2.uniforms[ 'direction' ].value = OutlinePass.BlurDirectionX;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetBlurBuffer2 );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial2.uniforms[ 'colorTexture' ].value = this.renderTargetBlurBuffer2.texture;
							 | 
						||
| 
								 | 
							
											this.separableBlurMaterial2.uniforms[ 'direction' ].value = OutlinePass.BlurDirectionY;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( this.renderTargetEdgeBuffer2 );
							 | 
						||
| 
								 | 
							
											renderer.clear();
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Blend it additively over the input texture
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.overlayMaterial;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'maskTexture' ].value = this.renderTargetMaskBuffer.texture;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'edgeTexture1' ].value = this.renderTargetEdgeBuffer1.texture;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'edgeTexture2' ].value = this.renderTargetEdgeBuffer2.texture;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'patternTexture' ].value = this.patternTexture;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'edgeStrength' ].value = this.edgeStrength;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'edgeGlow' ].value = this.edgeGlow;
							 | 
						||
| 
								 | 
							
											this.overlayMaterial.uniforms[ 'usePatternTexture' ].value = this.usePatternTexture;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( maskActive ) renderer.state.buffers.stencil.setTest( true );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( readBuffer );
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											renderer.setClearColor( this._oldClearColor, this.oldClearAlpha );
							 | 
						||
| 
								 | 
							
											renderer.autoClear = oldAutoClear;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( this.renderToScreen ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.fsQuad.material = this.materialCopy;
							 | 
						||
| 
								 | 
							
											this.copyUniforms[ 'tDiffuse' ].value = readBuffer.texture;
							 | 
						||
| 
								 | 
							
											renderer.setRenderTarget( null );
							 | 
						||
| 
								 | 
							
											this.fsQuad.render( renderer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getPrepareMaskMaterial() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniforms: {
							 | 
						||
| 
								 | 
							
												'depthTexture': { value: null },
							 | 
						||
| 
								 | 
							
												'cameraNearFar': { value: new Vector2( 0.5, 0.5 ) },
							 | 
						||
| 
								 | 
							
												'textureMatrix': { value: null }
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											vertexShader:
							 | 
						||
| 
								 | 
							
												`#include <morphtarget_pars_vertex>
							 | 
						||
| 
								 | 
							
												#include <skinning_pars_vertex>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												varying vec4 projTexCoord;
							 | 
						||
| 
								 | 
							
												varying vec4 vPosition;
							 | 
						||
| 
								 | 
							
												uniform mat4 textureMatrix;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													#include <skinbase_vertex>
							 | 
						||
| 
								 | 
							
													#include <begin_vertex>
							 | 
						||
| 
								 | 
							
													#include <morphtarget_vertex>
							 | 
						||
| 
								 | 
							
													#include <skinning_vertex>
							 | 
						||
| 
								 | 
							
													#include <project_vertex>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													vPosition = mvPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													vec4 worldPosition = vec4( transformed, 1.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													#ifdef USE_INSTANCING
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														worldPosition = instanceMatrix * worldPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													#endif
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
													worldPosition = modelMatrix * worldPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													projTexCoord = textureMatrix * worldPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}`,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fragmentShader:
							 | 
						||
| 
								 | 
							
												`#include <packing>
							 | 
						||
| 
								 | 
							
												varying vec4 vPosition;
							 | 
						||
| 
								 | 
							
												varying vec4 projTexCoord;
							 | 
						||
| 
								 | 
							
												uniform sampler2D depthTexture;
							 | 
						||
| 
								 | 
							
												uniform vec2 cameraNearFar;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													float depth = unpackRGBAToDepth(texture2DProj( depthTexture, projTexCoord ));
							 | 
						||
| 
								 | 
							
													float viewZ = - DEPTH_TO_VIEW_Z( depth, cameraNearFar.x, cameraNearFar.y );
							 | 
						||
| 
								 | 
							
													float depthTest = (-vPosition.z > viewZ) ? 1.0 : 0.0;
							 | 
						||
| 
								 | 
							
													gl_FragColor = vec4(0.0, depthTest, 1.0, 1.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getEdgeDetectionMaterial() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniforms: {
							 | 
						||
| 
								 | 
							
												'maskTexture': { value: null },
							 | 
						||
| 
								 | 
							
												'texSize': { value: new Vector2( 0.5, 0.5 ) },
							 | 
						||
| 
								 | 
							
												'visibleEdgeColor': { value: new Vector3( 1.0, 1.0, 1.0 ) },
							 | 
						||
| 
								 | 
							
												'hiddenEdgeColor': { value: new Vector3( 1.0, 1.0, 1.0 ) },
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											vertexShader:
							 | 
						||
| 
								 | 
							
												`varying vec2 vUv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vUv = uv;
							 | 
						||
| 
								 | 
							
													gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
							 | 
						||
| 
								 | 
							
												}`,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fragmentShader:
							 | 
						||
| 
								 | 
							
												`varying vec2 vUv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												uniform sampler2D maskTexture;
							 | 
						||
| 
								 | 
							
												uniform vec2 texSize;
							 | 
						||
| 
								 | 
							
												uniform vec3 visibleEdgeColor;
							 | 
						||
| 
								 | 
							
												uniform vec3 hiddenEdgeColor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vec2 invSize = 1.0 / texSize;
							 | 
						||
| 
								 | 
							
													vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize);
							 | 
						||
| 
								 | 
							
													vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);
							 | 
						||
| 
								 | 
							
													vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);
							 | 
						||
| 
								 | 
							
													vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);
							 | 
						||
| 
								 | 
							
													vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw);
							 | 
						||
| 
								 | 
							
													float diff1 = (c1.r - c2.r)*0.5;
							 | 
						||
| 
								 | 
							
													float diff2 = (c3.r - c4.r)*0.5;
							 | 
						||
| 
								 | 
							
													float d = length( vec2(diff1, diff2) );
							 | 
						||
| 
								 | 
							
													float a1 = min(c1.g, c2.g);
							 | 
						||
| 
								 | 
							
													float a2 = min(c3.g, c4.g);
							 | 
						||
| 
								 | 
							
													float visibilityFactor = min(a1, a2);
							 | 
						||
| 
								 | 
							
													vec3 edgeColor = 1.0 - visibilityFactor > 0.001 ? visibleEdgeColor : hiddenEdgeColor;
							 | 
						||
| 
								 | 
							
													gl_FragColor = vec4(edgeColor, 1.0) * vec4(d);
							 | 
						||
| 
								 | 
							
												}`
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getSeperableBlurMaterial( maxRadius ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											defines: {
							 | 
						||
| 
								 | 
							
												'MAX_RADIUS': maxRadius,
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniforms: {
							 | 
						||
| 
								 | 
							
												'colorTexture': { value: null },
							 | 
						||
| 
								 | 
							
												'texSize': { value: new Vector2( 0.5, 0.5 ) },
							 | 
						||
| 
								 | 
							
												'direction': { value: new Vector2( 0.5, 0.5 ) },
							 | 
						||
| 
								 | 
							
												'kernelRadius': { value: 1.0 }
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											vertexShader:
							 | 
						||
| 
								 | 
							
												`varying vec2 vUv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vUv = uv;
							 | 
						||
| 
								 | 
							
													gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
							 | 
						||
| 
								 | 
							
												}`,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fragmentShader:
							 | 
						||
| 
								 | 
							
												`#include <common>
							 | 
						||
| 
								 | 
							
												varying vec2 vUv;
							 | 
						||
| 
								 | 
							
												uniform sampler2D colorTexture;
							 | 
						||
| 
								 | 
							
												uniform vec2 texSize;
							 | 
						||
| 
								 | 
							
												uniform vec2 direction;
							 | 
						||
| 
								 | 
							
												uniform float kernelRadius;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												float gaussianPdf(in float x, in float sigma) {
							 | 
						||
| 
								 | 
							
													return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vec2 invSize = 1.0 / texSize;
							 | 
						||
| 
								 | 
							
													float sigma = kernelRadius/2.0;
							 | 
						||
| 
								 | 
							
													float weightSum = gaussianPdf(0.0, sigma);
							 | 
						||
| 
								 | 
							
													vec4 diffuseSum = texture2D( colorTexture, vUv) * weightSum;
							 | 
						||
| 
								 | 
							
													vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);
							 | 
						||
| 
								 | 
							
													vec2 uvOffset = delta;
							 | 
						||
| 
								 | 
							
													for( int i = 1; i <= MAX_RADIUS; i ++ ) {
							 | 
						||
| 
								 | 
							
														float x = kernelRadius * float(i) / float(MAX_RADIUS);
							 | 
						||
| 
								 | 
							
														float w = gaussianPdf(x, sigma);
							 | 
						||
| 
								 | 
							
														vec4 sample1 = texture2D( colorTexture, vUv + uvOffset);
							 | 
						||
| 
								 | 
							
														vec4 sample2 = texture2D( colorTexture, vUv - uvOffset);
							 | 
						||
| 
								 | 
							
														diffuseSum += ((sample1 + sample2) * w);
							 | 
						||
| 
								 | 
							
														weightSum += (2.0 * w);
							 | 
						||
| 
								 | 
							
														uvOffset += delta;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													gl_FragColor = diffuseSum/weightSum;
							 | 
						||
| 
								 | 
							
												}`
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getOverlayMaterial() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniforms: {
							 | 
						||
| 
								 | 
							
												'maskTexture': { value: null },
							 | 
						||
| 
								 | 
							
												'edgeTexture1': { value: null },
							 | 
						||
| 
								 | 
							
												'edgeTexture2': { value: null },
							 | 
						||
| 
								 | 
							
												'patternTexture': { value: null },
							 | 
						||
| 
								 | 
							
												'edgeStrength': { value: 1.0 },
							 | 
						||
| 
								 | 
							
												'edgeGlow': { value: 1.0 },
							 | 
						||
| 
								 | 
							
												'usePatternTexture': { value: 0.0 }
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											vertexShader:
							 | 
						||
| 
								 | 
							
												`varying vec2 vUv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vUv = uv;
							 | 
						||
| 
								 | 
							
													gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
							 | 
						||
| 
								 | 
							
												}`,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fragmentShader:
							 | 
						||
| 
								 | 
							
												`varying vec2 vUv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												uniform sampler2D maskTexture;
							 | 
						||
| 
								 | 
							
												uniform sampler2D edgeTexture1;
							 | 
						||
| 
								 | 
							
												uniform sampler2D edgeTexture2;
							 | 
						||
| 
								 | 
							
												uniform sampler2D patternTexture;
							 | 
						||
| 
								 | 
							
												uniform float edgeStrength;
							 | 
						||
| 
								 | 
							
												uniform float edgeGlow;
							 | 
						||
| 
								 | 
							
												uniform bool usePatternTexture;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												void main() {
							 | 
						||
| 
								 | 
							
													vec4 edgeValue1 = texture2D(edgeTexture1, vUv);
							 | 
						||
| 
								 | 
							
													vec4 edgeValue2 = texture2D(edgeTexture2, vUv);
							 | 
						||
| 
								 | 
							
													vec4 maskColor = texture2D(maskTexture, vUv);
							 | 
						||
| 
								 | 
							
													vec4 patternColor = texture2D(patternTexture, 6.0 * vUv);
							 | 
						||
| 
								 | 
							
													float visibilityFactor = 1.0 - maskColor.g > 0.0 ? 1.0 : 0.5;
							 | 
						||
| 
								 | 
							
													vec4 edgeValue = edgeValue1 + edgeValue2 * edgeGlow;
							 | 
						||
| 
								 | 
							
													vec4 finalColor = edgeStrength * maskColor.r * edgeValue;
							 | 
						||
| 
								 | 
							
													if(usePatternTexture)
							 | 
						||
| 
								 | 
							
														finalColor += + visibilityFactor * (1.0 - maskColor.r) * (1.0 - patternColor.r);
							 | 
						||
| 
								 | 
							
													gl_FragColor = finalColor;
							 | 
						||
| 
								 | 
							
												}`,
							 | 
						||
| 
								 | 
							
											blending: AdditiveBlending,
							 | 
						||
| 
								 | 
							
											depthTest: false,
							 | 
						||
| 
								 | 
							
											depthWrite: false,
							 | 
						||
| 
								 | 
							
											transparent: true
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								OutlinePass.BlurDirectionX = new Vector2( 1.0, 0.0 );
							 | 
						||
| 
								 | 
							
								OutlinePass.BlurDirectionY = new Vector2( 0.0, 1.0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { OutlinePass };
							 |