Browse Source

JSM: Added modules and TS files for basic post processing classes.

Mugen87 6 năm trước cách đây
mục cha
commit
0198829e01

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

@@ -156,6 +156,14 @@
 						<li>PMREMGenerator</li>
 					</ul>
 				</li>
+				<li>postprocessing
+					<ul>
+						<li>EffectComposer</li>
+						<li>MaskPass</li>
+						<li>RenderPass</li>
+						<li>ShaderPass</li>
+					</ul>
+				</li>
 				<li>renderers
 					<ul>
 						<li>CSS2DRenderer</li>
@@ -169,6 +177,9 @@
 				<li>shaders
 					<ul>
 						<li>BokehShader2</li>
+						<li>CopyShader</li>
+						<li>DotScreenShader</li>
+						<li>RGBShiftShader</li>
 						<li>UnpackDepthRGBAShader</li>
 						<li>WaterRefractionShader</li>
 					</ul>

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

@@ -240,9 +240,9 @@ THREE.Pass = function () {
 
 Object.assign( THREE.Pass.prototype, {
 
-	setSize: function ( width, height ) {},
+	setSize: function ( /* width, height */ ) {},
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
 
 		console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
 

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

@@ -20,7 +20,7 @@ THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 
 	constructor: THREE.MaskPass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
 
 		var context = renderer.context;
 		var state = renderer.state;
@@ -93,7 +93,7 @@ THREE.ClearMaskPass.prototype = Object.create( THREE.Pass.prototype );
 
 Object.assign( THREE.ClearMaskPass.prototype, {
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
 
 		renderer.state.buffers.stencil.setTest( false );
 

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

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

+ 2 - 1
examples/js/postprocessing/ShaderPass.js

@@ -30,13 +30,14 @@ THREE.ShaderPass = function ( shader, textureID ) {
 	}
 
 	this.fsQuad = new THREE.Pass.FullScreenQuad( this.material );
+
 };
 
 THREE.ShaderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
 
 	constructor: THREE.ShaderPass,
 
-	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
 
 		if ( this.uniforms[ this.textureID ] ) {
 

+ 27 - 0
examples/jsm/postprocessing/EffectComposer.d.ts

@@ -0,0 +1,27 @@
+import {
+  WebGLRenderer,
+  WebGLRenderTarget,
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+import { ShaderPass } from './ShaderPass';
+
+export class EffectComposer {
+  constructor(renderer: WebGLRenderer, renderTarget?: WebGLRenderTarget);
+  renderer: WebGLRenderer;
+  renderTarget1: WebGLRenderTarget;
+  renderTarget2: WebGLRenderTarget;
+  writeBuffer: WebGLRenderTarget;
+  readBuffer: WebGLRenderTarget;
+  passes: Pass[];
+  copyPass: ShaderPass;
+
+  swapBuffers(): void;
+  addPass(pass: Pass): void;
+  insertPass(pass: Pass, index: number): void;
+  isLastEnabledPass(): boolean;
+  render(deltaTime: number): void;
+  reset(renderTarget?: WebGLRenderTarget): void;
+  setSize(width: number, height: number): void;
+  setPixelRatio(pixelRatio: number): void;
+}

+ 309 - 0
examples/jsm/postprocessing/EffectComposer.js

@@ -0,0 +1,309 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	LinearFilter,
+	Mesh,
+	OrthographicCamera,
+	PlaneBufferGeometry,
+	RGBAFormat,
+	Vector2,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+import { CopyShader } from "../shaders/CopyShader.js";
+import { ShaderPass } from "../postprocessing/ShaderPass.js";
+import { MaskPass } from "../postprocessing/MaskPass.js";
+import { ClearMaskPass } from "../postprocessing/MaskPass.js";
+
+var EffectComposer = function ( renderer, renderTarget ) {
+
+	this.renderer = renderer;
+
+	if ( renderTarget === undefined ) {
+
+		var parameters = {
+			minFilter: LinearFilter,
+			magFilter: LinearFilter,
+			format: RGBAFormat,
+			stencilBuffer: false
+		};
+
+		var size = renderer.getSize( new Vector2() );
+		this._pixelRatio = renderer.getPixelRatio();
+		this._width = size.width;
+		this._height = size.height;
+
+		renderTarget = new WebGLRenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, parameters );
+		renderTarget.texture.name = 'EffectComposer.rt1';
+
+	} else {
+
+		this._pixelRatio = 1;
+		this._width = renderTarget.width;
+		this._height = renderTarget.height;
+
+	}
+
+	this.renderTarget1 = renderTarget;
+	this.renderTarget2 = renderTarget.clone();
+	this.renderTarget2.texture.name = 'EffectComposer.rt2';
+
+	this.writeBuffer = this.renderTarget1;
+	this.readBuffer = this.renderTarget2;
+
+	this.renderToScreen = true;
+
+	this.passes = [];
+
+	// dependencies
+
+	if ( CopyShader === undefined ) {
+
+		console.error( 'THREE.EffectComposer relies on CopyShader' );
+
+	}
+
+	if ( ShaderPass === undefined ) {
+
+		console.error( 'THREE.EffectComposer relies on ShaderPass' );
+
+	}
+
+	this.copyPass = new ShaderPass( CopyShader );
+
+	this._previousFrameTime = Date.now();
+
+};
+
+Object.assign( EffectComposer.prototype, {
+
+	swapBuffers: function () {
+
+		var tmp = this.readBuffer;
+		this.readBuffer = this.writeBuffer;
+		this.writeBuffer = tmp;
+
+	},
+
+	addPass: function ( pass ) {
+
+		this.passes.push( pass );
+
+		var size = this.renderer.getDrawingBufferSize( new Vector2() );
+		pass.setSize( size.width, size.height );
+
+	},
+
+	insertPass: function ( pass, index ) {
+
+		this.passes.splice( index, 0, pass );
+
+	},
+
+	isLastEnabledPass: function ( passIndex ) {
+
+		for ( var i = passIndex + 1; i < this.passes.length; i ++ ) {
+
+			if ( this.passes[ i ].enabled ) {
+
+				return false;
+
+			}
+
+		}
+
+		return true;
+
+	},
+
+	render: function ( deltaTime ) {
+
+		// deltaTime value is in seconds
+
+		if ( deltaTime === undefined ) {
+
+			deltaTime = ( Date.now() - this._previousFrameTime ) * 0.001;
+
+		}
+
+		this._previousFrameTime = Date.now();
+
+		var currentRenderTarget = this.renderer.getRenderTarget();
+
+		var maskActive = false;
+
+		var pass, i, il = this.passes.length;
+
+		for ( i = 0; i < il; i ++ ) {
+
+			pass = this.passes[ i ];
+
+			if ( pass.enabled === false ) continue;
+
+			pass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );
+			pass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );
+
+			if ( pass.needsSwap ) {
+
+				if ( maskActive ) {
+
+					var context = this.renderer.context;
+
+					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
+
+					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );
+
+					context.stencilFunc( context.EQUAL, 1, 0xffffffff );
+
+				}
+
+				this.swapBuffers();
+
+			}
+
+			if ( MaskPass !== undefined ) {
+
+				if ( pass instanceof MaskPass ) {
+
+					maskActive = true;
+
+				} else if ( pass instanceof ClearMaskPass ) {
+
+					maskActive = false;
+
+				}
+
+			}
+
+		}
+
+		this.renderer.setRenderTarget( currentRenderTarget );
+
+	},
+
+	reset: function ( renderTarget ) {
+
+		if ( renderTarget === undefined ) {
+
+			var size = this.renderer.getSize( new Vector2() );
+			this._pixelRatio = this.renderer.getPixelRatio();
+			this._width = size.width;
+			this._height = size.height;
+
+			renderTarget = this.renderTarget1.clone();
+			renderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
+
+		}
+
+		this.renderTarget1.dispose();
+		this.renderTarget2.dispose();
+		this.renderTarget1 = renderTarget;
+		this.renderTarget2 = renderTarget.clone();
+
+		this.writeBuffer = this.renderTarget1;
+		this.readBuffer = this.renderTarget2;
+
+	},
+
+	setSize: function ( width, height ) {
+
+		this._width = width;
+		this._height = height;
+
+		var effectiveWidth = this._width * this._pixelRatio;
+		var effectiveHeight = this._height * this._pixelRatio;
+
+		this.renderTarget1.setSize( effectiveWidth, effectiveHeight );
+		this.renderTarget2.setSize( effectiveWidth, effectiveHeight );
+
+		for ( var i = 0; i < this.passes.length; i ++ ) {
+
+			this.passes[ i ].setSize( effectiveWidth, effectiveHeight );
+
+		}
+
+	},
+
+	setPixelRatio: function ( pixelRatio ) {
+
+		this._pixelRatio = pixelRatio;
+
+		this.setSize( this._width, this._height );
+
+	}
+
+} );
+
+
+var Pass = function () {
+
+	// if set to true, the pass is processed by the composer
+	this.enabled = true;
+
+	// if set to true, the pass indicates to swap read and write buffer after rendering
+	this.needsSwap = true;
+
+	// if set to true, the pass clears its buffer before rendering
+	this.clear = false;
+
+	// if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.
+	this.renderToScreen = false;
+
+};
+
+Object.assign( Pass.prototype, {
+
+	setSize: function ( /* width, height */ ) {},
+
+	render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
+
+		console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
+
+	}
+
+} );
+
+// Helper for passes that need to fill the viewport with a single quad.
+Pass.FullScreenQuad = ( function () {
+
+	var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+	var geometry = new PlaneBufferGeometry( 2, 2 );
+
+	var FullScreenQuad = function ( material ) {
+
+		this._mesh = new Mesh( geometry, material );
+
+	};
+
+	Object.defineProperty( FullScreenQuad.prototype, 'material', {
+
+		get: function () {
+
+			return this._mesh.material;
+
+		},
+
+		set: function ( value ) {
+
+			this._mesh.material = value;
+
+		}
+
+	} );
+
+	Object.assign( FullScreenQuad.prototype, {
+
+		render: function ( renderer ) {
+
+			renderer.render( this._mesh, camera );
+
+		}
+
+	} );
+
+	return FullScreenQuad;
+
+} )();
+
+export { EffectComposer, Pass };

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

@@ -0,0 +1,17 @@
+import {
+  Scene,
+  Camera,
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class MaskPass extends Pass {
+  constructor(scene: Scene, camera: Camera);
+  scene: Scene;
+  camera: Camera;
+  inverse: boolean;
+}
+
+export class ClearMaskPass extends Pass {
+  constructor();
+}

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

@@ -0,0 +1,107 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+
+import { Pass } from "../postprocessing/Pass.js";
+
+var MaskPass = function ( scene, camera ) {
+
+	Pass.call( this );
+
+	this.scene = scene;
+	this.camera = camera;
+
+	this.clear = true;
+	this.needsSwap = false;
+
+	this.inverse = false;
+
+};
+
+MaskPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: MaskPass,
+
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		var context = renderer.context;
+		var state = renderer.state;
+
+		// don't update color or depth
+
+		state.buffers.color.setMask( false );
+		state.buffers.depth.setMask( false );
+
+		// lock buffers
+
+		state.buffers.color.setLocked( true );
+		state.buffers.depth.setLocked( true );
+
+		// set up stencil
+
+		var writeValue, clearValue;
+
+		if ( this.inverse ) {
+
+			writeValue = 0;
+			clearValue = 1;
+
+		} else {
+
+			writeValue = 1;
+			clearValue = 0;
+
+		}
+
+		state.buffers.stencil.setTest( true );
+		state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
+		state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
+		state.buffers.stencil.setClear( clearValue );
+
+		// draw into the stencil buffer
+
+		renderer.setRenderTarget( readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		renderer.setRenderTarget( writeBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		// unlock color and depth buffer for subsequent rendering
+
+		state.buffers.color.setLocked( false );
+		state.buffers.depth.setLocked( false );
+
+		// only render where stencil is set to 1
+
+		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
+		state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
+
+	}
+
+} );
+
+
+var ClearMaskPass = function () {
+
+	Pass.call( this );
+
+	this.needsSwap = false;
+
+};
+
+ClearMaskPass.prototype = Object.create( Pass.prototype );
+
+Object.assign( ClearMaskPass.prototype, {
+
+	render: function ( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
+
+		renderer.state.buffers.stencil.setTest( false );
+
+	}
+
+} );
+
+export { MaskPass, ClearMaskPass };

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

@@ -0,0 +1,15 @@
+import {
+  WebGLRenderer,
+  WebGLRenderTarget
+} from '../../../src/Three';
+
+export class Pass {
+  constructor();
+  enabled: boolean;
+  needsSwap: boolean;
+  clear: boolean;
+  renderToScreen: boolean;
+
+  setSize(width: number, height: number): void;
+  render(renderer: WebGLRenderer, writeBuffer: WebGLRenderTarget, readBuffer: WebGLRenderTarget, deltaTime: number, maskActive: boolean): void;
+}

+ 78 - 0
examples/jsm/postprocessing/Pass.js

@@ -0,0 +1,78 @@
+import {
+	OrthographicCamera,
+	PlaneBufferGeometry,
+	Mesh
+} from "../../../build/three.module.js";
+
+function Pass() {
+
+	// if set to true, the pass is processed by the composer
+	this.enabled = true;
+
+	// if set to true, the pass indicates to swap read and write buffer after rendering
+	this.needsSwap = true;
+
+	// if set to true, the pass clears its buffer before rendering
+	this.clear = false;
+
+	// if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.
+	this.renderToScreen = false;
+
+}
+
+Object.assign( Pass.prototype, {
+
+	setSize: function ( /* width, height */ ) {},
+
+	render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
+
+		console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
+
+	}
+
+} );
+
+// Helper for passes that need to fill the viewport with a single quad.
+
+Pass.FullScreenQuad = ( function () {
+
+	var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+	var geometry = new PlaneBufferGeometry( 2, 2 );
+
+	var FullScreenQuad = function ( material ) {
+
+		this._mesh = new Mesh( geometry, material );
+
+	};
+
+	Object.defineProperty( FullScreenQuad.prototype, 'material', {
+
+		get: function () {
+
+			return this._mesh.material;
+
+		},
+
+		set: function ( value ) {
+
+			this._mesh.material = value;
+
+		}
+
+	} );
+
+	Object.assign( FullScreenQuad.prototype, {
+
+		render: function ( renderer ) {
+
+			renderer.render( this._mesh, camera );
+
+		}
+
+	} );
+
+	return FullScreenQuad;
+
+} )();
+
+export { Pass };

+ 18 - 0
examples/jsm/postprocessing/RenderPass.d.ts

@@ -0,0 +1,18 @@
+import {
+  Scene,
+  Camera,
+  Material,
+  Color
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class RenderPass extends Pass {
+  constructor(scene: Scene, camera: Camera, overrideMaterial: Material, clearColor: Color, clearAlpha: number);
+  scene: Scene;
+  camera: Camera;
+  overrideMaterial: Material;
+  clearColor: Color;
+  clearAlpha: number;
+  clearDepth: boolean;
+}

+ 73 - 0
examples/jsm/postprocessing/RenderPass.js

@@ -0,0 +1,73 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+
+import { Pass } from "../postprocessing/Pass.js";
+
+var RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
+
+	Pass.call( this );
+
+	this.scene = scene;
+	this.camera = camera;
+
+	this.overrideMaterial = overrideMaterial;
+
+	this.clearColor = clearColor;
+	this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
+
+	this.clear = true;
+	this.clearDepth = false;
+	this.needsSwap = false;
+
+};
+
+RenderPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: RenderPass,
+
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		var oldAutoClear = renderer.autoClear;
+		renderer.autoClear = false;
+
+		this.scene.overrideMaterial = this.overrideMaterial;
+
+		var oldClearColor, oldClearAlpha;
+
+		if ( this.clearColor ) {
+
+			oldClearColor = renderer.getClearColor().getHex();
+			oldClearAlpha = renderer.getClearAlpha();
+
+			renderer.setClearColor( this.clearColor, this.clearAlpha );
+
+		}
+
+		if ( this.clearDepth ) {
+
+			renderer.clearDepth();
+
+		}
+
+		renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
+
+		// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
+		if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+		renderer.render( this.scene, this.camera );
+
+		if ( this.clearColor ) {
+
+			renderer.setClearColor( oldClearColor, oldClearAlpha );
+
+		}
+
+		this.scene.overrideMaterial = null;
+		renderer.autoClear = oldAutoClear;
+
+	}
+
+} );
+
+export { RenderPass };

+ 13 - 0
examples/jsm/postprocessing/ShaderPass.d.ts

@@ -0,0 +1,13 @@
+import {
+  Material
+} from '../../../src/Three';
+
+import { Pass } from './Pass';
+
+export class ShaderPass extends Pass {
+  constructor(shader: object, textureID?: string);
+  textureID: string;
+  uniforms: object;
+  material: Material;
+  fsQuad: object;
+}

+ 74 - 0
examples/jsm/postprocessing/ShaderPass.js

@@ -0,0 +1,74 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	ShaderMaterial,
+	UniformsUtils
+} from "../../../build/three.module.js";
+import { Pass } from "../postprocessing/Pass.js";
+
+var ShaderPass = function ( shader, textureID ) {
+
+	Pass.call( this );
+
+	this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
+
+	if ( shader instanceof ShaderMaterial ) {
+
+		this.uniforms = shader.uniforms;
+
+		this.material = shader;
+
+	} else if ( shader ) {
+
+		this.uniforms = UniformsUtils.clone( shader.uniforms );
+
+		this.material = new ShaderMaterial( {
+
+			defines: Object.assign( {}, shader.defines ),
+			uniforms: this.uniforms,
+			vertexShader: shader.vertexShader,
+			fragmentShader: shader.fragmentShader
+
+		} );
+
+	}
+
+	this.fsQuad = new Pass.FullScreenQuad( this.material );
+
+};
+
+ShaderPass.prototype = Object.assign( Object.create( Pass.prototype ), {
+
+	constructor: ShaderPass,
+
+	render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+
+		if ( this.uniforms[ this.textureID ] ) {
+
+			this.uniforms[ this.textureID ].value = readBuffer.texture;
+
+		}
+
+		this.fsQuad.material = this.material;
+
+		if ( this.renderToScreen ) {
+
+			renderer.setRenderTarget( null );
+			this.fsQuad.render( renderer );
+
+		} else {
+
+			renderer.setRenderTarget( writeBuffer );
+			// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
+			if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+			this.fsQuad.render( renderer );
+
+		}
+
+	}
+
+} );
+
+export { ShaderPass };

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

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

+ 50 - 0
examples/jsm/shaders/CopyShader.js

@@ -0,0 +1,50 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * Full-screen textured quad shader
+ */
+
+
+
+var CopyShader = {
+
+	uniforms: {
+
+		"tDiffuse": { value: null },
+		"opacity":  { value: 1.0 }
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"uniform float opacity;",
+
+		"uniform sampler2D tDiffuse;",
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vec4 texel = texture2D( tDiffuse, vUv );",
+			"gl_FragColor = opacity * texel;",
+
+		"}"
+
+	].join( "\n" )
+
+};
+
+export { CopyShader };

+ 15 - 0
examples/jsm/shaders/DotScreenShader.d.ts

@@ -0,0 +1,15 @@
+import {
+  Uniform
+} from '../../../src/Three';
+
+export interface DotScreenShader {
+  uniforms: {
+    tDiffuse: Uniform;
+    tSize: Uniform;
+    center: Uniform;
+    angle: Uniform;
+    scale: Uniform;
+  };
+  vertexShader: string;
+  fragmentShader:string;
+}

+ 74 - 0
examples/jsm/shaders/DotScreenShader.js

@@ -0,0 +1,74 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * Dot screen shader
+ * based on glfx.js sepia shader
+ * https://github.com/evanw/glfx.js
+ */
+
+import {
+	Vector2
+} from "../../../build/three.module.js";
+
+var DotScreenShader = {
+
+	uniforms: {
+
+		"tDiffuse": { value: null },
+		"tSize":    { value: new Vector2( 256, 256 ) },
+		"center":   { value: new Vector2( 0.5, 0.5 ) },
+		"angle":    { value: 1.57 },
+		"scale":    { value: 1.0 }
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"uniform vec2 center;",
+		"uniform float angle;",
+		"uniform float scale;",
+		"uniform vec2 tSize;",
+
+		"uniform sampler2D tDiffuse;",
+
+		"varying vec2 vUv;",
+
+		"float pattern() {",
+
+			"float s = sin( angle ), c = cos( angle );",
+
+			"vec2 tex = vUv * tSize - center;",
+			"vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;",
+
+			"return ( sin( point.x ) * sin( point.y ) ) * 4.0;",
+
+		"}",
+
+		"void main() {",
+
+			"vec4 color = texture2D( tDiffuse, vUv );",
+
+			"float average = ( color.r + color.g + color.b ) / 3.0;",
+
+			"gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );",
+
+		"}"
+
+	].join( "\n" )
+
+};
+
+export { DotScreenShader };

+ 13 - 0
examples/jsm/shaders/RGBShiftShader.d.ts

@@ -0,0 +1,13 @@
+import {
+  Uniform
+} from '../../../src/Three';
+
+export interface RGBShiftShader {
+  uniforms: {
+    tDiffuse: Uniform;
+    amount: Uniform;
+    angle: Uniform;
+  };
+  vertexShader: string;
+  fragmentShader:string;
+}

+ 60 - 0
examples/jsm/shaders/RGBShiftShader.js

@@ -0,0 +1,60 @@
+/**
+ * @author felixturner / http://airtight.cc/
+ *
+ * RGB Shift Shader
+ * Shifts red and blue channels from center in opposite directions
+ * Ported from http://kriss.cx/tom/2009/05/rgb-shift/
+ * by Tom Butterworth / http://kriss.cx/tom/
+ *
+ * amount: shift distance (1 is width of input)
+ * angle: shift angle in radians
+ */
+
+
+
+var RGBShiftShader = {
+
+	uniforms: {
+
+		"tDiffuse": { value: null },
+		"amount":   { value: 0.005 },
+		"angle":    { value: 0.0 }
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"uniform sampler2D tDiffuse;",
+		"uniform float amount;",
+		"uniform float angle;",
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vec2 offset = amount * vec2( cos(angle), sin(angle));",
+			"vec4 cr = texture2D(tDiffuse, vUv + offset);",
+			"vec4 cga = texture2D(tDiffuse, vUv);",
+			"vec4 cb = texture2D(tDiffuse, vUv - offset);",
+			"gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);",
+
+		"}"
+
+	].join( "\n" )
+
+};
+
+export { RGBShiftShader };

+ 34 - 26
examples/webgl_postprocessing.html

@@ -14,18 +14,26 @@
 	</head>
 	<body>
 
-		<script src="../build/three.js"></script>
-
-		<script src="js/shaders/CopyShader.js"></script>
-		<script src="js/shaders/DotScreenShader.js"></script>
-		<script src="js/shaders/RGBShiftShader.js"></script>
-
-		<script src="js/postprocessing/EffectComposer.js"></script>
-		<script src="js/postprocessing/RenderPass.js"></script>
-		<script src="js/postprocessing/ShaderPass.js"></script>
-
-
-		<script>
+		<script type="module">
+			import {
+				Fog,
+				PerspectiveCamera,
+				Scene,
+				WebGLRenderer,
+				Object3D,
+				SphereBufferGeometry,
+				MeshPhongMaterial,
+				Mesh,
+				AmbientLight,
+				DirectionalLight
+			} from "../build/three.module.js";
+
+			import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
+			import { RenderPass } from './jsm/postprocessing/RenderPass.js';
+			import { ShaderPass } from './jsm/postprocessing/ShaderPass.js';
+
+			import { RGBShiftShader } from './jsm/shaders/RGBShiftShader.js';
+			import { DotScreenShader } from './jsm/shaders/DotScreenShader.js';
 
 			var camera, scene, renderer, composer;
 			var object, light;
@@ -35,28 +43,28 @@
 
 			function init() {
 
-				renderer = new THREE.WebGLRenderer();
+				renderer = new WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 
 				//
 
-				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera = new PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
 				camera.position.z = 400;
 
-				scene = new THREE.Scene();
-				scene.fog = new THREE.Fog( 0x000000, 1, 1000 );
+				scene = new Scene();
+				scene.fog = new Fog( 0x000000, 1, 1000 );
 
-				object = new THREE.Object3D();
+				object = new Object3D();
 				scene.add( object );
 
-				var geometry = new THREE.SphereBufferGeometry( 1, 4, 4 );
-				var material = new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } );
+				var geometry = new SphereBufferGeometry( 1, 4, 4 );
+				var material = new MeshPhongMaterial( { color: 0xffffff, flatShading: true } );
 
 				for ( var i = 0; i < 100; i ++ ) {
 
-					var mesh = new THREE.Mesh( geometry, material );
+					var mesh = new Mesh( geometry, material );
 					mesh.position.set( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 ).normalize();
 					mesh.position.multiplyScalar( Math.random() * 400 );
 					mesh.rotation.set( Math.random() * 2, Math.random() * 2, Math.random() * 2 );
@@ -65,22 +73,22 @@
 
 				}
 
-				scene.add( new THREE.AmbientLight( 0x222222 ) );
+				scene.add( new AmbientLight( 0x222222 ) );
 
-				light = new THREE.DirectionalLight( 0xffffff );
+				light = new DirectionalLight( 0xffffff );
 				light.position.set( 1, 1, 1 );
 				scene.add( light );
 
 				// postprocessing
 
-				composer = new THREE.EffectComposer( renderer );
-				composer.addPass( new THREE.RenderPass( scene, camera ) );
+				composer = new EffectComposer( renderer );
+				composer.addPass( new RenderPass( scene, camera ) );
 
-				var effect = new THREE.ShaderPass( THREE.DotScreenShader );
+				var effect = new ShaderPass( DotScreenShader );
 				effect.uniforms[ 'scale' ].value = 4;
 				composer.addPass( effect );
 
-				var effect = new THREE.ShaderPass( THREE.RGBShiftShader );
+				var effect = new ShaderPass( RGBShiftShader );
 				effect.uniforms[ 'amount' ].value = 0.0015;
 				composer.addPass( effect );
 

+ 15 - 5
utils/modularize.js

@@ -67,9 +67,10 @@ var files = [
 	{ path: 'pmrem/PMREMCubeUVPacker.js', dependencies: [], ignoreList: [] },
 	{ path: 'pmrem/PMREMGenerator.js', dependencies: [], ignoreList: [] },
 
-	{ path: 'shaders/BokehShader2.js', dependencies: [], ignoreList: [] },
-	{ path: 'shaders/UnpackDepthRGBAShader.js', dependencies: [], ignoreList: [] },
-	{ path: 'shaders/WaterRefractionShader.js', dependencies: [], 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/MaskPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/RenderPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
+	{ path: 'postprocessing/ShaderPass.js', dependencies: [ { name: 'Pass', path: 'postprocessing/Pass.js' } ], ignoreList: [] },
 
 	{ path: 'renderers/CSS2DRenderer.js', dependencies: [], ignoreList: [] },
 	{ path: 'renderers/CSS3DRenderer.js', dependencies: [], ignoreList: [] },
@@ -78,6 +79,13 @@ var files = [
 	{ path: 'renderers/SVGRenderer.js', dependencies: [ { name: 'Projector', path: 'renderers/Projector.js' }, { name: 'RenderableFace', path: 'renderers/Projector.js' }, { name: 'RenderableLine', path: 'renderers/Projector.js' }, { name: 'RenderableSprite', path: 'renderers/Projector.js' } ], ignoreList: [] },
 	{ path: 'renderers/RaytracingRenderer.js', dependencies: [], ignoreList: [] },
 
+	{ path: 'shaders/BokehShader2.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/CopyShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/DotScreenShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/RGBShiftShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/UnpackDepthRGBAShader.js', dependencies: [], ignoreList: [] },
+	{ path: 'shaders/WaterRefractionShader.js', dependencies: [], ignoreList: [] },
+
 	{ path: 'utils/BufferGeometryUtils.js', dependencies: [], ignoreList: [] },
 	{ path: 'utils/GeometryUtils.js', dependencies: [], ignoreList: [] },
 	{ path: 'utils/MathUtils.js', dependencies: [], ignoreList: [] },
@@ -186,9 +194,11 @@ function convert( path, exampleDependencies, ignoreList ) {
 		.sort()
 		.toString();
 
+	var imports = '';
+
 	// core imports
 
-	var imports = `import {${keys}\n} from "../../../build/three.module.js";`;
+	if ( keys ) imports += `import {${keys}\n} from "../../../build/three.module.js";`;
 
 	// example imports
 
@@ -202,7 +212,7 @@ function convert( path, exampleDependencies, ignoreList ) {
 
 	var exports = `export { ${classNames.join( ", " )} };\n`;
 
-	var output = contents.replace( '_IMPORTS_', keys ? imports : '' ) + '\n' + exports;
+	var output = contents.replace( '_IMPORTS_', imports ) + '\n' + exports;
 
 	// console.log( output );