Browse Source

Added vignette shader / effect. Updated postprocessing example.

alteredq 14 years ago
parent
commit
3a5d02cc39

+ 2 - 1
build/Three.js

@@ -356,8 +356,9 @@ THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:"attribute vec4 tang
 cube:{uniforms:{tCube:{type:"t",value:1,texture:null}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( - wPos.x, wPos.yz ) );\n}"},convolution:{uniforms:{tDiffuse:{type:"t",
 value:0,texture:null},uImageIncrement:{type:"v2",value:new THREE.Vector2(0.001953125,0)},cKernel:{type:"fv1",value:[]}},vertexShader:"varying vec2 vUv;\nuniform vec2 uImageIncrement;\nvoid main(void) {\nvUv = uv - ((KERNEL_SIZE - 1.0) / 2.0) * uImageIncrement;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform vec2 uImageIncrement;\nuniform float cKernel[KERNEL_SIZE];\nvoid main(void) {\nvec2 imageCoord = vUv;\nvec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );\nfor( int i=0; i<KERNEL_SIZE; ++i ) {\nsum += texture2D( tDiffuse, imageCoord ) * cKernel[i];\nimageCoord += uImageIncrement;\n}\ngl_FragColor = sum;\n}"},
 film:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},time:{type:"f",value:0},nIntensity:{type:"f",value:0.5},sIntensity:{type:"f",value:0.05},sCount:{type:"f",value:4096},grayscale:{type:"i",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float time;\nuniform bool grayscale;\nuniform float nIntensity;\nuniform float sIntensity;\nuniform float sCount;\nvoid main() {\nvec4 cTextureScreen = texture2D( tDiffuse, vUv );\nfloat x = vUv.x * vUv.y * time *  1000.0;\nx = mod( x, 13.0 ) * mod( x, 123.0 );\nfloat dx = mod( x, 0.01 );\nvec3 cResult = cTextureScreen.rgb + cTextureScreen.rgb * clamp( 0.1 + dx * 100.0, 0.0, 1.0 );\nvec2 sc = vec2( sin( vUv.y * sCount ), cos( vUv.y * sCount ) );\ncResult += cTextureScreen.rgb * vec3( sc.x, sc.y, sc.x ) * sIntensity;\ncResult = cTextureScreen.rgb + clamp( nIntensity, 0.0,1.0 ) * ( cResult - cTextureScreen.rgb );\nif( grayscale ) {\ncResult = vec3( cResult.r * 0.3 + cResult.g * 0.59 + cResult.b * 0.11 );\n}\ngl_FragColor =  vec4( cResult, cTextureScreen.a );\n}"},
-sepia:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},amount:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float amount;\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nvec3 c = color.rgb;\ncolor.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );\ncolor.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );\ncolor.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );\ngl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );\n}"},
+sepia:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},amount:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float amount;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nvec3 c = color.rgb;\ncolor.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );\ncolor.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );\ncolor.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );\ngl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );\n}"},
 dotscreen:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},tSize:{type:"v2",value:new THREE.Vector2(256,256)},center:{type:"v2",value:new THREE.Vector2(0.5,0.5)},angle:{type:"f",value:1.57},scale:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform vec2 center;\nuniform float angle;\nuniform float scale;\nuniform vec2 tSize;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nfloat pattern() {\nfloat s = sin( angle ), c = cos( angle );\nvec2 tex = vUv * tSize - center;\nvec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;\nreturn ( sin( point.x ) * sin( point.y ) ) * 4.0;\n}\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nfloat average = ( color.r + color.g + color.b ) / 3.0;\ngl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );\n}"},
+vignette:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},offset:{type:"f",value:1},darkness:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float offset;\nuniform float darkness;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nvoid main() {\nvec4 texel = texture2D( tDiffuse, vUv );\nvec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );\ngl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );\n}"},
 screen:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},opacity:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float opacity;\nvoid main() {\nvec4 texel = texture2D( tDiffuse, vUv );\ngl_FragColor = opacity * texel;\n}"},basic:{uniforms:{},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",
 fragmentShader:"void main() {\ngl_FragColor = vec4( 1.0, 0.0, 0.0, 0.5 );\n}"}},buildKernel:function(b){var c,e,f,g,j=2*Math.ceil(b*3)+1;j>25&&(j=25);g=(j-1)*0.5;e=Array(j);for(c=f=0;c<j;++c)e[c]=Math.exp(-((c-g)*(c-g))/(2*b*b)),f+=e[c];for(c=0;c<j;++c)e[c]/=f;return e}};
 THREE.AnimationHandler=function(){var b=[],c={},e={update:function(c){for(var e=0;e<b.length;e++)b[e].update(c)},addToUpdate:function(c){b.indexOf(c)===-1&&b.push(c)},removeFromUpdate:function(c){c=b.indexOf(c);c!==-1&&b.splice(c,1)},add:function(b){c[b.name]!==void 0&&console.log("THREE.AnimationHandler.add: Warning! "+b.name+" already exists in library. Overwriting.");c[b.name]=b;if(b.initialized!==!0){for(var e=0;e<b.hierarchy.length;e++){for(var f=0;f<b.hierarchy[e].keys.length;f++){if(b.hierarchy[e].keys[f].time<

+ 2 - 1
build/custom/ThreeExtras.js

@@ -22,8 +22,9 @@ THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:"attribute vec4 tang
 cube:{uniforms:{tCube:{type:"t",value:1,texture:null}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( - wPos.x, wPos.yz ) );\n}"},convolution:{uniforms:{tDiffuse:{type:"t",
 value:0,texture:null},uImageIncrement:{type:"v2",value:new THREE.Vector2(0.001953125,0)},cKernel:{type:"fv1",value:[]}},vertexShader:"varying vec2 vUv;\nuniform vec2 uImageIncrement;\nvoid main(void) {\nvUv = uv - ((KERNEL_SIZE - 1.0) / 2.0) * uImageIncrement;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform vec2 uImageIncrement;\nuniform float cKernel[KERNEL_SIZE];\nvoid main(void) {\nvec2 imageCoord = vUv;\nvec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );\nfor( int i=0; i<KERNEL_SIZE; ++i ) {\nsum += texture2D( tDiffuse, imageCoord ) * cKernel[i];\nimageCoord += uImageIncrement;\n}\ngl_FragColor = sum;\n}"},
 film:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},time:{type:"f",value:0},nIntensity:{type:"f",value:0.5},sIntensity:{type:"f",value:0.05},sCount:{type:"f",value:4096},grayscale:{type:"i",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float time;\nuniform bool grayscale;\nuniform float nIntensity;\nuniform float sIntensity;\nuniform float sCount;\nvoid main() {\nvec4 cTextureScreen = texture2D( tDiffuse, vUv );\nfloat x = vUv.x * vUv.y * time *  1000.0;\nx = mod( x, 13.0 ) * mod( x, 123.0 );\nfloat dx = mod( x, 0.01 );\nvec3 cResult = cTextureScreen.rgb + cTextureScreen.rgb * clamp( 0.1 + dx * 100.0, 0.0, 1.0 );\nvec2 sc = vec2( sin( vUv.y * sCount ), cos( vUv.y * sCount ) );\ncResult += cTextureScreen.rgb * vec3( sc.x, sc.y, sc.x ) * sIntensity;\ncResult = cTextureScreen.rgb + clamp( nIntensity, 0.0,1.0 ) * ( cResult - cTextureScreen.rgb );\nif( grayscale ) {\ncResult = vec3( cResult.r * 0.3 + cResult.g * 0.59 + cResult.b * 0.11 );\n}\ngl_FragColor =  vec4( cResult, cTextureScreen.a );\n}"},
-sepia:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},amount:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float amount;\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nvec3 c = color.rgb;\ncolor.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );\ncolor.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );\ncolor.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );\ngl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );\n}"},
+sepia:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},amount:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float amount;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nvec3 c = color.rgb;\ncolor.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );\ncolor.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );\ncolor.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );\ngl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );\n}"},
 dotscreen:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},tSize:{type:"v2",value:new THREE.Vector2(256,256)},center:{type:"v2",value:new THREE.Vector2(0.5,0.5)},angle:{type:"f",value:1.57},scale:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform vec2 center;\nuniform float angle;\nuniform float scale;\nuniform vec2 tSize;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nfloat pattern() {\nfloat s = sin( angle ), c = cos( angle );\nvec2 tex = vUv * tSize - center;\nvec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;\nreturn ( sin( point.x ) * sin( point.y ) ) * 4.0;\n}\nvoid main() {\nvec4 color = texture2D( tDiffuse, vUv );\nfloat average = ( color.r + color.g + color.b ) / 3.0;\ngl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );\n}"},
+vignette:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},offset:{type:"f",value:1},darkness:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float offset;\nuniform float darkness;\nvarying vec2 vUv;\nuniform sampler2D tDiffuse;\nvoid main() {\nvec4 texel = texture2D( tDiffuse, vUv );\nvec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );\ngl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );\n}"},
 screen:{uniforms:{tDiffuse:{type:"t",value:0,texture:null},opacity:{type:"f",value:1}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"varying vec2 vUv;\nuniform sampler2D tDiffuse;\nuniform float opacity;\nvoid main() {\nvec4 texel = texture2D( tDiffuse, vUv );\ngl_FragColor = opacity * texel;\n}"},basic:{uniforms:{},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",
 fragmentShader:"void main() {\ngl_FragColor = vec4( 1.0, 0.0, 0.0, 0.5 );\n}"}},buildKernel:function(a){var b,c,e,f,h=2*Math.ceil(a*3)+1;h>25&&(h=25);f=(h-1)*0.5;c=Array(h);for(b=e=0;b<h;++b)c[b]=Math.exp(-((b-f)*(b-f))/(2*a*a)),e+=c[b];for(b=0;b<h;++b)c[b]/=e;return c}};
 THREE.AnimationHandler=function(){var a=[],b={},c={update:function(c){for(var b=0;b<a.length;b++)a[b].update(c)},addToUpdate:function(c){a.indexOf(c)===-1&&a.push(c)},removeFromUpdate:function(c){c=a.indexOf(c);c!==-1&&a.splice(c,1)},add:function(a){b[a.name]!==void 0&&console.log("THREE.AnimationHandler.add: Warning! "+a.name+" already exists in library. Overwriting.");b[a.name]=a;if(a.initialized!==!0){for(var c=0;c<a.hierarchy.length;c++){for(var e=0;e<a.hierarchy[c].keys.length;e++){if(a.hierarchy[c].keys[e].time<

+ 46 - 0
examples/js/postprocessing/VignettePass.js

@@ -0,0 +1,46 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.VignettePass = function( offset, darkness ) {
+
+	var shader = THREE.ShaderUtils.lib[ "vignette" ];
+
+	this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+
+	if ( offset !== undefined )	this.uniforms[ "offset"].value = offset;
+	if ( darkness !== undefined ) this.uniforms[ "darkness"].value = darkness;
+
+	this.material = new THREE.MeshShaderMaterial( {
+
+		uniforms: this.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader
+
+	} );
+
+	this.renderToScreen = false;
+
+};
+
+THREE.VignettePass.prototype = {
+
+	render: function ( renderer, renderTarget, delta ) {
+
+		this.uniforms[ "tDiffuse" ].texture = renderTarget;
+
+		THREE.EffectComposer.quad.materials[ 0 ] = this.material;
+
+		if ( this.renderToScreen ) {
+
+			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera );
+
+		} else {
+
+			renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, renderTarget, false );
+
+		}
+
+	}
+
+};

+ 18 - 10
examples/webgl_postprocessing.html

@@ -17,8 +17,8 @@
 		    }
 
 		    #info {
-			color:#000;
-			background-color: rgba( 255, 255, 255, 0.95 );
+			color:#fff;
+			background-color: rgba( 0, 0, 0, 0.5 );
 			position: relative;
 			margin: 0 auto -2em;
 			top: 0px;
@@ -48,6 +48,7 @@
 		<script type="text/javascript" src="js/postprocessing/SepiaPass.js"></script>
 		<script type="text/javascript" src="js/postprocessing/DotScreenPass.js"></script>
 		<script type="text/javascript" src="js/postprocessing/ScreenPass.js"></script>
+		<script type="text/javascript" src="js/postprocessing/VignettePass.js"></script>
 
 		<script type="text/javascript" src="js/Detector.js"></script>
 		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
@@ -62,7 +63,8 @@
 
 			void main() {
 
-				gl_FragColor = vec4( time, vUv.x, vUv.y, 1.0 );
+				//gl_FragColor = vec4( time, vUv.x, vUv.y, 1.0 );
+				gl_FragColor = vec4( 0.2, 0.4, 0.5, 1.0 );
 
 			}
 
@@ -155,23 +157,27 @@
 
 				container.appendChild( renderer.domElement );
 
+				//
+
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
 				stats.domElement.style.top = '0px';
-				container.appendChild( stats.domElement );
+				//container.appendChild( stats.domElement );
 
 				//
 
 				var effectBloom = new THREE.BloomPass( 0.75 );
-				var effectFilm = new THREE.FilmPass( 0.35, 0.5, 2048, false );
+				var effectFilm = new THREE.FilmPass( 0.75, 0.025, 648, false );
 				var effectFilmBW = new THREE.FilmPass( 0.35, 0.5, 2048, true );
 				var effectSepia = new THREE.SepiaPass( 1.0 );
 				var effectScreen = new THREE.ScreenPass();
 				var effectDotScreen = new THREE.DotScreenPass( new THREE.Vector2( 0, 0 ), 0.5, 0.4 );
+				var effectVignette = new THREE.VignettePass( 0.95, 1.6 );
 
-				effectFilm.renderToScreen = true;
-				effectFilmBW.renderToScreen = true;
-				effectDotScreen.renderToScreen = true;
+				//effectFilm.renderToScreen = true;
+				//effectFilmBW.renderToScreen = true;
+				//effectDotScreen.renderToScreen = true;
+				effectVignette.renderToScreen = true;
 
 				//
 
@@ -215,6 +221,7 @@
 				composer1.addPass( renderScene );
 				composer1.addPass( effectBloom );
 				composer1.addPass( effectFilmBW );
+				composer1.addPass( effectVignette );
 
 				//
 
@@ -222,6 +229,7 @@
 
 				composer2.addPass( renderScene );
 				composer2.addPass( effectDotScreen );
+				composer2.addPass( effectVignette );
 
 				//
 
@@ -230,6 +238,7 @@
 				composer3.addPass( renderScene );
 				composer3.addPass( effectSepia );
 				composer3.addPass( effectFilm );
+				composer3.addPass( effectVignette );
 
 				//
 
@@ -237,8 +246,7 @@
 
 				composer4.addPass( renderScene );
 				composer4.addPass( effectBloom );
-				composer4.addPass( effectSepia );
-				composer4.addPass( effectScreen );
+				composer4.addPass( effectVignette );
 
 				//
 

+ 65 - 3
src/extras/ShaderUtils.js

@@ -574,7 +574,7 @@ THREE.ShaderUtils = {
 			uniforms: {
 
 				tDiffuse: { type: "t", value: 0, texture: null },
-				amount: { type: "f", value: 1.0 }
+				amount:   { type: "f", value: 1.0 }
 
 			},
 
@@ -593,9 +593,10 @@ THREE.ShaderUtils = {
 
 			fragmentShader: [
 
+				"uniform float amount;",
+
 				"varying vec2 vUv;",
 				"uniform sampler2D tDiffuse;",
-				"uniform float amount;",
 
 				"void main() {",
 
@@ -680,6 +681,67 @@ THREE.ShaderUtils = {
 
 		},
 
+		/* ------------------------------------------------------------------------------------------------
+		//	Vignette shader
+		//	- based on PaintEffect postprocess from ro.me
+		//		http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js
+		 ------------------------------------------------------------------------------------------------ */
+
+		'vignette': {
+
+			uniforms: {
+
+				tDiffuse: { type: "t", value: 0, texture: null },
+				offset:   { type: "f", value: 1.0 },
+				darkness: { type: "f", value: 1.0 }
+
+			},
+
+			vertexShader: [
+
+				"varying vec2 vUv;",
+
+				"void main() {",
+
+					"vUv = vec2( uv.x, 1.0 - uv.y );",
+					"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+				"}"
+
+			].join("\n"),
+
+			fragmentShader: [
+
+				"uniform float offset;",
+				"uniform float darkness;",
+
+				"varying vec2 vUv;",
+				"uniform sampler2D tDiffuse;",
+
+				"void main() {",
+
+					// Eskil's vignette
+
+					"vec4 texel = texture2D( tDiffuse, vUv );",
+					"vec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );",
+					"gl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );",
+
+					/*
+					// alternative version from glfx.js
+					// this one makes more "dusty" look (as opposed to "burned")
+
+					"vec4 color = texture2D( tDiffuse, vUv );",
+					"float dist = distance( vUv, vec2( 0.5 ) );",
+					"color.rgb *= smoothstep( 0.8, offset * 0.799, dist *( darkness + offset ) );",
+					"gl_FragColor = color;",
+					*/
+
+				"}"
+
+			].join("\n")
+
+		},
+
 		/* -------------------------------------------------------------------------
 		//	Full-screen textured quad shader
 		 ------------------------------------------------------------------------- */
@@ -689,7 +751,7 @@ THREE.ShaderUtils = {
 			uniforms: {
 
 				tDiffuse: { type: "t", value: 0, texture: null },
-				opacity: { type: "f", value: 1.0 }
+				opacity:  { type: "f", value: 1.0 }
 
 			},