constructor( resolution, scene, camera, selectedObjects ) {

		super();

		/**
		 * The scene to render.
		 *
		 * @type {Object}
		 */
		this.renderScene = scene;

		/**
		 * The camera.
		 *
		 * @type {Object}
		 */
		this.renderCamera = camera;

		/**
		 * The selected 3D objects that should receive an outline.
		 *
		 * @type {Array<Object3D>}
		 */
		this.selectedObjects = selectedObjects !== undefined ? selectedObjects : [];

		/**
		 * The visible edge color.
		 *
		 * @type {Color}
		 * @default (1,1,1)
		 */
		this.visibleEdgeColor = new Color( 1, 1, 1 );

		/**
		 * The hidden edge color.
		 *
		 * @type {Color}
		 * @default (0.1,0.04,0.02)
		 */
		this.hiddenEdgeColor = new Color( 0.1, 0.04, 0.02 );

		/**
		 * Can be used for an animated glow/pulse effect.
		 *
		 * @type {number}
		 * @default 0
		 */
		this.edgeGlow = 0.0;

		/**
		 * Whether to use a pattern texture for to highlight selected
		 * 3D objects or not.
		 *
		 * @type {boolean}
		 * @default false
		 */
		this.usePatternTexture = false;

		/**
		 * Can be used to highlight selected 3D objects. Requires to set
		 * {@link OutlinePass#usePatternTexture} to `true`.
		 *
		 * @type {?Texture}
		 * @default null
		 */
		this.patternTexture = null;

		/**
		 * The edge thickness.
		 *
		 * @type {number}
		 * @default 1
		 */
		this.edgeThickness = 1.0;

		/**
		 * The edge strength.
		 *
		 * @type {number}
		 * @default 3
		 */
		this.edgeStrength = 3.0;

		/**
		 * The downsample ratio. The effect can be rendered in a much
		 * lower resolution than the beauty pass.
		 *
		 * @type {number}
		 * @default 2
		 */
		this.downSampleRatio = 2;

		/**
		 * The pulse period.
		 *
		 * @type {number}
		 * @default 0
		 */
		this.pulsePeriod = 0;

		this._visibilityCache = new Map();
		this._selectionCache = new Set();

		/**
		 * The effect's resolution.
		 *
		 * @type {Vector2}
		 * @default (256,256)
		 */
		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._getSeparableBlurMaterial( MAX_EDGE_THICKNESS );
		this.separableBlurMaterial1.uniforms[ 'texSize' ].value.set( resx, resy );
		this.separableBlurMaterial1.uniforms[ 'kernelRadius' ].value = 1;
		this.separableBlurMaterial2 = this._getSeparableBlurMaterial( 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' );

		}

	}
Constructs a new outline pass.

@param {Vector2} [resolution] - The effect's resolution.
@param {Scene} scene - The scene to render.
@param {Camera} camera - The camera.
@param {Array<Object3D>} [selectedObjects] - The selected 3D objects that should receive an outline.