Browse Source

Merge pull request #16535 from Mugen87/dev30

JSM: More modules and TS files for FX-passes.
Michael Herzog 6 years ago
parent
commit
f835df72ce
30 changed files with 1347 additions and 27 deletions
  1. 9 0
      docs/manual/en/introduction/Import-via-modules.html
  2. 2 2
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  3. 4 6
      examples/js/postprocessing/BokehPass.js
  4. 1 1
      examples/js/postprocessing/CubeTexturePass.js
  5. 1 1
      examples/js/postprocessing/GlitchPass.js
  6. 1 1
      examples/js/postprocessing/HalftonePass.js
  7. 5 5
      examples/js/shaders/ToneMapShader.js
  8. 2 2
      examples/js/shaders/TriangleBlurShader.js
  9. 1 0
      examples/jsm/controls/TransformControls.js
  10. 1 1
      examples/jsm/loaders/GLTFLoader.js
  11. 32 0
      examples/jsm/postprocessing/AdaptiveToneMappingPass.d.ts
  12. 365 0
      examples/jsm/postprocessing/AdaptiveToneMappingPass.js
  13. 17 0
      examples/jsm/postprocessing/AfterimagePass.d.ts
  14. 107 0
      examples/jsm/postprocessing/AfterimagePass.js
  15. 32 0
      examples/jsm/postprocessing/BokehPass.d.ts
  16. 137 0
      examples/jsm/postprocessing/BokehPass.js
  17. 19 0
      examples/jsm/postprocessing/CubeTexturePass.d.ts
  18. 72 0
      examples/jsm/postprocessing/CubeTexturePass.js
  19. 19 0
      examples/jsm/postprocessing/GlitchPass.d.ts
  20. 126 0
      examples/jsm/postprocessing/GlitchPass.js
  21. 25 0
      examples/jsm/postprocessing/HalftonePass.d.ts
  22. 81 0
      examples/jsm/postprocessing/HalftonePass.js
  23. 15 0
      examples/jsm/postprocessing/SavePass.d.ts
  24. 71 0
      examples/jsm/postprocessing/SavePass.js
  25. 16 0
      examples/jsm/shaders/ToneMapShader.d.ts
  26. 81 0
      examples/jsm/shaders/ToneMapShader.js
  27. 12 0
      examples/jsm/shaders/TriangleBlurShader.d.ts
  28. 78 0
      examples/jsm/shaders/TriangleBlurShader.js
  29. 5 7
      examples/jsm/utils/SceneUtils.js
  30. 10 1
      utils/modularize.js

+ 9 - 0
docs/manual/en/introduction/Import-via-modules.html

@@ -158,13 +158,20 @@
 				</li>
 				<li>postprocessing
 					<ul>
+						<li>AdaptiveToneMappingPass</li>
+						<li>AfterimagePass</li>
 						<li>BloomPass</li>
+						<li>BokehPass</li>
 						<li>ClearPass</li>
+						<li>CubeTexturePass</li>
 						<li>DotScreenPass</li>
 						<li>EffectComposer</li>
 						<li>FilmPass</li>
+						<li>GlitchPass</li>
+						<li>HalftonePass</li>
 						<li>MaskPass</li>
 						<li>RenderPass</li>
+						<li>SavePass</li>
 						<li>ShaderPass</li>
 						<li>TexturePass</li>
 					</ul>
@@ -219,6 +226,8 @@
 						<li>SobelOperatorShader</li>
 						<li>SSAOShader</li>
 						<li>TechnicolorShader</li>
+						<li>ToneMapShader</li>
+						<li>TriangleBlurShader</li>
 						<li>UnpackDepthRGBAShader</li>
 						<li>VerticalBlurShader</li>
 						<li>VerticalTiltShiftShader</li>

+ 2 - 2
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -125,7 +125,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	constructor: THREE.AdaptiveToneMappingPass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer, deltaTime/*, maskActive*/ ) {
 
 		if ( this.needsInit ) {
 
@@ -183,7 +183,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	reset: function ( renderer ) {
+	reset: function () {
 
 		// render targets
 		if ( this.luminanceRT ) {

+ 4 - 6
examples/js/postprocessing/BokehPass.js

@@ -2,7 +2,6 @@
  * Depth-of-field post-process with bokeh shader
  */
 
-
 THREE.BokehPass = function ( scene, camera, params ) {
 
 	THREE.Pass.call( this );
@@ -69,7 +68,6 @@ THREE.BokehPass = function ( scene, camera, params ) {
 	this.fsQuad = new THREE.Pass.FullScreenQuad( this.materialBokeh );
 
 	this.oldClearColor = new THREE.Color();
-	this.oldClearAlpha = 1;
 
 };
 
@@ -77,14 +75,14 @@ THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 
 	constructor: THREE.BokehPass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
 
 		// Render depth into texture
 
 		this.scene.overrideMaterial = this.materialDepth;
 
 		this.oldClearColor.copy( renderer.getClearColor() );
-		this.oldClearAlpha = renderer.getClearAlpha();
+		var oldClearAlpha = renderer.getClearAlpha();
 		var oldAutoClear = renderer.autoClear;
 		renderer.autoClear = false;
 
@@ -115,8 +113,8 @@ THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 
 		this.scene.overrideMaterial = null;
 		renderer.setClearColor( this.oldClearColor );
-		renderer.setClearAlpha( this.oldClearAlpha );
-		renderer.autoClear = this.oldAutoClear;
+		renderer.setClearAlpha( oldClearAlpha );
+		renderer.autoClear = oldAutoClear;
 
 	}
 

+ 1 - 1
examples/js/postprocessing/CubeTexturePass.js

@@ -36,7 +36,7 @@ THREE.CubeTexturePass.prototype = Object.assign( Object.create( THREE.Pass.proto
 
 	constructor: THREE.CubeTexturePass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
 
 		var oldAutoClear = renderer.autoClear;
 		renderer.autoClear = false;

+ 1 - 1
examples/js/postprocessing/GlitchPass.js

@@ -35,7 +35,7 @@ THREE.GlitchPass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 
 	constructor: THREE.GlitchPass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
 
 		this.uniforms[ "tDiffuse" ].value = readBuffer.texture;
 		this.uniforms[ 'seed' ].value = Math.random();//default seeding

+ 1 - 1
examples/js/postprocessing/HalftonePass.js

@@ -44,7 +44,7 @@ THREE.HalftonePass.prototype = Object.assign( Object.create( THREE.Pass.prototyp
 
 	constructor: THREE.HalftonePass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
 
  		this.material.uniforms[ "tDiffuse" ].value = readBuffer.texture;
 

+ 5 - 5
examples/js/shaders/ToneMapShader.js

@@ -9,11 +9,11 @@ THREE.ToneMapShader = {
 	uniforms: {
 
 		"tDiffuse": { value: null },
-		"averageLuminance":  { value: 1.0 },
-		"luminanceMap":  { value: null },
-		"maxLuminance":  { value: 16.0 },
-		"minLuminance":  { value: 0.01 },
-		"middleGrey":  { value: 0.6 }
+		"averageLuminance": { value: 1.0 },
+		"luminanceMap": { value: null },
+		"maxLuminance": { value: 16.0 },
+		"minLuminance": { value: 0.01 },
+		"middleGrey": { value: 0.6 }
 	},
 
 	vertexShader: [

+ 2 - 2
examples/js/shaders/TriangleBlurShader.js

@@ -12,10 +12,10 @@
 
 THREE.TriangleBlurShader = {
 
-	uniforms : {
+	uniforms: {
 
 		"texture": { value: null },
-		"delta":   { value: new THREE.Vector2( 1, 1 ) }
+		"delta": { value: new THREE.Vector2( 1, 1 ) }
 
 	},
 

+ 1 - 0
examples/jsm/controls/TransformControls.js

@@ -144,6 +144,7 @@ var TransformControls = function ( camera, domElement ) {
 		domElement.removeEventListener( "mousedown", onPointerDown );
 		domElement.removeEventListener( "touchstart", onPointerDown );
 		domElement.removeEventListener( "mousemove", onPointerHover );
+		document.removeEventListener( "mousemove", onPointerMove );
 		domElement.removeEventListener( "touchmove", onPointerHover );
 		domElement.removeEventListener( "touchmove", onPointerMove );
 		document.removeEventListener( "mouseup", onPointerUp );

+ 1 - 1
examples/jsm/loaders/GLTFLoader.js

@@ -934,7 +934,7 @@ var GLTFLoader = ( function () {
 				for ( var i = 0, il = params.length; i < il; i ++ ) {
 
 					var value = source[ params[ i ] ];
-					target[ params[ i ] ] = value.isColor ? value.clone() : value;
+					target[ params[ i ] ] = ( value && value.isColor ) ? value.clone() : value;
 
 				}
 

+ 32 - 0
examples/jsm/postprocessing/AdaptiveToneMappingPass.d.ts

@@ -0,0 +1,32 @@
+import {
+  WebGLRenderTarget,
+  ShaderMaterial
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class AdaptiveToneMappingPass extends Pass {
+  constructor(adaptive?: boolean, resolution?: number);
+  adaptive: boolean;
+  resolution: number;
+  needsInit: number;
+  luminanceRT: WebGLRenderTarget;
+  previousLuminanceRT: WebGLRenderTarget;
+  currentLuminanceRT: WebGLRenderTarget;
+  copyUniforms: object;
+  materialCopy: ShaderMaterial;
+  materialLuminance: ShaderMaterial;
+  adaptLuminanceShader: object;
+  materialAdaptiveLum: ShaderMaterial;
+  materialToneMap: ShaderMaterial;
+  fsQuad: object;
+
+  reset(): void;
+  setAdaptive(adaptive: boolean): void;
+  setAdaptionRate(rate: number): void;
+  setMinLuminance(minLum: number): void;
+  setMaxLuminance(maxLum: number): void;
+  setAverageLuminance(avgLum: number): void;
+  setMiddleGrey(middleGrey: number): void;
+  dispose(): void;
+}

+ 365 - 0
examples/jsm/postprocessing/AdaptiveToneMappingPass.js

@@ -0,0 +1,365 @@
+/**
+ * @author miibond
+ * Generate a texture that represents the luminosity of the current scene, adapted over time
+ * to simulate the optic nerve responding to the amount of light it is receiving.
+ * Based on a GDC2007 presentation by Wolfgang Engel titled "Post-Processing Pipeline"
+ *
+ * Full-screen tone-mapping shader based on http://www.graphics.cornell.edu/~jaf/publications/sig02_paper.pdf
+ */
+
+import {
+	LinearFilter,
+	LinearMipMapLinearFilter,
+	MeshBasicMaterial,
+	NoBlending,
+	RGBAFormat,
+	ShaderMaterial,
+	UniformsUtils,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { CopyShader } from "../shaders/CopyShader.js";
+import { LuminosityShader } from "../shaders/LuminosityShader.js";
+import { ToneMapShader } from "../shaders/ToneMapShader.js";
+
+var AdaptiveToneMappingPass = function ( adaptive, resolution ) {
+
+	Pass.call( this );
+
+	this.resolution = ( resolution !== undefined ) ? resolution : 256;
+	this.needsInit = true;
+	this.adaptive = adaptive !== undefined ? !! adaptive : true;
+
+	this.luminanceRT = null;
+	this.previousLuminanceRT = null;
+	this.currentLuminanceRT = null;
+
+	if ( CopyShader === undefined )
+		console.error( "AdaptiveToneMappingPass relies on CopyShader" );
+
+	var 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
+
+	} );
+
+	if ( LuminosityShader === undefined )
+		console.error( "AdaptiveToneMappingPass relies on LuminosityShader" );
+
+	this.materialLuminance = new ShaderMaterial( {
+
+		uniforms: UniformsUtils.clone( LuminosityShader.uniforms ),
+		vertexShader: LuminosityShader.vertexShader,
+		fragmentShader: LuminosityShader.fragmentShader,
+		blending: NoBlending
+	} );
+
+	this.adaptLuminanceShader = {
+		defines: {
+			"MIP_LEVEL_1X1": ( Math.log( this.resolution ) / Math.log( 2.0 ) ).toFixed( 1 )
+		},
+		uniforms: {
+			"lastLum": { value: null },
+			"currentLum": { value: null },
+			"minLuminance": { value: 0.01 },
+			"delta": { value: 0.016 },
+			"tau": { value: 1.0 }
+		},
+		vertexShader: [
+			"varying vec2 vUv;",
+
+			"void main() {",
+
+			"	vUv = uv;",
+			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+		].join( '\n' ),
+		fragmentShader: [
+			"varying vec2 vUv;",
+
+			"uniform sampler2D lastLum;",
+			"uniform sampler2D currentLum;",
+			"uniform float minLuminance;",
+			"uniform float delta;",
+			"uniform float tau;",
+
+			"void main() {",
+
+			"	vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
+			"	vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
+
+			"	float fLastLum = max( minLuminance, lastLum.r );",
+			"	float fCurrentLum = max( minLuminance, currentLum.r );",
+
+			//The adaption seems to work better in extreme lighting differences
+			//if the input luminance is squared.
+			"	fCurrentLum *= fCurrentLum;",
+
+			// Adapt the luminance using Pattanaik's technique
+			"	float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau));",
+			// "fAdaptedLum = sqrt(fAdaptedLum);",
+			"	gl_FragColor.r = fAdaptedLum;",
+			"}"
+		].join( '\n' )
+	};
+
+	this.materialAdaptiveLum = new ShaderMaterial( {
+
+		uniforms: UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
+		vertexShader: this.adaptLuminanceShader.vertexShader,
+		fragmentShader: this.adaptLuminanceShader.fragmentShader,
+		defines: Object.assign( {}, this.adaptLuminanceShader.defines ),
+		blending: NoBlending
+	} );
+
+	if ( ToneMapShader === undefined )
+		console.error( "AdaptiveToneMappingPass relies on ToneMapShader" );
+
+	this.materialToneMap = new ShaderMaterial( {
+
+		uniforms: UniformsUtils.clone( ToneMapShader.uniforms ),
+		vertexShader: ToneMapShader.vertexShader,
+		fragmentShader: ToneMapShader.fragmentShader,
+		blending: NoBlending
+	} );
+
+	this.fsQuad = new Pass.FullScreenQuad( null );
+
+};
+
+AdaptiveToneMappingPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: AdaptiveToneMappingPass,
+
+	render: function ( renderer, writeBuffer, readBuffer, deltaTime/*, maskActive*/ ) {
+
+		if ( this.needsInit ) {
+
+			this.reset( renderer );
+
+			this.luminanceRT.texture.type = readBuffer.texture.type;
+			this.previousLuminanceRT.texture.type = readBuffer.texture.type;
+			this.currentLuminanceRT.texture.type = readBuffer.texture.type;
+			this.needsInit = false;
+
+		}
+
+		if ( this.adaptive ) {
+
+			//Render the luminance of the current scene into a render target with mipmapping enabled
+			this.fsQuad.material = this.materialLuminance;
+			this.materialLuminance.uniforms.tDiffuse.value = readBuffer.texture;
+			renderer.setRenderTarget( this.currentLuminanceRT );
+			this.fsQuad.render( renderer );
+
+			//Use the new luminance values, the previous luminance and the frame delta to
+			//adapt the luminance over time.
+			this.fsQuad.material = this.materialAdaptiveLum;
+			this.materialAdaptiveLum.uniforms.delta.value = deltaTime;
+			this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.texture;
+			this.materialAdaptiveLum.uniforms.currentLum.value = this.currentLuminanceRT.texture;
+			renderer.setRenderTarget( this.luminanceRT );
+			this.fsQuad.render( renderer );
+
+			//Copy the new adapted luminance value so that it can be used by the next frame.
+			this.fsQuad.material = this.materialCopy;
+			this.copyUniforms.tDiffuse.value = this.luminanceRT.texture;
+			renderer.setRenderTarget( this.previousLuminanceRT );
+			this.fsQuad.render( renderer );
+
+		}
+
+		this.fsQuad.material = this.materialToneMap;
+		this.materialToneMap.uniforms.tDiffuse.value = readBuffer.texture;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.fsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			this.fsQuad.render( renderer );
+
+		}
+
+	},
+
+	reset: function () {
+
+		// render targets
+		if ( this.luminanceRT ) {
+
+			this.luminanceRT.dispose();
+
+		}
+		if ( this.currentLuminanceRT ) {
+
+			this.currentLuminanceRT.dispose();
+
+		}
+		if ( this.previousLuminanceRT ) {
+
+			this.previousLuminanceRT.dispose();
+
+		}
+
+		var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat }; // was RGB format. changed to RGBA format. see discussion in #8415 / #8450
+
+		this.luminanceRT = new WebGLRenderTarget( this.resolution, this.resolution, pars );
+		this.luminanceRT.texture.name = "AdaptiveToneMappingPass.l";
+		this.luminanceRT.texture.generateMipmaps = false;
+
+		this.previousLuminanceRT = new WebGLRenderTarget( this.resolution, this.resolution, pars );
+		this.previousLuminanceRT.texture.name = "AdaptiveToneMappingPass.pl";
+		this.previousLuminanceRT.texture.generateMipmaps = false;
+
+		// We only need mipmapping for the current luminosity because we want a down-sampled version to sample in our adaptive shader
+		pars.minFilter = LinearMipMapLinearFilter;
+		pars.generateMipmaps = true;
+		this.currentLuminanceRT = new WebGLRenderTarget( this.resolution, this.resolution, pars );
+		this.currentLuminanceRT.texture.name = "AdaptiveToneMappingPass.cl";
+
+		if ( this.adaptive ) {
+
+			this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ] = "";
+			this.materialToneMap.uniforms.luminanceMap.value = this.luminanceRT.texture;
+
+		}
+		//Put something in the adaptive luminance texture so that the scene can render initially
+		this.fsQuad.material = new MeshBasicMaterial( { color: 0x777777 } );
+		this.materialLuminance.needsUpdate = true;
+		this.materialAdaptiveLum.needsUpdate = true;
+		this.materialToneMap.needsUpdate = true;
+		// renderer.render( this.scene, this.camera, this.luminanceRT );
+		// renderer.render( this.scene, this.camera, this.previousLuminanceRT );
+		// renderer.render( this.scene, this.camera, this.currentLuminanceRT );
+
+	},
+
+	setAdaptive: function ( adaptive ) {
+
+		if ( adaptive ) {
+
+			this.adaptive = true;
+			this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ] = "";
+			this.materialToneMap.uniforms.luminanceMap.value = this.luminanceRT.texture;
+
+		} else {
+
+			this.adaptive = false;
+			delete this.materialToneMap.defines[ "ADAPTED_LUMINANCE" ];
+			this.materialToneMap.uniforms.luminanceMap.value = null;
+
+		}
+		this.materialToneMap.needsUpdate = true;
+
+	},
+
+	setAdaptionRate: function ( rate ) {
+
+		if ( rate ) {
+
+			this.materialAdaptiveLum.uniforms.tau.value = Math.abs( rate );
+
+		}
+
+	},
+
+	setMinLuminance: function ( minLum ) {
+
+		if ( minLum ) {
+
+			this.materialToneMap.uniforms.minLuminance.value = minLum;
+			this.materialAdaptiveLum.uniforms.minLuminance.value = minLum;
+
+		}
+
+	},
+
+	setMaxLuminance: function ( maxLum ) {
+
+		if ( maxLum ) {
+
+			this.materialToneMap.uniforms.maxLuminance.value = maxLum;
+
+		}
+
+	},
+
+	setAverageLuminance: function ( avgLum ) {
+
+		if ( avgLum ) {
+
+			this.materialToneMap.uniforms.averageLuminance.value = avgLum;
+
+		}
+
+	},
+
+	setMiddleGrey: function ( middleGrey ) {
+
+		if ( middleGrey ) {
+
+			this.materialToneMap.uniforms.middleGrey.value = middleGrey;
+
+		}
+
+	},
+
+	dispose: function () {
+
+		if ( this.luminanceRT ) {
+
+			this.luminanceRT.dispose();
+
+		}
+		if ( this.previousLuminanceRT ) {
+
+			this.previousLuminanceRT.dispose();
+
+		}
+		if ( this.currentLuminanceRT ) {
+
+			this.currentLuminanceRT.dispose();
+
+		}
+		if ( this.materialLuminance ) {
+
+			this.materialLuminance.dispose();
+
+		}
+		if ( this.materialAdaptiveLum ) {
+
+			this.materialAdaptiveLum.dispose();
+
+		}
+		if ( this.materialCopy ) {
+
+			this.materialCopy.dispose();
+
+		}
+		if ( this.materialToneMap ) {
+
+			this.materialToneMap.dispose();
+
+		}
+
+	}
+
+} );
+
+export { AdaptiveToneMappingPass };

+ 17 - 0
examples/jsm/postprocessing/AfterimagePass.d.ts

@@ -0,0 +1,17 @@
+import {
+  WebGLRenderTarget,
+  ShaderMaterial
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class AfterimagePass extends Pass {
+  constructor(damp?: number);
+  shader: object;
+  uniforms: object;
+  textureComp: WebGLRenderTarget;
+  textureOld: WebGLRenderTarget;
+  shaderMaterial: ShaderMaterial;
+  compFsQuad: object;
+  copyFsQuad: object;
+}

+ 107 - 0
examples/jsm/postprocessing/AfterimagePass.js

@@ -0,0 +1,107 @@
+/**
+ * @author HypnosNova / https://www.threejs.org.cn/gallery/
+ */
+
+import {
+	LinearFilter,
+	MeshBasicMaterial,
+	NearestFilter,
+	RGBAFormat,
+	ShaderMaterial,
+	UniformsUtils,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { AfterimageShader } from "../shaders/AfterimageShader.js";
+
+var AfterimagePass = function ( damp ) {
+
+	Pass.call( this );
+
+	if ( AfterimageShader === undefined )
+		console.error( "AfterimagePass relies on AfterimageShader" );
+
+	this.shader = AfterimageShader;
+
+	this.uniforms = UniformsUtils.clone( this.shader.uniforms );
+
+	this.uniforms[ "damp" ].value = damp !== undefined ? damp : 0.96;
+
+	this.textureComp = new WebGLRenderTarget( window.innerWidth, window.innerHeight, {
+
+		minFilter: LinearFilter,
+		magFilter: NearestFilter,
+		format: RGBAFormat
+
+	} );
+
+	this.textureOld = new WebGLRenderTarget( window.innerWidth, window.innerHeight, {
+
+		minFilter: LinearFilter,
+		magFilter: NearestFilter,
+		format: RGBAFormat
+
+	} );
+
+	this.shaderMaterial = new ShaderMaterial( {
+
+		uniforms: this.uniforms,
+		vertexShader: this.shader.vertexShader,
+		fragmentShader: this.shader.fragmentShader
+
+	} );
+
+	this.compFsQuad = new Pass.FullScreenQuad( this.shaderMaterial );
+
+	var material = new MeshBasicMaterial();
+	this.copyFsQuad = new Pass.FullScreenQuad( material );
+
+};
+
+AfterimagePass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: AfterimagePass,
+
+	render: function ( renderer, writeBuffer, readBuffer ) {
+
+		this.uniforms[ "tOld" ].value = this.textureOld.texture;
+		this.uniforms[ "tNew" ].value = readBuffer.texture;
+
+		renderer.setRenderTarget( this.textureComp );
+		this.compFsQuad.render( renderer );
+
+		this.copyFsQuad.material.map = this.textureComp.texture;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.copyFsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			this.copyFsQuad.render( renderer );
+
+		}
+
+		// Swap buffers.
+		var temp = this.textureOld;
+		this.textureOld = this.textureComp;
+		this.textureComp = temp;
+		// Now textureOld contains the latest image, ready for the next frame.
+
+	},
+
+	setSize: function ( width, height ) {
+
+		this.textureComp.setSize( width, height );
+		this.textureOld.setSize( width, height );
+
+	}
+
+} );
+
+export { AfterimagePass };

+ 32 - 0
examples/jsm/postprocessing/BokehPass.d.ts

@@ -0,0 +1,32 @@
+import {
+  Scene,
+  Camera,
+  ShaderMaterial,
+  WebGLRenderTarget,
+  MeshDepthMaterial,
+  Color
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export interface BokehPassParamters {
+  focus?: number;
+  aspect?: number;
+  aperture?: number;
+  maxblur?: number;
+  width?: number;
+  height?: number;
+}
+
+export class BokehPass extends Pass {
+  constructor(scene: Scene, camera: Camera, params: BokehPassParamters);
+  scene: Scene;
+  camera: Camera;
+  renderTargetColor: WebGLRenderTarget;
+  renderTargetDepth: WebGLRenderTarget;
+  materialDepth: MeshDepthMaterial;
+  materialBokeh: ShaderMaterial;
+  uniforms: object;
+  fsQuad: object;
+  oldClearColor: Color;
+}

+ 137 - 0
examples/jsm/postprocessing/BokehPass.js

@@ -0,0 +1,137 @@
+/**
+ * Depth-of-field post-process with bokeh shader
+ */
+
+import {
+	Color,
+	LinearFilter,
+	MeshDepthMaterial,
+	NoBlending,
+	RGBADepthPacking,
+	RGBFormat,
+	ShaderMaterial,
+	UniformsUtils,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { BokehShader } from "../shaders/BokehShader.js";
+
+var BokehPass = function ( scene, camera, params ) {
+
+	Pass.call( this );
+
+	this.scene = scene;
+	this.camera = camera;
+
+	var focus = ( params.focus !== undefined ) ? params.focus : 1.0;
+	var aspect = ( params.aspect !== undefined ) ? params.aspect : camera.aspect;
+	var aperture = ( params.aperture !== undefined ) ? params.aperture : 0.025;
+	var maxblur = ( params.maxblur !== undefined ) ? params.maxblur : 1.0;
+
+	// render targets
+
+	var width = params.width || window.innerWidth || 1;
+	var height = params.height || window.innerHeight || 1;
+
+	this.renderTargetColor = new WebGLRenderTarget( width, height, {
+		minFilter: LinearFilter,
+		magFilter: LinearFilter,
+		format: RGBFormat
+	} );
+	this.renderTargetColor.texture.name = "BokehPass.color";
+
+	this.renderTargetDepth = this.renderTargetColor.clone();
+	this.renderTargetDepth.texture.name = "BokehPass.depth";
+
+	// depth material
+
+	this.materialDepth = new MeshDepthMaterial();
+	this.materialDepth.depthPacking = RGBADepthPacking;
+	this.materialDepth.blending = NoBlending;
+
+	// bokeh material
+
+	if ( BokehShader === undefined ) {
+
+		console.error( "BokehPass relies on BokehShader" );
+
+	}
+
+	var bokehShader = BokehShader;
+	var bokehUniforms = UniformsUtils.clone( bokehShader.uniforms );
+
+	bokehUniforms[ "tDepth" ].value = this.renderTargetDepth.texture;
+
+	bokehUniforms[ "focus" ].value = focus;
+	bokehUniforms[ "aspect" ].value = aspect;
+	bokehUniforms[ "aperture" ].value = aperture;
+	bokehUniforms[ "maxblur" ].value = maxblur;
+	bokehUniforms[ "nearClip" ].value = camera.near;
+	bokehUniforms[ "farClip" ].value = camera.far;
+
+	this.materialBokeh = new ShaderMaterial( {
+		defines: Object.assign( {}, bokehShader.defines ),
+		uniforms: bokehUniforms,
+		vertexShader: bokehShader.vertexShader,
+		fragmentShader: bokehShader.fragmentShader
+	} );
+
+	this.uniforms = bokehUniforms;
+	this.needsSwap = false;
+
+	this.fsQuad = new Pass.FullScreenQuad( this.materialBokeh );
+
+	this.oldClearColor = new Color();
+
+};
+
+BokehPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: BokehPass,
+
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
+
+		// Render depth into texture
+
+		this.scene.overrideMaterial = this.materialDepth;
+
+		this.oldClearColor.copy( renderer.getClearColor() );
+		var oldClearAlpha = renderer.getClearAlpha();
+		var oldAutoClear = renderer.autoClear;
+		renderer.autoClear = false;
+
+		renderer.setClearColor( 0xffffff );
+		renderer.setClearAlpha( 1.0 );
+		renderer.setRenderTarget( this.renderTargetDepth );
+		renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		// Render bokeh composite
+
+		this.uniforms[ "tColor" ].value = readBuffer.texture;
+		this.uniforms[ "nearClip" ].value = this.camera.near;
+		this.uniforms[ "farClip" ].value = this.camera.far;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.fsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+			renderer.clear();
+			this.fsQuad.render( renderer );
+
+		}
+
+		this.scene.overrideMaterial = null;
+		renderer.setClearColor( this.oldClearColor );
+		renderer.setClearAlpha( oldClearAlpha );
+		renderer.autoClear = oldAutoClear;
+
+	}
+
+} );
+
+export { BokehPass };

+ 19 - 0
examples/jsm/postprocessing/CubeTexturePass.d.ts

@@ -0,0 +1,19 @@
+import {
+  PerspectiveCamera,
+  CubeTexture,
+  Mesh,
+  Scene
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class CubeTexturePass extends Pass {
+  constructor(camera: PerspectiveCamera, envMap?: CubeTexture, opacity?: number);
+  camera: PerspectiveCamera;
+  cubeShader: object;
+  cubeMesh: Mesh;
+  envMap: CubeTexture;
+  opacity: number;
+  cubeScene: Scene;
+  cubeCamera: PerspectiveCamera;
+}

+ 72 - 0
examples/jsm/postprocessing/CubeTexturePass.js

@@ -0,0 +1,72 @@
+/**
+ * @author bhouston / http://clara.io/
+ */
+
+import {
+	BackSide,
+	BoxBufferGeometry,
+	Mesh,
+	PerspectiveCamera,
+	Scene,
+	ShaderLib,
+	ShaderMaterial
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+
+var CubeTexturePass = function ( camera, envMap, opacity ) {
+
+	Pass.call( this );
+
+	this.camera = camera;
+
+	this.needsSwap = false;
+
+	this.cubeShader = ShaderLib[ 'cube' ];
+	this.cubeMesh = new Mesh(
+		new BoxBufferGeometry( 10, 10, 10 ),
+		new ShaderMaterial( {
+			uniforms: this.cubeShader.uniforms,
+			vertexShader: this.cubeShader.vertexShader,
+			fragmentShader: this.cubeShader.fragmentShader,
+			depthTest: false,
+			depthWrite: false,
+			side: BackSide
+		} )
+	);
+
+	this.envMap = envMap;
+	this.opacity = ( opacity !== undefined ) ? opacity : 1.0;
+
+	this.cubeScene = new Scene();
+	this.cubeCamera = new PerspectiveCamera();
+	this.cubeScene.add( this.cubeMesh );
+
+};
+
+CubeTexturePass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: CubeTexturePass,
+
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
+
+		var oldAutoClear = renderer.autoClear;
+		renderer.autoClear = false;
+
+		this.cubeCamera.projectionMatrix.copy( this.camera.projectionMatrix );
+		this.cubeCamera.quaternion.setFromRotationMatrix( this.camera.matrixWorld );
+
+		this.cubeMesh.material.uniforms[ "tCube" ].value = this.envMap;
+		this.cubeMesh.material.uniforms[ "opacity" ].value = this.opacity;
+		this.cubeMesh.material.transparent = ( this.opacity < 1.0 );
+
+		renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.cubeScene, this.cubeCamera );
+
+		renderer.autoClear = oldAutoClear;
+
+	}
+
+} );
+
+export { CubeTexturePass };

+ 19 - 0
examples/jsm/postprocessing/GlitchPass.d.ts

@@ -0,0 +1,19 @@
+import {
+  ShaderMaterial,
+  DataTexture
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class GlitchPass extends Pass {
+  constructor(dt_size?: number);
+  uniforms: object;
+  material: ShaderMaterial;
+  fsQuad: object;
+  goWild: boolean;
+  curF: number;
+  randX: number;
+
+  generateTrigger(): void;
+  generateHeightmap(dt_size: number): DataTexture;
+}

+ 126 - 0
examples/jsm/postprocessing/GlitchPass.js

@@ -0,0 +1,126 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	DataTexture,
+	FloatType,
+	Math as _Math,
+	RGBFormat,
+	ShaderMaterial,
+	UniformsUtils
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { DigitalGlitch } from "../shaders/DigitalGlitch.js";
+
+var GlitchPass = function ( dt_size ) {
+
+	Pass.call( this );
+
+	if ( DigitalGlitch === undefined ) console.error( "GlitchPass relies on DigitalGlitch" );
+
+	var shader = DigitalGlitch;
+	this.uniforms = UniformsUtils.clone( shader.uniforms );
+
+	if ( dt_size == undefined ) dt_size = 64;
+
+
+	this.uniforms[ "tDisp" ].value = this.generateHeightmap( dt_size );
+
+
+	this.material = new ShaderMaterial( {
+		uniforms: this.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader
+	} );
+
+	this.fsQuad = new Pass.FullScreenQuad( this.material );
+
+	this.goWild = false;
+	this.curF = 0;
+	this.generateTrigger();
+
+};
+
+GlitchPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: GlitchPass,
+
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		this.uniforms[ "tDiffuse" ].value = readBuffer.texture;
+		this.uniforms[ 'seed' ].value = Math.random();//default seeding
+		this.uniforms[ 'byp' ].value = 0;
+
+		if ( this.curF % this.randX == 0 || this.goWild == true ) {
+
+			this.uniforms[ 'amount' ].value = Math.random() / 30;
+			this.uniforms[ 'angle' ].value = _Math.randFloat( - Math.PI, Math.PI );
+			this.uniforms[ 'seed_x' ].value = _Math.randFloat( - 1, 1 );
+			this.uniforms[ 'seed_y' ].value = _Math.randFloat( - 1, 1 );
+			this.uniforms[ 'distortion_x' ].value = _Math.randFloat( 0, 1 );
+			this.uniforms[ 'distortion_y' ].value = _Math.randFloat( 0, 1 );
+			this.curF = 0;
+			this.generateTrigger();
+
+		} else if ( this.curF % this.randX < this.randX / 5 ) {
+
+			this.uniforms[ 'amount' ].value = Math.random() / 90;
+			this.uniforms[ 'angle' ].value = _Math.randFloat( - Math.PI, Math.PI );
+			this.uniforms[ 'distortion_x' ].value = _Math.randFloat( 0, 1 );
+			this.uniforms[ 'distortion_y' ].value = _Math.randFloat( 0, 1 );
+			this.uniforms[ 'seed_x' ].value = _Math.randFloat( - 0.3, 0.3 );
+			this.uniforms[ 'seed_y' ].value = _Math.randFloat( - 0.3, 0.3 );
+
+		} else if ( this.goWild == false ) {
+
+			this.uniforms[ 'byp' ].value = 1;
+
+		}
+
+		this.curF ++;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.fsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+			if ( this.clear ) renderer.clear();
+			this.fsQuad.render( renderer );
+
+		}
+
+	},
+
+	generateTrigger: function () {
+
+		this.randX = _Math.randInt( 120, 240 );
+
+	},
+
+	generateHeightmap: function ( dt_size ) {
+
+		var data_arr = new Float32Array( dt_size * dt_size * 3 );
+		var length = dt_size * dt_size;
+
+		for ( var i = 0; i < length; i ++ ) {
+
+			var val = _Math.randFloat( 0, 1 );
+			data_arr[ i * 3 + 0 ] = val;
+			data_arr[ i * 3 + 1 ] = val;
+			data_arr[ i * 3 + 2 ] = val;
+
+		}
+
+		var texture = new DataTexture( data_arr, dt_size, dt_size, RGBFormat, FloatType );
+		texture.needsUpdate = true;
+		return texture;
+
+	}
+
+} );
+
+export { GlitchPass };

+ 25 - 0
examples/jsm/postprocessing/HalftonePass.d.ts

@@ -0,0 +1,25 @@
+import {
+  ShaderMaterial,
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export interface HalftonePassParameters {
+  shape?: number;
+  radius?: number;
+  rotateR?: number;
+  rotateB?: number;
+  rotateG?: number;
+  scatter?: number;
+  blending?: number;
+  blendingMode?: number;
+  greyscale?: boolean;
+  disable?: boolean;
+}
+
+export class HalftonePass extends Pass {
+  constructor(width: number, height: number, params: HalftonePassParameters);
+  uniforms: object;
+  material: ShaderMaterial;
+  fsQuad: object;
+}

+ 81 - 0
examples/jsm/postprocessing/HalftonePass.js

@@ -0,0 +1,81 @@
+/**
+ * @author meatbags / xavierburrow.com, github/meatbags
+ *
+ * RGB Halftone pass for three.js effects composer. Requires HalftoneShader.
+ *
+ */
+
+import {
+	ShaderMaterial,
+	UniformsUtils
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { HalftoneShader } from "../shaders/HalftoneShader.js";
+
+var HalftonePass = function ( width, height, params ) {
+
+	Pass.call( this );
+
+ 	if ( HalftoneShader === undefined ) {
+
+ 		console.error( 'THREE.HalftonePass requires HalftoneShader' );
+
+ 	}
+
+ 	this.uniforms = UniformsUtils.clone( HalftoneShader.uniforms );
+ 	this.material = new ShaderMaterial( {
+ 		uniforms: this.uniforms,
+ 		fragmentShader: HalftoneShader.fragmentShader,
+ 		vertexShader: HalftoneShader.vertexShader
+ 	} );
+
+	// set params
+	this.uniforms.width.value = width;
+	this.uniforms.height.value = height;
+
+	for ( var key in params ) {
+
+		if ( params.hasOwnProperty( key ) && this.uniforms.hasOwnProperty( key ) ) {
+
+			this.uniforms[ key ].value = params[ key ];
+
+		}
+
+	}
+
+	this.fsQuad = new Pass.FullScreenQuad( this.material );
+
+};
+
+HalftonePass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: HalftonePass,
+
+	render: function ( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
+
+ 		this.material.uniforms[ "tDiffuse" ].value = readBuffer.texture;
+
+ 		if ( this.renderToScreen ) {
+
+ 			renderer.setRenderTarget( null );
+ 			this.fsQuad.render( renderer );
+
+		} else {
+
+ 			renderer.setRenderTarget( writeBuffer );
+ 			if ( this.clear ) renderer.clear();
+			this.fsQuad.render( renderer );
+
+		}
+
+ 	},
+
+ 	setSize: function ( width, height ) {
+
+ 		this.uniforms.width.value = width;
+ 		this.uniforms.height.value = height;
+
+ 	}
+} );
+
+export { HalftonePass };

+ 15 - 0
examples/jsm/postprocessing/SavePass.d.ts

@@ -0,0 +1,15 @@
+import {
+  ShaderMaterial,
+  WebGLRenderTarget
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class SavePass extends Pass {
+  constructor(renderTarget: WebGLRenderTarget);
+  textureID: string;
+  renderTarget: WebGLRenderTarget;
+  uniforms: object;
+  material: ShaderMaterial;
+  fsQuad: object;
+}

+ 71 - 0
examples/jsm/postprocessing/SavePass.js

@@ -0,0 +1,71 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	LinearFilter,
+	RGBFormat,
+	ShaderMaterial,
+	UniformsUtils,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+import { CopyShader } from "../shaders/CopyShader.js";
+
+var SavePass = function ( renderTarget ) {
+
+	Pass.call( this );
+
+	if ( CopyShader === undefined )
+		console.error( "SavePass relies on CopyShader" );
+
+	var shader = CopyShader;
+
+	this.textureID = "tDiffuse";
+
+	this.uniforms = UniformsUtils.clone( shader.uniforms );
+
+	this.material = new ShaderMaterial( {
+
+		uniforms: this.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader
+
+	} );
+
+	this.renderTarget = renderTarget;
+
+	if ( this.renderTarget === undefined ) {
+
+		this.renderTarget = new WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat, stencilBuffer: false } );
+		this.renderTarget.texture.name = "SavePass.rt";
+
+	}
+
+	this.needsSwap = false;
+
+	this.fsQuad = new Pass.FullScreenQuad( this.material );
+
+};
+
+SavePass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: SavePass,
+
+	render: function ( renderer, writeBuffer, readBuffer ) {
+
+		if ( this.uniforms[ this.textureID ] ) {
+
+			this.uniforms[ this.textureID ].value = readBuffer.texture;
+
+		}
+
+		renderer.setRenderTarget( this.renderTarget );
+		if ( this.clear ) renderer.clear();
+		this.fsQuad.render( renderer );
+
+	}
+
+} );
+
+export { SavePass };

+ 16 - 0
examples/jsm/shaders/ToneMapShader.d.ts

@@ -0,0 +1,16 @@
+import {
+  Uniform
+} from '../../../src/Three';
+
+export interface ToneMapShader {
+  uniforms: {
+    tDiffuse: Uniform;
+    averageLuminance: Uniform;
+    luminanceMap: Uniform;
+    maxLuminance: Uniform;
+    minLuminance: Uniform;
+    middleGrey: Uniform;
+  };
+  vertexShader: string;
+  fragmentShader: string;
+}

+ 81 - 0
examples/jsm/shaders/ToneMapShader.js

@@ -0,0 +1,81 @@
+/**
+ * @author miibond
+ *
+ * Full-screen tone-mapping shader based on http://www.cis.rit.edu/people/faculty/ferwerda/publications/sig02_paper.pdf
+ */
+
+
+
+var ToneMapShader = {
+
+	uniforms: {
+
+		"tDiffuse": { value: null },
+		"averageLuminance": { value: 1.0 },
+		"luminanceMap": { value: null },
+		"maxLuminance": { value: 16.0 },
+		"minLuminance": { value: 0.01 },
+		"middleGrey": { value: 0.6 }
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"#include <common>",
+
+		"uniform sampler2D tDiffuse;",
+
+		"varying vec2 vUv;",
+
+		"uniform float middleGrey;",
+		"uniform float minLuminance;",
+		"uniform float maxLuminance;",
+		"#ifdef ADAPTED_LUMINANCE",
+			"uniform sampler2D luminanceMap;",
+		"#else",
+			"uniform float averageLuminance;",
+		"#endif",
+
+		"vec3 ToneMap( vec3 vColor ) {",
+			"#ifdef ADAPTED_LUMINANCE",
+				// Get the calculated average luminance
+				"float fLumAvg = texture2D(luminanceMap, vec2(0.5, 0.5)).r;",
+			"#else",
+				"float fLumAvg = averageLuminance;",
+			"#endif",
+
+			// Calculate the luminance of the current pixel
+			"float fLumPixel = linearToRelativeLuminance( vColor );",
+
+			// Apply the modified operator (Eq. 4)
+			"float fLumScaled = (fLumPixel * middleGrey) / max( minLuminance, fLumAvg );",
+
+			"float fLumCompressed = (fLumScaled * (1.0 + (fLumScaled / (maxLuminance * maxLuminance)))) / (1.0 + fLumScaled);",
+			"return fLumCompressed * vColor;",
+		"}",
+
+		"void main() {",
+
+			"vec4 texel = texture2D( tDiffuse, vUv );",
+
+			"gl_FragColor = vec4( ToneMap( texel.xyz ), texel.w );",
+
+		"}"
+
+	].join( "\n" )
+
+};
+
+export { ToneMapShader };

+ 12 - 0
examples/jsm/shaders/TriangleBlurShader.d.ts

@@ -0,0 +1,12 @@
+import {
+  Uniform
+} from '../../../src/Three';
+
+export interface TriangleBlurShader {
+  uniforms: {
+    texture: Uniform;
+    delta: Uniform;
+  };
+  vertexShader: string;
+  fragmentShader: string;
+}

+ 78 - 0
examples/jsm/shaders/TriangleBlurShader.js

@@ -0,0 +1,78 @@
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ *
+ * Triangle blur shader
+ * based on glfx.js triangle blur shader
+ * https://github.com/evanw/glfx.js
+ *
+ * A basic blur filter, which convolves the image with a
+ * pyramid filter. The pyramid filter is separable and is applied as two
+ * perpendicular triangle filters.
+ */
+
+import {
+	Vector2
+} from "../../../build/three.module.js";
+
+var TriangleBlurShader = {
+
+	uniforms: {
+
+		"texture": { value: null },
+		"delta": { value: new Vector2( 1, 1 ) }
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"#include <common>",
+
+		"#define ITERATIONS 10.0",
+
+		"uniform sampler2D texture;",
+		"uniform vec2 delta;",
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vec4 color = vec4( 0.0 );",
+
+			"float total = 0.0;",
+
+			// randomize the lookup values to hide the fixed number of samples
+
+			"float offset = rand( vUv );",
+
+			"for ( float t = -ITERATIONS; t <= ITERATIONS; t ++ ) {",
+
+				"float percent = ( t + offset - 0.5 ) / ITERATIONS;",
+				"float weight = 1.0 - abs( percent );",
+
+				"color += texture2D( texture, vUv + delta * percent ) * weight;",
+				"total += weight;",
+
+			"}",
+
+			"gl_FragColor = color / total;",
+
+		"}"
+
+	].join( "\n" )
+
+};
+
+export { TriangleBlurShader };

+ 5 - 7
examples/jsm/utils/SceneUtils.js

@@ -4,7 +4,6 @@
 
 import {
 	Group,
-	Matrix4,
 	Mesh
 } from "../../../build/three.module.js";
 
@@ -26,18 +25,17 @@ var SceneUtils = {
 
 	detach: function ( child, parent, scene ) {
 
-		child.applyMatrix( parent.matrixWorld );
-		parent.remove( child );
-		scene.add( child );
+		console.warn( 'THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.' );
+
+		scene.attach( child );
 
 	},
 
 	attach: function ( child, scene, parent ) {
 
-		child.applyMatrix( new Matrix4().getInverse( parent.matrixWorld ) );
+		console.warn( 'THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.' );
 
-		scene.remove( child );
-		parent.add( child );
+		parent.attach( child );
 
 	}
 

+ 10 - 1
utils/modularize.js

@@ -67,15 +67,22 @@ var files = [
 	{ path: 'pmrem/PMREMCubeUVPacker.js', dependencies: [], ignoreList: [] },
 	{ path: 'pmrem/PMREMGenerator.js', dependencies: [], ignoreList: [] },
 
+	{ path: 'postprocessing/AdaptiveToneMappingPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' }, { name: 'LuminosityShader', path: 'shaders/LuminosityShader.js' }, { name: 'ToneMapShader', path: 'shaders/ToneMapShader.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/AfterimagePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'AfterimageShader', path: 'shaders/AfterimageShader.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/BloomPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' }, { name: 'ConvolutionShader', path: 'shaders/ConvolutionShader.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/BokehPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'BokehShader', path: 'shaders/BokehShader.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/ClearPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/CubeTexturePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/DotScreenPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'DotScreenShader', path: 'shaders/DotScreenShader.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/EffectComposer.js', dependencies: [ { name: 'CopyShader', path: 'shaders/CopyShader.js' }, { name: 'ShaderPass', path: 'postprocessing/ShaderPass.js' }, { name: 'MaskPass', path: 'postprocessing/MaskPass.js' }, { name: 'ClearMaskPass', path: 'postprocessing/MaskPass.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/FilmPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'FilmShader', path: 'shaders/FilmShader.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/GlitchPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'DigitalGlitch', path: 'shaders/DigitalGlitch.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/HalftonePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'HalftoneShader', path: 'shaders/HalftoneShader.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/MaskPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/RenderPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
-	{ path: 'postprocessing/TexturePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/SavePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' } ], ignoreList: [] },
 	{ path: 'postprocessing/ShaderPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/TexturePass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' }, { name: 'CopyShader', path: 'shaders/CopyShader.js' } ], ignoreList: [] },
 
 	{ path: 'renderers/CSS2DRenderer.js', dependencies: [], ignoreList: [] },
 	{ path: 'renderers/CSS3DRenderer.js', dependencies: [], ignoreList: [] },
@@ -122,6 +129,8 @@ var files = [
 	{ path: 'shaders/SobelOperatorShader.js', dependencies: [], ignoreList: [] },
 	{ path: 'shaders/SSAOShader.js', dependencies: [], ignoreList: [] },
 	{ path: 'shaders/TechnicolorShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/ToneMapShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/TriangleBlurShader.js', dependencies: [], ignoreList: [] },
 	{ path: 'shaders/UnpackDepthRGBAShader.js', dependencies: [], ignoreList: [] },
 	{ path: 'shaders/VerticalBlurShader.js', dependencies: [], ignoreList: [] },
 	{ path: 'shaders/VerticalTiltShiftShader.js', dependencies: [], ignoreList: [] },