Browse Source

Added deferred shading example with morph animation.

Started with extraction of deferred shading code snippets into more reusable components.
alteredq 12 years ago
parent
commit
05e363b4a8

+ 4 - 4
build/three.js

@@ -10813,7 +10813,7 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f
 	this.name = '';
 
 	this.image = image;
-	this.mipmaps = null;
+	this.mipmaps = [];
 
 	this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();
 
@@ -10850,7 +10850,7 @@ THREE.Texture.prototype = {
 		if ( texture === undefined ) texture = new THREE.Texture();
 
 		texture.image = this.image;
-		texture.mipmaps = this.mipmaps;
+		texture.mipmaps = this.mipmaps.slice(0);
 
 		texture.mapping = this.mapping;
 
@@ -22253,7 +22253,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				// if there are no manual mipmaps
 				// set 0 level mipmap and then use GL to generate other mipmap levels
 
-				if ( mipmaps && isImagePowerOfTwo ) {
+				if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
 
 					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
 
@@ -22288,7 +22288,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				// if there are no manual mipmaps
 				// set 0 level mipmap and then use GL to generate other mipmap levels
 
-				if ( mipmaps && isImagePowerOfTwo ) {
+				if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
 
 					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
 

File diff suppressed because it is too large
+ 9 - 9
build/three.min.js


+ 434 - 0
examples/js/ShaderDeferred.js

@@ -0,0 +1,434 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author MPanknin / http://www.redplant.de/
+ *
+ */
+
+
+THREE.ShaderDeferred = {
+
+	"clipDepth" : {
+
+		uniforms: { },
+
+		fragmentShader : [
+
+			"varying vec4 clipPos;",
+
+			"void main() {",
+
+				"gl_FragColor = vec4( clipPos.z / clipPos.w, 1.0, 1.0, 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec4 clipPos;",
+
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "default_vertex" ],
+
+				"clipPos = gl_Position;",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	"normals" : {
+
+		uniforms: { },
+
+		fragmentShader : [
+
+			"varying vec3 normalView;",
+
+			"void main() {",
+
+				"gl_FragColor = vec4( vec3( normalView * 0.5 + 0.5 ), 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec3 normalView;",
+
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "morphnormal_vertex" ],
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "default_vertex" ],
+
+				"vec3 objectNormal;",
+
+				"#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )",
+
+					"objectNormal = morphedNormal;",
+
+				"#endif",
+
+				"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )",
+
+					"objectNormal = normal;",
+
+				"#endif",
+
+				"normalView = normalize( normalMatrix * objectNormal );",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	"bump" : {
+
+		uniforms: {
+
+			bumpMap: 	  { type: "t", value: null },
+			bumpScale:	  { type: "f", value: 1 },
+			offsetRepeat: { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }
+
+		},
+
+		fragmentShader : [
+
+			"#extension GL_OES_standard_derivatives : enable\n",
+
+			"varying vec3 normalView;",
+			"varying vec2 vUv;",
+			"varying vec3 vViewPosition;",
+
+			"uniform sampler2D bumpMap;",
+			"uniform float bumpScale;",
+
+			// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
+			//	http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html
+
+			// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
+
+			"vec2 dHdxy_fwd() {",
+
+				"vec2 dSTdx = dFdx( vUv );",
+				"vec2 dSTdy = dFdy( vUv );",
+
+				"float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
+				"float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
+				"float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
+
+				"return vec2( dBx, dBy );",
+
+			"}",
+
+			"vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
+
+				"vec3 vSigmaX = dFdx( surf_pos );",
+				"vec3 vSigmaY = dFdy( surf_pos );",
+				"vec3 vN = surf_norm;",		// normalized
+
+				"vec3 R1 = cross( vSigmaY, vN );",
+				"vec3 R2 = cross( vN, vSigmaX );",
+
+				"float fDet = dot( vSigmaX, R1 );",
+
+				"vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
+				"return normalize( abs( fDet ) * surf_norm - vGrad );",
+
+			"}",
+
+			"void main() {",
+
+				"vec3 normal = normalize( normalView );",
+				"normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",
+				"gl_FragColor = vec4( vec3( normal * 0.5 + 0.5 ), 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec3 normalView;",
+			"varying vec2 vUv;",
+			"varying vec3 vViewPosition;",
+
+			"uniform vec4 offsetRepeat;",
+
+			"void main() {",
+
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				"gl_Position = projectionMatrix * mvPosition;",
+				"normalView = normalize( normalMatrix * normal );",
+				"vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",
+				"vViewPosition = -mvPosition.xyz;",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	"unlit" : {
+
+		uniforms: {
+
+			samplerDepth: { type: "t", value: null },
+			viewWidth:    { type: "f", value: 800 },
+			viewHeight:   { type: "f", value: 600 },
+			lightColor:   { type: "v3", value: new THREE.Vector3( 0, 0, 0 ) }
+
+		},
+
+		fragmentShader : [
+
+			"varying vec4 clipPos;",
+			"uniform sampler2D samplerDepth;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+
+			"void main() {",
+
+				"vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );",
+				"float z = texture2D( samplerDepth, texCoord ).x;",
+				"vec4 color = vec4( lightColor, 1.0 );",
+				"float depth = clipPos.z / clipPos.w;",
+				"if( depth > z && z > 0.0 ) color.w = 0.0;",
+				"gl_FragColor = color;",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec4 clipPos;",
+
+			"void main() {",
+
+				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+				"clipPos = gl_Position;",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	"composite" : {
+
+		uniforms: {
+
+			samplerLightBuffer: { type: "t", value: null },
+			samplerEmitter: 	{ type: "t", value: null }
+
+		},
+
+		fragmentShader : [
+
+			"varying vec2 texCoord;",
+			"uniform sampler2D samplerLightBuffer;",
+			"uniform sampler2D samplerEmitter;",
+			"uniform vec3 lightPos;",
+
+			"void main() {",
+
+				"vec3 color = texture2D( samplerLightBuffer, texCoord ).xyz;",
+				"vec3 emitter = texture2D( samplerEmitter, texCoord ).xyz;",
+
+				"if ( emitter != vec3( 0.0 ) ) {",
+
+					"gl_FragColor = vec4( emitter, 1.0 );",
+
+				"} else {",
+
+					"gl_FragColor = vec4( sqrt( color ), 1.0 );",
+
+				"}",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec2 texCoord;",
+
+			"void main() {",
+
+				"vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );",
+				"texCoord = pos.xy * vec2( 0.5 ) + 0.5;",
+				"gl_Position = pos;",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	"light" : {
+
+		uniforms: {
+
+			samplerLightBuffer: { type: "t", value: null },
+			samplerNormals: { type: "t", value: null },
+			samplerDepth: 	{ type: "t", value: null },
+			samplerColor: 	{ type: "t", value: null },
+			matView: 		{ type: "m4", value: new THREE.Matrix4() },
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+			viewWidth: 		{ type: "f", value: 800 },
+			viewHeight: 	{ type: "f", value: 600 },
+			lightPos: 		{ type: "v3", value: new THREE.Vector3( 0, 0, 0 ) },
+			lightColor: 	{ type: "v3", value: new THREE.Vector3( 0, 0, 0 ) },
+			lightIntensity: { type: "f", value: 1.0 },
+			lightRadius: 	{ type: "f", value: 1.0 }
+
+		},
+
+		fragmentShader : [
+
+			"varying vec3 lightView;",
+			"varying vec4 clipPos;",
+
+			"uniform sampler2D samplerColor;",
+			"uniform sampler2D samplerDepth;",
+			"uniform sampler2D samplerNormals;",
+			"uniform sampler2D samplerLightBuffer;",
+
+			"uniform float lightRadius;",
+			"uniform float lightIntensity;",
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+
+			"uniform mat4 matProjInverse;",
+
+			"void main() {",
+
+				"vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );",
+
+				"float z = texture2D( samplerDepth, texCoord ).x;",
+				"float lightZ = clipPos.z / clipPos.w;",
+
+				/*
+				"if ( z == 0.0 ) {",
+
+					"gl_FragColor = vec4( vec3( 0.0 ), 1.0 );",
+					"return;",
+
+				"}",
+				*/
+
+				"if ( z == 0.0 || lightZ > z ) discard;",
+
+				"float x = texCoord.x * 2.0 - 1.0;",
+				"float y = texCoord.y * 2.0 - 1.0;",
+
+				"vec4 projectedPos = vec4( x, y, z, 1.0 );",
+
+				"vec4 viewPos = matProjInverse * projectedPos;",
+				"viewPos.xyz /= viewPos.w;",
+				"viewPos.w = 1.0;",
+
+				"vec3 lightDir = lightView - viewPos.xyz;",
+				"float dist = length( lightDir );",
+
+				"if ( dist > lightRadius ) discard;",
+
+				"lightDir = normalize( lightDir );",
+
+				"float cutoff = 0.3;",
+				"float denom = dist/lightRadius + 1.0;",
+				"float attenuation = 1.0 / ( denom * denom );",
+				"attenuation = ( attenuation - cutoff ) / ( 1.0 - cutoff );",
+				"attenuation = max( attenuation, 0.0 );",
+				"attenuation *= attenuation;",
+
+				"vec3 normal = texture2D( samplerNormals, texCoord ).xyz * 2.0 - 1.0;",
+
+				// wrap around lighting
+
+				"float diffuseFull = max( dot( normal, lightDir ), 0.0 );",
+				"float diffuseHalf = max( 0.5 + 0.5 * dot( normal, lightDir ), 0.0 );",
+
+				"const vec3 wrapRGB = vec3( 0.6, 0.2, 0.2 );",
+				"vec3 diffuse = mix( vec3 ( diffuseFull ), vec3( diffuseHalf ), wrapRGB );",
+
+				// simple lighting
+
+				//"float diffuseFull = max( dot( normal, lightDir ), 0.0 );",
+				//"vec3 diffuse = vec3 ( diffuseFull );",
+
+				// specular
+
+				"const float shininess = 75.0;",
+				"const float specularIntensity = 0.4;",
+
+				"vec3 halfVector = normalize( lightDir - normalize( viewPos.xyz ) );",
+				"float dotNormalHalf = max( dot( normal, halfVector ), 0.0 );",
+
+				// simple specular
+
+				//"vec3 specular = specularIntensity * max( pow( dotNormalHalf, shininess ), 0.0 ) * diffuse;",
+
+				// physically based specular
+
+				"vec3 specularColor = specularIntensity * vec3( 0.312 );",
+
+				"float specularNormalization = ( shininess + 2.0001 ) / 8.0;",
+
+				"vec3 schlick = specularColor + vec3( 1.0 - specularColor ) * pow( 1.0 - dot( lightDir, halfVector ), 5.0 );",
+				"vec3 specular = schlick * max( pow( dotNormalHalf, shininess ), 0.0 ) * diffuse * specularNormalization;",
+
+				// color
+
+				"vec4 albedo = texture2D( samplerColor, texCoord );",
+
+				// combine
+
+				"vec4 color = vec4( 0.0 );",
+				"color.xyz = albedo.xyz * lightColor * lightIntensity;",
+				"color.w = attenuation;",
+				//"gl_FragColor = color * vec4( diffuse + specular, 1.0 );",
+				"gl_FragColor = color * vec4( diffuse, 1.0 ) + vec4( lightColor * lightIntensity * specular, attenuation );",
+
+			"}"
+
+		].join("\n"),
+
+		vertexShader : [
+
+			"varying vec3 lightView;",
+			"varying vec4 clipPos;",
+			"uniform vec3 lightPos;",
+			"uniform mat4 matView;",
+
+			"void main() { ",
+
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				"gl_Position = projectionMatrix * mvPosition;",
+				"lightView = vec3( matView * vec4( lightPos, 1.0 ) );",
+				"clipPos = gl_Position;",
+
+			"}"
+
+		].join("\n")
+
+	}
+
+
+};

File diff suppressed because it is too large
+ 43 - 0
examples/models/animated/elderlyWalk.js


+ 826 - 0
examples/webgl_lights_deferred_morphs.html

@@ -0,0 +1,826 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js webgl - deferred rendering [morphs]</title>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background-color: #000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 20px; width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+			}
+
+			a {
+				color: #ff0080;
+				text-decoration: none;
+			}
+
+			a:hover {
+				color: #0080ff;
+			}
+
+			#stats { position: absolute; top:10px; left: 5px }
+			#stats #fps { background: transparent !important }
+			#stats #fps #fpsText { color: #aaa !important }
+			#stats #fps #fpsGraph { display: none }
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> - webgl deferred rendering with morph animation -
+			character from <a href="http://www.sintel.org/">Sintel</a>
+		</div>
+		<div id="container"></div>
+
+
+		<script src="js/libs/stats.min.js"></script>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+
+		<script src="js/ShaderDeferred.js"></script>
+
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/FXAAShader.js"></script>
+		<script src="js/shaders/ColorCorrectionShader.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+
+		<script src="js/controls/TrackballControls.js"></script>
+
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var SCALE = 0.75;
+			var MARGIN = 100;
+
+			var WIDTH = window.innerWidth;
+			var HEIGHT = window.innerHeight - 2 * MARGIN;
+
+			var NEAR = 1.0, FAR = 350.0;
+			var VIEW_ANGLE = 45;
+			var ASPECT = WIDTH / HEIGHT;
+
+			var mouseX = 0;
+			var mouseY = 0;
+
+			var targetX = 0, targetY = 0;
+			var angle = 0;
+			var target = new THREE.Vector3( 0, 0, 0 );
+
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			// core
+
+			var renderer, camera, controls, stats, clock;
+
+			// scenes and scene nodes
+
+			var lightScene, lightNode, scene, sceneNode, emitterScene, emitterNode, quadScene, quadNode;
+
+			// rendertargets
+
+			var rtColor, rtNormals, rtDepth, rtLightBuffer, rtEmitter, rtFinal;
+
+			// composer
+
+			var compColor, compNormals, compDepth, compLightBuffer, compFinal, compEmitter, compositePass;
+			var effectFXAA;
+
+			// materials
+
+			var normalShader, bumpShader, clipDepthShader, lightShader, unlitShader, compositeShader;
+			var matNormal, matClipDepth, matBasic, matUnlit;
+
+			// lights
+
+			var numLights = 50;
+			var lights = new Array();
+
+			// morphs
+
+			var morphs = [];
+
+			// -----------------------------
+
+			function bootstrap() {
+
+				renderer = new THREE.WebGLRenderer( { alpha: false } );
+				renderer.setSize( WIDTH, HEIGHT );
+				renderer.setClearColorHex( 0x000000, 1 );
+
+				renderer.domElement.style.position = "absolute";
+				renderer.domElement.style.top = MARGIN + "px";
+				renderer.domElement.style.left = "0px";
+
+				var container = document.getElementById( 'container' );
+				container.appendChild( renderer.domElement );
+
+				// scene camera
+
+				camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR );
+				camera.position.z = 150;
+
+				controls = new THREE.TrackballControls( camera, renderer.domElement );
+
+				// scene for walt's head model
+
+				scene = new THREE.Scene();
+				sceneNode = new THREE.Object3D();
+				scene.add( sceneNode );
+				scene.add( camera );
+
+				// scene for light proxy geometry
+
+				lightScene = new THREE.Scene();
+				lightNode = new THREE.Object3D();
+				lightScene.add( lightNode );
+
+				// scene for the coloured emitter spheres
+
+				emitterScene = new THREE.Scene();
+				emitterNode = new THREE.Object3D();
+				emitterScene.add( emitterNode );
+
+				// full screen quad for compositing
+
+				quadScene = new THREE.Scene();
+				quadNode = new THREE.Object3D();
+				quadScene.add( quadNode );
+				quadNode.add( new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 ) ) );
+
+				// stats
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '8px';
+				stats.domElement.style.zIndex = 100;
+				container.appendChild( stats.domElement );
+
+				// clock
+
+				clock = new THREE.Clock();
+
+			}
+
+			// -----------------------------
+
+			function createRenderTargets() {
+
+				var rtParamsFloat = { minFilter: THREE.NearestFilter, magFilter: THREE.LinearFilter, stencilBuffer: false,
+							          format: THREE.RGBAFormat, type: THREE.FloatType };
+
+				var rtParamsUByte = { minFilter: THREE.NearestFilter, magFilter: THREE.LinearFilter, stencilBuffer: false,
+							          format: THREE.RGBFormat, type: THREE.UnsignedByteType };
+
+				// ----------------------------------------------------------
+				// g-buffer
+				// ----------------------------------------------------------
+
+				rtNormals = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsFloat );
+				rtDepth = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsFloat );
+				rtColor = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsUByte );
+				rtFinal = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsUByte );
+
+				rtNormals.generateMipmaps = false;
+				rtDepth.generateMipmaps = false;
+				rtColor.generateMipmaps = false;
+				rtFinal.generateMipmaps = false;
+
+				var passNormals = new THREE.RenderPass( scene, camera );
+				compNormals = new THREE.EffectComposer( renderer, rtNormals );
+				compNormals.addPass( passNormals );
+
+				var passDepth = new THREE.RenderPass( scene, camera );
+				compDepth = new THREE.EffectComposer( renderer, rtDepth );
+				compDepth.addPass( passDepth );
+
+				var passColor = new THREE.RenderPass( scene, camera );
+				compColor = new THREE.EffectComposer( renderer, rtColor );
+				compColor.addPass( passColor );
+
+				// ----------------------------------------------------------
+				// light emitter spheres
+				// ----------------------------------------------------------
+
+				var emitterPass = new THREE.RenderPass( emitterScene, camera );
+				rtEmitter = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsUByte );
+				rtEmitter.generateMipmaps = false;
+
+				compEmitter = new THREE.EffectComposer( renderer, rtEmitter );
+				compEmitter.addPass( emitterPass );
+
+				// ----------------------------------------------------------
+				// lighting pass
+				// ----------------------------------------------------------
+
+				rtLightBuffer = new THREE.WebGLRenderTarget( SCALE * WIDTH, SCALE * HEIGHT, rtParamsFloat );
+				rtLightBuffer.generateMipmaps = false;
+
+				var passLight = new THREE.RenderPass( lightScene, camera );
+				compLightBuffer = new THREE.EffectComposer( renderer, rtLightBuffer );
+				compLightBuffer.addPass( passLight );
+
+				lightShader.uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
+				lightShader.uniforms[ 'samplerNormals' ].value = compNormals.renderTarget2;
+				lightShader.uniforms[ 'samplerDepth' ].value = compDepth.renderTarget2;
+				lightShader.uniforms[ 'samplerLightBuffer' ].value = rtLightBuffer;
+
+				var geomEmitter = new THREE.SphereGeometry( 0.7, 7, 7 );
+
+				for ( var x = 0; x < numLights; x ++ ) {
+
+					var light = lights[ x ];
+
+					// setup material
+
+					var matLight = new THREE.ShaderMaterial({
+
+						uniforms:       THREE.UniformsUtils.clone( lightShader.uniforms ),
+						vertexShader:   lightShader.vertexShader,
+						fragmentShader: lightShader.fragmentShader
+
+					});
+
+					matLight.blending = THREE.AdditiveBlending;
+					matLight.transparent = true;
+					matLight.depthWrite = false;
+					matLight.uniforms[ "lightPos" ].value = light.position;
+					matLight.uniforms[ "lightRadius" ].value = light.distance;
+					matLight.uniforms[ "lightIntensity" ].value = light.intensity;
+					matLight.uniforms[ "lightColor" ].value = light.color;
+
+					// setup proxy geometry for this light
+
+					var geomLight = new THREE.SphereGeometry( light.distance, 16, 8 );
+					var meshLight = new THREE.Mesh( geomLight, matLight );
+					lightNode.add( meshLight );
+
+					// create emitter sphere
+
+					var matEmitter = new THREE.ShaderMaterial({
+
+						uniforms:       THREE.UniformsUtils.clone( unlitShader.uniforms ),
+						vertexShader:   unlitShader.vertexShader,
+						fragmentShader: unlitShader.fragmentShader
+
+					});
+
+					var meshEmitter = new THREE.Mesh( geomEmitter, matEmitter );
+					meshEmitter.position = light.position;
+					emitterNode.add( meshEmitter );
+
+					// add emitter to light node
+
+					meshLight.emitter = meshEmitter;
+
+				}
+
+				// ----------------------------------------------------------
+				// composite
+				// ----------------------------------------------------------
+
+				compositeShader.uniforms[ 'samplerLightBuffer' ].value = compLightBuffer.renderTarget2;
+				compositeShader.uniforms[ 'samplerEmitter' ].value = compEmitter.renderTarget2;
+
+				compositePass = new THREE.ShaderPass( compositeShader );
+				compositePass.needsSwap = true;
+
+				effectFXAA = new THREE.ShaderPass( THREE.FXAAShader );
+				effectFXAA.uniforms[ 'resolution' ].value.set( 1 / ( SCALE * WIDTH ), 1 / ( SCALE * HEIGHT ) );
+
+				var effectColor = new THREE.ShaderPass( THREE.ColorCorrectionShader );
+				effectColor.renderToScreen = true;
+				effectColor.uniforms[ 'powRGB' ].value.set( 1, 1, 1 );
+				effectColor.uniforms[ 'mulRGB' ].value.set( 2, 2, 2 );
+
+				compFinal = new THREE.EffectComposer( renderer, rtFinal );
+				compFinal.addPass( compositePass );
+				compFinal.addPass( effectFXAA );
+				compFinal.addPass( effectColor );
+
+			}
+
+			// -----------------------------
+
+			function initScene( object, y, scale ) {
+
+				var shader = THREE.ShaderLib[ "basic" ];
+
+				object.traverse( function( node ) {
+
+					if ( node.material ) {
+
+						// color material
+
+						var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+						var defines = { "USE_MAP": !!node.material.map, "GAMMA_INPUT": true };
+
+						var material = new THREE.ShaderMaterial( {
+
+							fragmentShader: shader.fragmentShader,
+							vertexShader: 	shader.vertexShader,
+							uniforms: 		uniforms,
+							defines: 		defines,
+							shading:		node.material.shading
+
+						} );
+
+						uniforms.diffuse.value.copy( node.material.color );
+						uniforms.map.value = node.material.map;
+
+						material.vertexColors = node.material.vertexColors;
+						material.morphTargets = node.material.morphTargets;
+						material.morphNormals = node.material.morphNormals;
+
+						if ( node.material.bumpMap ) {
+
+							var offset = node.material.bumpMap.offset;
+							var repeat = node.material.bumpMap.repeat;
+
+							uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+
+						}
+
+						if ( node.material.transparent ) {
+
+							material.alphaTest = 0.1;
+
+						}
+
+						if ( node.material.name === "eyetrans" ) {
+
+							material.visible = false;
+
+						}
+
+						node.properties.colorMaterial = material;
+
+						// normal material
+
+						if ( node.material.bumpMap ) {
+
+							var uniforms = THREE.UniformsUtils.clone( bumpShader.uniforms );
+
+							var normalMaterial = new THREE.ShaderMaterial( {
+
+								uniforms: 		uniforms,
+								vertexShader: 	bumpShader.vertexShader,
+								fragmentShader: bumpShader.fragmentShader
+
+							} );
+
+							uniforms.bumpMap.value = node.material.bumpMap;
+							uniforms.bumpScale.value = node.material.bumpScale;
+
+							var offset = node.material.bumpMap.offset;
+							var repeat = node.material.bumpMap.repeat;
+
+							uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+
+							node.properties.normalMaterial = normalMaterial;
+
+						} else if ( node.material.morphTargets ) {
+
+							var normalMaterial = new THREE.ShaderMaterial( {
+
+								uniforms:       THREE.UniformsUtils.clone( normalShader.uniforms ),
+								vertexShader:   normalShader.vertexShader,
+								fragmentShader: normalShader.fragmentShader,
+								shading:		node.material.shading
+
+							} );
+
+							normalMaterial.morphTargets = node.material.morphTargets;
+							normalMaterial.morphNormals = node.material.morphNormals;
+							node.properties.normalMaterial = normalMaterial;
+
+						} else {
+
+							node.properties.normalMaterial = matNormal;
+
+						}
+
+						// depth material
+
+						if ( node.material.morphTargets ) {
+
+							var depthMaterial = new THREE.ShaderMaterial({
+
+								uniforms:       THREE.UniformsUtils.clone( clipDepthShader.uniforms ),
+								vertexShader:   clipDepthShader.vertexShader,
+								fragmentShader: clipDepthShader.fragmentShader
+
+							});
+
+							depthMaterial.morphTargets = node.material.morphTargets;
+
+							node.properties.depthMaterial = depthMaterial;
+
+						} else {
+
+							node.properties.depthMaterial = matClipDepth;
+
+						}
+
+					}
+
+				} );
+
+				object.position.y = y;
+				object.scale.set( scale, scale, scale );
+				sceneNode.add( object );
+
+			}
+
+			// -----------------------------
+
+			function initMaterials() {
+
+				// -----------------------
+				// shader definitions
+				// -----------------------
+
+				normalShader = THREE.ShaderDeferred[ "normals" ];
+				bumpShader = THREE.ShaderDeferred[ "bump" ];
+				clipDepthShader = THREE.ShaderDeferred[ "clipDepth" ];
+				unlitShader = THREE.ShaderDeferred[ "unlit" ];
+				lightShader = THREE.ShaderDeferred[ "light" ];
+				compositeShader = THREE.ShaderDeferred[ "composite" ];
+
+				unlitShader.uniforms[ "viewWidth" ].value = SCALE * WIDTH;
+				unlitShader.uniforms[ "viewHeight" ].value = SCALE * HEIGHT;
+
+				lightShader.uniforms[ "viewWidth" ].value = SCALE * WIDTH;
+				lightShader.uniforms[ "viewHeight" ].value = SCALE * HEIGHT;
+
+				// -----------------------
+				// default materials
+				// -----------------------
+
+				matNormal = new THREE.ShaderMaterial( {
+
+					uniforms:       THREE.UniformsUtils.clone( normalShader.uniforms ),
+					vertexShader:   normalShader.vertexShader,
+					fragmentShader: normalShader.fragmentShader
+
+				} );
+
+				matClipDepth = new THREE.ShaderMaterial({
+
+					uniforms:       THREE.UniformsUtils.clone( clipDepthShader.uniforms ),
+					vertexShader:   clipDepthShader.vertexShader,
+					fragmentShader: clipDepthShader.fragmentShader
+
+				});
+
+			}
+
+			// -----------------------------
+
+			function initLights() {
+
+				var distance = 40;
+
+				// front light
+
+				var light = new THREE.PointLight();
+
+				light.color = new THREE.Vector3( 1, 1, 1 );
+				light.intensity = 1.5;
+				light.distance = 1.5 * distance;
+
+				lights.push( light );
+
+				// random lights
+
+				for ( var i = 1; i < numLights; i ++ ) {
+
+					var light = new THREE.PointLight();
+
+					light.color = new THREE.Vector3( Math.random(), Math.random(), Math.random() ).normalize();
+
+					// gamma to linear
+
+					light.color.x *= light.color.x;
+					light.color.y *= light.color.y;
+					light.color.z *= light.color.z;
+
+					light.intensity = 2.0;
+					light.distance = distance;
+
+					lights.push( light );
+
+				}
+
+			}
+
+			// -----------------------------
+
+			function onDocumentMouseMove( event ) {
+
+				mouseX = ( event.clientX - windowHalfX ) * 1;
+				mouseY = ( event.clientY - windowHalfY ) * 1;
+
+			}
+
+			// -----------------------------
+
+			function animate() {
+
+				var delta = clock.getDelta();
+
+				requestAnimationFrame( animate );
+
+				//controls.update( delta );
+
+				targetX = mouseX * .001;
+				targetY = mouseY * .001;
+
+				angle += 0.05 * ( targetX - angle );
+
+				camera.position.x = -Math.sin( angle ) * 150;
+				camera.position.z = Math.cos( angle ) * 150;
+
+				camera.lookAt( target );
+
+				for ( var i = 0; i < morphs.length; i ++ ) {
+
+					morph = morphs[ i ];
+					morph.updateAnimation( 1000 * delta );
+
+					morph.position.x += morph.properties.delta * delta;
+					if ( morph.position.x < -50 ) morph.position.x = 200;
+
+				}
+
+				stats.update();
+				render();
+
+			}
+
+			// -----------------------------
+
+			function render() {
+
+				// -----------------------------
+				// g-buffer color
+				// -----------------------------
+
+				sceneNode.traverse( function( node ) {
+
+					if ( node.material ) {
+
+						node.material = node.properties.colorMaterial;
+
+					}
+
+				} );
+
+				compColor.render();
+
+
+				// -----------------------------
+				// g-buffer depth
+				// -----------------------------
+
+				sceneNode.traverse( function( node ) {
+
+					if ( node.material ) {
+
+						node.material = node.properties.depthMaterial;
+
+					}
+
+				} );
+
+				compDepth.render();
+
+
+				// -----------------------------
+				// g-buffer normals
+				// -----------------------------
+
+				sceneNode.traverse( function( node ) {
+
+					if ( node.material ) {
+
+						node.material = node.properties.normalMaterial;
+
+					}
+
+				} );
+
+				compNormals.render();
+
+				// -----------------------------
+				// emitter pass
+				// -----------------------------
+
+				for ( var i = 0, il = lightNode.children.length; i < il; i ++ ) {
+
+					var light = lightNode.children[ i ];
+					var color = light.material.uniforms[ "lightColor" ].value;
+
+					var emitter = light.emitter;
+					emitter.material.uniforms[ "samplerDepth" ].value = compDepth.renderTarget2;
+					emitter.material.uniforms[ "lightColor" ].value = color;
+
+				}
+
+				compEmitter.render();
+
+				// -----------------------------
+				// light pass
+				// -----------------------------
+
+				camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
+
+				for ( var i = 0, il = lightNode.children.length; i < il; i ++ ) {
+
+					var uniforms = lightNode.children[ i ].material.uniforms;
+
+					uniforms[ "matProjInverse" ].value = camera.projectionMatrixInverse;
+					uniforms[ "matView" ].value = camera.matrixWorldInverse;
+
+				}
+
+				var time = Date.now() * 0.0005;
+
+				// update lights
+
+				var x, y, z;
+
+				for ( var i = 0; i < numLights; i ++ ) {
+
+					if ( i > 0 ) {
+
+						x = Math.sin( time + i * 1.7 ) * 80;
+						y = Math.cos( time + i * 1.5 ) * 40;
+						z = Math.cos( time + i * 1.3 ) * 30;
+
+					} else {
+
+						x = Math.sin( time * 3 ) * 20;
+						y = 15;
+						z = Math.cos( time * 3 ) * 25 + 10;
+
+					}
+
+					var light = lightNode.children[ i ];
+					var lightPosition = light.material.uniforms[ "lightPos" ].value;
+
+					lightPosition.x = x;
+					lightPosition.y = y;
+					lightPosition.z = z;
+
+					light.emitter.position = lightPosition;
+					light.position = lightPosition;
+					light.frustumCulled = false;
+
+				}
+
+				compLightBuffer.render();
+
+				// -----------------------------
+				// composite pass
+				// -----------------------------
+
+				compFinal.render( 0.1 );
+
+			}
+
+			function generateBox() {
+
+				var object = new THREE.Object3D();
+
+				var mapHeight2 = THREE.ImageUtils.loadTexture( "obj/lightmap/rocks.jpg" );
+				mapHeight2.repeat.set( 3, 1.5 );
+				mapHeight2.wrapS = mapHeight2.wrapT = THREE.RepeatWrapping;
+				mapHeight2.anisotropy = 4;
+				mapHeight2.format = THREE.RGBFormat;
+
+				var mapHeight3 = THREE.ImageUtils.loadTexture( "textures/water.jpg" );
+				mapHeight3.repeat.set( 16, 8 );
+				mapHeight3.wrapS = mapHeight3.wrapT = THREE.RepeatWrapping;
+				mapHeight3.anisotropy = 4;
+				mapHeight3.format = THREE.RGBFormat;
+
+				var geoPlane = new THREE.PlaneGeometry( 40, 20 );
+				var matPlane = new THREE.MeshPhongMaterial( { color: 0x000000, bumpMap: mapHeight2, bumpScale: 0.5 } );
+				var matPlane2 = new THREE.MeshPhongMaterial( { color: 0x000000, bumpMap: mapHeight3, bumpScale: 0.5 } );
+				var matPlane3 = new THREE.MeshPhongMaterial( { color: 0x000000, bumpMap: mapHeight3, bumpScale: 1 } );
+
+
+				// bottom
+
+				var mesh = new THREE.Mesh( geoPlane, matPlane2 );
+				mesh.position.z = -2;
+				mesh.position.y = -6;
+				mesh.rotation.x = -Math.PI/2;
+				object.add( mesh );
+
+				// top
+
+				var mesh = new THREE.Mesh( geoPlane, matPlane3 );
+				mesh.position.z = -2;
+				mesh.position.y = 7;
+				mesh.rotation.x = Math.PI/2;
+				object.add( mesh );
+
+				// back
+
+				var mesh = new THREE.Mesh( geoPlane, matPlane );
+				mesh.position.z = -4;
+				mesh.position.y = 0;
+				object.add( mesh );
+
+				// right
+
+				var mesh = new THREE.Mesh( geoPlane, matPlane );
+				mesh.position.z = 0;
+				mesh.position.y = 0;
+				mesh.position.x = 13;
+				mesh.rotation.y = -Math.PI/2;
+				//object.add( mesh );
+
+				// left
+
+				var mesh = new THREE.Mesh( geoPlane, matPlane );
+				mesh.position.z = 0;
+				mesh.position.y = 0;
+				mesh.position.x = -13;
+				mesh.rotation.y = Math.PI/2;
+				//object.add( mesh );
+
+				return object;
+
+			}
+
+			// -----------------------------
+			// entry point
+			// -----------------------------
+
+			bootstrap();
+			initMaterials();
+			initLights();
+			createRenderTargets();
+
+			// create animated model
+
+			var loader = new THREE.JSONLoader();
+			loader.load( "models/animated/elderlyWalk.js", function( geometry ) {
+
+				geometry.computeMorphNormals();
+
+				var material = new THREE.MeshPhongMaterial( { color: 0xffffff, morphTargets: true, morphNormals: true, vertexColors: THREE.NoColors, shading: THREE.FlatShading } );
+				var meshAnim = new THREE.MorphAnimMesh( geometry, material );
+
+				meshAnim.duration = 3000;
+				meshAnim.properties.delta = -13;
+
+				var s = 1;
+				meshAnim.scale.set( s, s, s );
+				meshAnim.position.x = 180;
+				meshAnim.position.z = -10;
+				meshAnim.rotation.y = -Math.PI/2;
+
+				morphs.push( meshAnim );
+
+				initScene( meshAnim, -48, 50 );
+
+			} );
+
+			// create box
+
+			var object = generateBox();
+			initScene( object, 0, 8 );
+
+			animate();
+
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+		</script>
+	</body>
+
+</html>

+ 1 - 0
utils/includes/examples.json

@@ -79,6 +79,7 @@
 	"../examples/js/ShaderSkin.js",
 	"../examples/js/ShaderTerrain.js",
 	"../examples/js/ShaderToon.js",
+	"../examples/js/ShaderDeferred.js",
 
 	"../examples/js/Sparks.js",
 	"../examples/js/UVsUtils.js",

Some files were not shown because too many files changed in this diff