Kaynağa Gözat

node material r5 + mirror nodes example (#8886)

SUNAG 9 yıl önce
ebeveyn
işleme
2f4e3023f6

+ 1 - 0
examples/files.js

@@ -152,6 +152,7 @@ var files = {
 		"webgl_materials_video",
 		"webgl_materials_wireframe",
 		"webgl_mirror",
+		"webgl_mirror_nodes",
 		"webgl_modifier_subdivision",
 		"webgl_modifier_tessellation",
 		"webgl_morphnormals",

+ 16 - 7
examples/js/nodes/BuilderNode.js

@@ -7,7 +7,9 @@ THREE.BuilderNode = function( material ) {
 	this.material = material;
 
 	this.caches = [];
-	this.isVerify = false;
+
+	this.parsing = false;
+	this.optimize = true;
 
 	this.addCache();
 
@@ -90,7 +92,13 @@ THREE.BuilderNode.prototype = {
 
 	getFormatName : function( format ) {
 
-		return format.replace( 'c', 'v3' ).replace( /fv1|iv1/, 'v1' );
+		return format.replace( /c/g, 'v3' ).replace( /fv1|iv1/g, 'v1' );
+
+	},
+
+	isFormatMatrix : function( format ) {
+
+		return /^m/.test( format );
 
 	},
 
@@ -119,11 +127,11 @@ THREE.BuilderNode.prototype = {
 
 			case 'v2=v1': return code + '.x';
 			case 'v2=v3': return 'vec3(' + code + ',0.0)';
-			case 'v2=v4': return 'vec4(' + code + ',0.0,0.0)';
+			case 'v2=v4': return 'vec4(' + code + ',0.0,1.0)';
 
 			case 'v3=v1': return code + '.x';
 			case 'v3=v2': return code + '.xy';
-			case 'v3=v4': return 'vec4(' + code + ',0.0)';
+			case 'v3=v4': return 'vec4(' + code + ',1.0)';
 
 			case 'v4=v1': return code + '.x';
 			case 'v4=v2': return code + '.xy';
@@ -134,7 +142,7 @@ THREE.BuilderNode.prototype = {
 
 	},
 
-	getType : function( format ) {
+	getTypeByFormat : function( format ) {
 
 		return THREE.BuilderNode.type[ format ];
 
@@ -164,7 +172,7 @@ THREE.BuilderNode.prototype = {
 
 	isShader : function( shader ) {
 
-		return this.shader == shader || this.isVerify;
+		return this.shader == shader;
 
 	},
 
@@ -181,7 +189,8 @@ THREE.BuilderNode.type = {
 	'float' : 'fv1',
 	vec2 : 'v2',
 	vec3 : 'v3',
-	vec4 : 'v4'
+	vec4 : 'v4',
+	mat4 : 'v4'
 };
 
 THREE.BuilderNode.constructors = [

+ 1 - 1
examples/js/nodes/FunctionCallNode.js

@@ -49,7 +49,7 @@ THREE.FunctionCallNode.prototype.generate = function( builder, output ) {
 		var inpt = func.inputs[ i ];
 		var param = this.inputs[ i ] || this.inputs[ inpt.name ];
 
-		params.push( param.build( builder, builder.getType( inpt.type ) ) );
+		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
 
 	}
 

+ 1 - 1
examples/js/nodes/FunctionNode.js

@@ -33,7 +33,7 @@ THREE.FunctionNode.prototype.parseReference = function( name ) {
 
 THREE.FunctionNode.prototype.getTypeNode = function( builder, type ) {
 
-	return builder.getType( type ) || type;
+	return builder.getTypeByFormat( type ) || type;
 
 };
 

+ 21 - 21
examples/js/nodes/GLNode.js

@@ -13,9 +13,9 @@ THREE.GLNode = function( type ) {
 
 };
 
-THREE.GLNode.prototype.verify = function( builder, cache, requires ) {
+THREE.GLNode.prototype.parse = function( builder, cache, requires ) {
 
-	builder.isVerify = true;
+	builder.parsing = true;
 
 	var material = builder.material;
 
@@ -26,13 +26,13 @@ THREE.GLNode.prototype.verify = function( builder, cache, requires ) {
 
 	builder.removeCache();
 
-	builder.isVerify = false;
+	builder.parsing = false;
 
 };
 
-THREE.GLNode.prototype.verifyAndBuildCode = function( builder, output, cache, requires ) {
+THREE.GLNode.prototype.parseAndBuildCode = function( builder, output, cache, requires ) {
 
-	this.verify( builder, cache, requires );
+	this.parse( builder, cache, requires );
 
 	return this.buildCode( builder, output, cache, requires );
 
@@ -53,27 +53,12 @@ THREE.GLNode.prototype.buildCode = function( builder, output, cache, requires )
 
 };
 
-THREE.GLNode.prototype.verifyDepsNode = function( builder, data, output ) {
-
-	data.deps = ( data.deps || 0 ) + 1;
-
-	var outputLen = builder.getFormatLength( output );
-
-	if ( outputLen > data.outputMax || this.getType( builder ) ) {
-
-		data.outputMax = outputLen;
-		data.output = output;
-
-	}
-
-};
-
 THREE.GLNode.prototype.build = function( builder, output, uuid ) {
 
 	var material = builder.material;
 	var data = material.getDataNode( uuid || this.uuid );
 
-	if ( builder.isShader( 'verify' ) ) this.verifyDepsNode( builder, data, output );
+	if ( builder.parsing ) this.appendDepsNode( builder, data, output );
 
 	if ( this.allow[ builder.shader ] === false ) {
 
@@ -92,6 +77,21 @@ THREE.GLNode.prototype.build = function( builder, output, uuid ) {
 
 };
 
+THREE.GLNode.prototype.appendDepsNode = function( builder, data, output ) {
+
+	data.deps = ( data.deps || 0 ) + 1;
+
+	var outputLen = builder.getFormatLength( output );
+
+	if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder ) ) {
+
+		data.outputMax = outputLen;
+		data.output = output;
+
+	}
+
+};
+
 THREE.GLNode.prototype.getType = function( builder ) {
 
 	return this.type;

+ 4 - 4
examples/js/nodes/InputNode.js

@@ -15,8 +15,8 @@ THREE.InputNode.prototype.generate = function( builder, output, uuid, type, ns,
 
 	var material = builder.material;
 
-	uuid = builder.getUuid( uuid || this.uuid );
-	type = type || this.type;
+	uuid = builder.getUuid( uuid || this.getUuid() );
+	type = type || this.getType( builder );
 
 	var data = material.getDataNode( uuid );
 
@@ -24,7 +24,7 @@ THREE.InputNode.prototype.generate = function( builder, output, uuid, type, ns,
 
 		if ( ! data.vertex ) {
 
-			data.vertex = material.getVertexUniform( this.value, type, ns, needsUpdate );
+			data.vertex = material.createVertexUniform( type, this.value, ns, needsUpdate );
 
 		}
 
@@ -35,7 +35,7 @@ THREE.InputNode.prototype.generate = function( builder, output, uuid, type, ns,
 
 		if ( ! data.fragment ) {
 
-			data.fragment = material.getFragmentUniform( this.value, type, ns, needsUpdate );
+			data.fragment = material.createFragmentUniform( type, this.value, ns, needsUpdate );
 
 		}
 

+ 31 - 8
examples/js/nodes/NodeMaterial.js

@@ -20,7 +20,8 @@ THREE.NodeMaterial.types = {
 	c : 'vec3',
 	v2 : 'vec2',
 	v3 : 'vec3',
-	v4 : 'vec4'
+	v4 : 'vec4',
+	m4 : 'mat4'
 };
 
 THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
@@ -42,7 +43,7 @@ THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
 
 	};
 
-	return (function() {
+	return ( function() {
 
 		var shortcuts = {};
 
@@ -56,7 +57,7 @@ THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
 
 		Object.defineProperties( proto, shortcuts );
 
-	})();
+	} )();
 
 };
 
@@ -109,6 +110,26 @@ THREE.NodeMaterial.prototype.build = function() {
 	this.vertexNode = '';
 	this.fragmentNode = '';
 
+	this.prefixCode = [
+	"#ifdef GL_EXT_shader_texture_lod",
+
+		"#define texCube(a, b) textureCube(a, b)",
+		"#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
+
+		"#define tex2D(a, b) texture2D(a, b)",
+		"#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
+
+	"#else",
+
+		"#define texCube(a, b) textureCube(a, b)",
+		"#define texCubeBias(a, b, c) textureCube(a, b, c)",
+
+		"#define tex2D(a, b) texture2D(a, b)",
+		"#define tex2DBias(a, b, c) texture2D(a, b, c)",
+
+	"#endif"
+	].join( "\n" );
+
 	var builder = new THREE.BuilderNode( this );
 
 	vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
@@ -192,6 +213,7 @@ THREE.NodeMaterial.prototype.build = function() {
 	this.transparent = this.requestAttrib.transparent;
 
 	this.vertexShader = [
+		this.prefixCode,
 		this.vertexPars,
 		this.getCodePars( this.vertexUniform, 'uniform' ),
 		this.getIncludes( this.consts[ 'vertex' ] ),
@@ -204,6 +226,7 @@ THREE.NodeMaterial.prototype.build = function() {
 	].join( "\n" );
 
 	this.fragmentShader = [
+		this.prefixCode,
 		this.fragmentPars,
 		this.getCodePars( this.fragmentUniform, 'uniform' ),
 		this.getIncludes( this.consts[ 'fragment' ] ),
@@ -244,7 +267,7 @@ THREE.NodeMaterial.prototype.mergeUniform = function( uniforms ) {
 
 };
 
-THREE.NodeMaterial.prototype.createUniform = function( value, type, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createUniform = function( type, value, ns, needsUpdate ) {
 
 	var index = this.uniformList.length;
 
@@ -404,9 +427,9 @@ THREE.NodeMaterial.prototype.getCodePars = function( pars, prefix ) {
 
 };
 
-THREE.NodeMaterial.prototype.getVertexUniform = function( value, type, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createVertexUniform = function( type, value, ns, needsUpdate ) {
 
-	var uniform = this.createUniform( value, type, ns, needsUpdate );
+	var uniform = this.createUniform( type, value, ns, needsUpdate );
 
 	this.vertexUniform.push( uniform );
 	this.vertexUniform[ uniform.name ] = uniform;
@@ -417,9 +440,9 @@ THREE.NodeMaterial.prototype.getVertexUniform = function( value, type, ns, needs
 
 };
 
-THREE.NodeMaterial.prototype.getFragmentUniform = function( value, type, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createFragmentUniform = function( type, value, ns, needsUpdate ) {
 
-	var uniform = this.createUniform( value, type, ns, needsUpdate );
+	var uniform = this.createUniform( type, value, ns, needsUpdate );
 
 	this.fragmentUniform.push( uniform );
 	this.fragmentUniform[ uniform.name ] = uniform;

+ 1 - 1
examples/js/nodes/RawNode.js

@@ -17,7 +17,7 @@ THREE.GLNode.prototype.generate = function( builder ) {
 
 	var material = builder.material;
 
-	var data = this.value.verifyAndBuildCode( builder, this.type );
+	var data = this.value.parseAndBuildCode( builder, this.type );
 
 	var code = data.code + '\n';
 

+ 13 - 6
examples/js/nodes/TempNode.js

@@ -35,24 +35,27 @@ THREE.TempNode.prototype.build = function( builder, output, uuid, ns ) {
 
 		var data = material.getDataNode( uuid );
 
-		if ( builder.isShader( 'verify' ) ) {
+		if ( builder.parsing ) {
 
 			if ( data.deps || 0 > 0 ) {
 
-				this.verifyDepsNode( builder, data, output );
-				return '';
+				this.appendDepsNode( builder, data, output );
+
+				return this.generate( builder, type, uuid );
 
 			}
 
 			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
 
 		}
-		else if ( data.deps == 1 ) {
+		else if ( ! builder.optimize || data.deps == 1 ) {
 
 			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
 
 		}
 
+		uuid = this.getUuid( false );
+
 		var name = this.getTemp( builder, uuid );
 		var type = data.output || this.getType( builder );
 
@@ -95,9 +98,13 @@ THREE.TempNode.prototype.isUnique = function() {
 
 };
 
-THREE.TempNode.prototype.getUuid = function() {
+THREE.TempNode.prototype.getUuid = function( unique ) {
+
+	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
+
+	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
 
-	return this.constructor.uuid || this.uuid;
+	return uuid;
 
 };
 

+ 8 - 0
examples/js/nodes/accessors/CameraNode.js

@@ -13,6 +13,7 @@ THREE.CameraNode = function( scope, camera ) {
 
 THREE.CameraNode.POSITION = 'position';
 THREE.CameraNode.DEPTH = 'depth';
+THREE.CameraNode.TO_VERTEX = 'toVertex';
 
 THREE.CameraNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.CameraNode.prototype.constructor = THREE.CameraNode;
@@ -67,6 +68,7 @@ THREE.CameraNode.prototype.isUnique = function( builder ) {
 
 	switch ( this.scope ) {
 		case THREE.CameraNode.DEPTH:
+		case THREE.CameraNode.TO_VERTEX:
 			return true;
 	}
 
@@ -106,6 +108,12 @@ THREE.CameraNode.prototype.generate = function( builder, output ) {
 
 			break;
 
+		case THREE.CameraNode.TO_VERTEX:
+
+			result = 'normalize( ' + new THREE.PositionNode( THREE.PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
+
+			break;
+
 	}
 
 	return builder.format( result, this.getType( builder ), output );

+ 1 - 1
examples/js/nodes/accessors/LightNode.js

@@ -20,7 +20,7 @@ THREE.LightNode.prototype.generate = function( builder, output ) {
 	}
 	else {
 
-		console.warn( "THREE.LightNode is compatible only in \"light\" channel." );
+		console.warn( "THREE.LightNode is only compatible in \"light\" channel." );
 
 		return builder.format( 'vec3( 0.0 )', this.getType( builder ), output );
 

+ 4 - 4
examples/js/nodes/accessors/PositionNode.js

@@ -55,7 +55,7 @@ THREE.PositionNode.prototype.generate = function( builder, output ) {
 			if ( builder.isShader( 'vertex' ) ) result = 'transformed';
 			else result = 'vPosition';
 
-		break;
+			break;
 
 		case THREE.PositionNode.WORLD:
 
@@ -64,21 +64,21 @@ THREE.PositionNode.prototype.generate = function( builder, output ) {
 			if ( builder.isShader( 'vertex' ) ) result = 'vWPosition';
 			else result = 'vWPosition';
 
-		break;
+			break;
 
 		case THREE.PositionNode.VIEW:
 
 			if ( builder.isShader( 'vertex' ) ) result = '-mvPosition.xyz';
 			else result = 'vViewPosition';
 
-		break;
+			break;
 
 		case THREE.PositionNode.PROJECTION:
 
 			if ( builder.isShader( 'vertex' ) ) result = '(projectionMatrix * modelViewMatrix * vec4( position, 1.0 ))';
 			else result = 'vec4( 0.0 )';
 
-		break;
+			break;
 
 	}
 

+ 43 - 14
examples/js/nodes/accessors/ReflectNode.js

@@ -2,38 +2,67 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ReflectNode = function() {
+THREE.ReflectNode = function( scope ) {
 
 	THREE.TempNode.call( this, 'v3', { unique: true } );
 
-	this.worldPosition = new THREE.PositionNode( THREE.PositionNode.WORLD );
+	this.scope = scope || THREE.ReflectNode.CUBE;
 
 };
 
+THREE.ReflectNode.CUBE = 'cube';
+THREE.ReflectNode.SPHERE = 'sphere';
+THREE.ReflectNode.VECTOR = 'vector';
+
 THREE.ReflectNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ReflectNode.prototype.constructor = THREE.ReflectNode;
 
+THREE.ReflectNode.prototype.getType = function( builder ) {
+
+	switch ( this.scope ) {
+		case THREE.CameraNode.SPHERE:
+			return 'v2';
+	}
+
+	return this.type;
+
+};
+
 THREE.ReflectNode.prototype.generate = function( builder, output ) {
 
-	var material = builder.material;
+	var result;
 
-	if ( builder.isShader( 'fragment' ) ) {
+	switch ( this.scope ) {
 
-		material.addFragmentNode( [
-			'vec3 cameraToVertex = normalize( ' + this.worldPosition.build( builder, 'v3' ) + ' - cameraPosition );',
-			'vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );',
-			'vec3 vReflect = reflect( cameraToVertex, worldNormal );'
-		].join( "\n" ) );
+		case THREE.ReflectNode.VECTOR:
 
-		return builder.format( 'vReflect', this.type, output );
+			builder.material.addFragmentNode( 'vec3 reflectVec = inverseTransformDirection( reflect( -geometry.viewDir, geometry.normal ), viewMatrix );' );
 
-	}
-	else {
+			result = 'reflectVec';
+
+			break;
 
-		console.warn( "THREE.ReflectNode is not compatible with " + builder.shader + " shader." );
+		case THREE.ReflectNode.CUBE:
 
-		return builder.format( 'vec3( 0.0 )', this.type, output );
+			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
 
+			builder.material.addFragmentNode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
+
+			result = 'reflectCubeVec';
+
+			break;
+
+		case THREE.ReflectNode.SPHERE:
+
+			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
+
+			builder.material.addFragmentNode( 'vec3 reflectSphereVec = normalize((viewMatrix * vec4(' + reflectVec + ', 0.0 )).xyz + vec3(0.0,0.0,1.0)).xy * 0.5 + 0.5;' );
+
+			result = 'reflectSphereVec';
+
+			break;
 	}
 
+	return builder.format( result, this.getType( this.type ), output );
+
 };

+ 2 - 2
examples/js/nodes/inputs/CubeTextureNode.js

@@ -35,8 +35,8 @@ THREE.CubeTextureNode.prototype.generate = function( builder, output ) {
 
 	var code;
 
-	if ( bias ) code = 'textureCube(' + cubetex + ',' + coord + ',' + bias + ')';
-	else code = 'textureCube(' + cubetex + ',' + coord + ')';
+	if ( bias ) code = 'texCubeBias(' + cubetex + ',' + coord + ',' + bias + ')';
+	else code = 'texCube(' + cubetex + ',' + coord + ')';
 
 	return builder.format( code, this.type, output );
 

+ 14 - 0
examples/js/nodes/inputs/Matrix4Node.js

@@ -0,0 +1,14 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.Matrix4Node = function( matrix ) {
+
+	THREE.InputNode.call( this, 'm4', { share: false } );
+
+	this.value = matrix || new THREE.Matrix4();
+
+};
+
+THREE.Matrix4Node.prototype = Object.create( THREE.InputNode.prototype );
+THREE.Matrix4Node.prototype.constructor = THREE.Matrix4Node;

+ 43 - 0
examples/js/nodes/inputs/MirrorNode.js

@@ -0,0 +1,43 @@
+THREE.MirrorNode = function( renderer, camera, options ) {
+
+	THREE.TempNode.call( this, 'v4' );
+
+	this.mirror = renderer instanceof THREE.Mirror ? renderer : new THREE.Mirror( renderer, camera, options );
+
+	this.textureMatrix = new THREE.Matrix4Node( this.mirror.textureMatrix );
+
+	this.worldPosition = new THREE.PositionNode( THREE.PositionNode.WORLD );
+
+	this.coord = new THREE.OperatorNode( this.textureMatrix, this.worldPosition, THREE.OperatorNode.MUL );
+	this.coordResult = new THREE.OperatorNode( null, this.coord, THREE.OperatorNode.ADD );
+
+	this.texture = new THREE.TextureNode( this.mirror.renderTarget.texture, this.coord, null, true );
+
+};
+
+THREE.MirrorNode.prototype = Object.create( THREE.TempNode.prototype );
+THREE.MirrorNode.prototype.constructor = THREE.MirrorNode;
+
+THREE.MirrorNode.prototype.generate = function( builder, output ) {
+
+	var material = builder.material;
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		this.coordResult.a = this.offset;
+		this.texture.coord = this.offset ? this.coordResult : this.coord;
+
+		var coord = this.texture.build( builder, this.type );
+
+		return builder.format( coord, this.type, output );
+
+	}
+	else {
+
+		console.warn( "THREE.MirrorNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec4(0.0)', this.type, output );
+
+	}
+
+};

+ 9 - 5
examples/js/nodes/inputs/TextureNode.js

@@ -2,13 +2,14 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TextureNode = function( value, coord, bias ) {
+THREE.TextureNode = function( value, coord, bias, project ) {
 
 	THREE.InputNode.call( this, 'v4' );
 
 	this.value = value;
 	this.coord = coord || new THREE.UVNode();
 	this.bias = bias;
+	this.project = project !== undefined ? project : false;
 
 };
 
@@ -24,7 +25,7 @@ THREE.TextureNode.prototype.getTexture = function( builder, output ) {
 THREE.TextureNode.prototype.generate = function( builder, output ) {
 
 	var tex = this.getTexture( builder, output );
-	var coord = this.coord.build( builder, 'v2' );
+	var coord = this.coord.build( builder, this.project ? 'v4' : 'v2' );
 	var bias = this.bias ? this.bias.build( builder, 'fv1' ) : undefined;
 
 	if ( bias == undefined && builder.requires.bias ) {
@@ -33,10 +34,13 @@ THREE.TextureNode.prototype.generate = function( builder, output ) {
 
 	}
 
-	var code;
+	var method, code;
 
-	if ( bias ) code = 'texture2D(' + tex + ',' + coord + ',' + bias + ')';
-	else code = 'texture2D(' + tex + ',' + coord + ')';
+	if ( this.project ) method = 'texture2DProj';
+	else method = bias ? 'tex2DBias' : 'tex2D';
+
+	if ( bias ) code = method + '(' + tex + ',' + coord + ',' + bias + ')';
+	else code = method + '(' + tex + ',' + coord + ')';
 
 	return builder.format( code, this.type, output );
 

+ 17 - 15
examples/js/nodes/materials/PhongNode.js

@@ -27,11 +27,12 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.verifyAndBuildCode( builder, 'v3', 'transform' ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', 'transform' ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
+			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
@@ -95,26 +96,26 @@ THREE.PhongNode.prototype.build = function( builder ) {
 	}
 	else {
 
-		// verify all nodes to reuse generate codes
+		// parse all nodes to reuse generate codes
 
-		this.color.verify( builder );
-		this.specular.verify( builder );
-		this.shininess.verify( builder );
+		this.color.parse( builder );
+		this.specular.parse( builder );
+		this.shininess.parse( builder );
 
-		if ( this.alpha ) this.alpha.verify( builder );
+		if ( this.alpha ) this.alpha.parse( builder );
 
-		if ( this.light ) this.light.verify( builder, 'light' );
+		if ( this.light ) this.light.parse( builder, 'light' );
 
-		if ( this.ao ) this.ao.verify( builder );
-		if ( this.ambient ) this.ambient.verify( builder );
-		if ( this.shadow ) this.shadow.verify( builder );
-		if ( this.emissive ) this.emissive.verify( builder );
+		if ( this.ao ) this.ao.parse( builder );
+		if ( this.ambient ) this.ambient.parse( builder );
+		if ( this.shadow ) this.shadow.parse( builder );
+		if ( this.emissive ) this.emissive.parse( builder );
 
-		if ( this.normal ) this.normal.verify( builder );
-		if ( this.normalScale && this.normal ) this.normalScale.verify( builder );
+		if ( this.normal ) this.normal.parse( builder );
+		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
 
-		if ( this.environment ) this.environment.verify( builder );
-		if ( this.environmentAlpha && this.environment ) this.environmentAlpha.verify( builder );
+		if ( this.environment ) this.environment.parse( builder );
+		if ( this.environmentAlpha && this.environment ) this.environmentAlpha.parse( builder );
 
 		// build code
 
@@ -143,6 +144,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
+			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

+ 42 - 21
examples/js/nodes/materials/StandardNode.js

@@ -20,18 +20,19 @@ THREE.StandardNode.prototype.build = function( builder ) {
 	var material = builder.material;
 	var code;
 
-	material.define( 'STANDARD' );
+	material.define( 'PHYSICAL' );
 	material.define( 'ALPHATEST', '0.0' );
 
 	material.requestAttrib.light = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.verifyAndBuildCode( builder, 'v3', 'transform' ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', 'transform' ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
+			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
@@ -95,31 +96,33 @@ THREE.StandardNode.prototype.build = function( builder ) {
 	}
 	else {
 
-		// autoblur textures for PBR Material effect
+		// blur textures for PBR effect
 
 		var requires = {
-			bias : new THREE.RoughnessToBlinnExponentNode()
+			bias : new THREE.RoughnessToBlinnExponentNode(),
+			offsetU : 0,
+			offsetV : 0
 		};
 
-		// verify all nodes to reuse generate codes
+		// parse all nodes to reuse generate codes
 
-		this.color.verify( builder );
-		this.roughness.verify( builder );
-		this.metalness.verify( builder );
+		this.color.parse( builder );
+		this.roughness.parse( builder );
+		this.metalness.parse( builder );
 
-		if ( this.alpha ) this.alpha.verify( builder );
+		if ( this.alpha ) this.alpha.parse( builder );
 
-		if ( this.light ) this.light.verify( builder, 'light' );
+		if ( this.light ) this.light.parse( builder, 'light' );
 
-		if ( this.ao ) this.ao.verify( builder );
-		if ( this.ambient ) this.ambient.verify( builder );
-		if ( this.shadow ) this.shadow.verify( builder );
-		if ( this.emissive ) this.emissive.verify( builder );
+		if ( this.ao ) this.ao.parse( builder );
+		if ( this.ambient ) this.ambient.parse( builder );
+		if ( this.shadow ) this.shadow.parse( builder );
+		if ( this.emissive ) this.emissive.parse( builder );
 
-		if ( this.normal ) this.normal.verify( builder );
-		if ( this.normalScale && this.normal ) this.normalScale.verify( builder );
+		if ( this.normal ) this.normal.parse( builder );
+		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
 
-		if ( this.environment ) this.environment.verify( builder, 'env', requires ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+		if ( this.environment ) this.environment.parse( builder, 'env', requires ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 
 		// build code
 
@@ -127,6 +130,8 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		var roughness = this.roughness.buildCode( builder, 'fv1' );
 		var metalness = this.metalness.buildCode( builder, 'fv1' );
 
+		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'fv1' ) : undefined;
+
 		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
 
 		var light = this.light ? this.light.buildCode( builder, 'v3', 'light' ) : undefined;
@@ -157,7 +162,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
 			THREE.ShaderChunk[ "lights_pars" ],
-			THREE.ShaderChunk[ "lights_standard_pars_fragment" ],
+			THREE.ShaderChunk[ "lights_physical_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],
 		].join( "\n" ) );
@@ -167,7 +172,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 				THREE.ShaderChunk[ "normal_fragment" ],
 
 				// prevent undeclared material
-			"	StandardMaterial material;",
+			"	PhysicalMaterial material;",
 			"	material.diffuseColor = vec3( 1.0 );",
 
 				color.code,
@@ -215,9 +220,25 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 		output.push(
 			// accumulation
-			'material.specularRoughness = clamp( roughnessFactor, 0.001, 1.0 );', // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
-			'material.specularColor = mix( vec3( 0.04 ), diffuseColor, metalnessFactor );',
+			'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );' // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
+		);
+
+		if ( reflectivity ) {
+
+			output.push(
+				'material.specularColor = mix( vec3( 0.16 * pow2( ' + reflectivity.builder( builder, 'fv1' ) + ' ) ), diffuseColor, metalnessFactor );'
+			);
 
+		}
+		else {
+
+			output.push(
+				'material.specularColor = mix( vec3( 0.04 ), diffuseColor, metalnessFactor );'
+			);
+
+		}
+
+		output.push(
 			THREE.ShaderChunk[ "lights_template" ]
 		);
 

+ 4 - 13
examples/js/nodes/math/Math3Node.js

@@ -28,19 +28,10 @@ THREE.Math3Node.prototype.getType = function( builder ) {
 	var b = builder.getFormatLength( this.b.getType( builder ) );
 	var c = builder.getFormatLength( this.c.getType( builder ) );
 
-	if ( a > b ) {
-
-		if ( a > c ) return this.a.getType( builder );
-		return this.c.getType( builder );
-
-	}
-	else {
-
-		if ( b > c ) return this.b.getType( builder );
-
-		return this.c.getType( builder );
-
-	}
+	if ( a > b && a > c ) return this.a.getType( builder );
+	else if ( b > c ) return this.b.getType( builder );
+	
+	return this.c.getType( builder );
 
 };
 

+ 18 - 8
examples/js/nodes/math/OperatorNode.js

@@ -22,25 +22,35 @@ THREE.OperatorNode.prototype.constructor = THREE.OperatorNode;
 
 THREE.OperatorNode.prototype.getType = function( builder ) {
 
+	var a = this.a.getType( builder );
+	var b = this.b.getType( builder );
+	
+	if ( builder.isFormatMatrix( a ) ) {
+	
+		return 'v4';
+		
+	}
 	// use the greater length vector
-	if ( builder.getFormatLength( this.b.getType( builder ) ) > builder.getFormatLength( this.a.getType( builder ) ) ) {
+	else if ( builder.getFormatLength( b ) > builder.getFormatLength( a ) ) {
 
-		return this.b.getType( builder );
+		return b;
 
 	}
 
-	return this.a.getType( builder );
+	return a;
 
 };
 
 THREE.OperatorNode.prototype.generate = function( builder, output ) {
 
-	var material = builder.material;
-	var data = material.getDataNode( this.uuid );
+	var material = builder.material, 
+		data = material.getDataNode( this.uuid );
 
-	var a = this.a.build( builder, output );
-	var b = this.b.build( builder, output );
+	var type = this.getType( builder );
+	
+	var a = this.a.build( builder, type );
+	var b = this.b.build( builder, type );
 
-	return '(' + a + this.op + b + ')';
+	return builder.format( '(' + a + this.op + b + ')', type, output );
 
 };

+ 21 - 7
examples/js/nodes/utils/RoughnessToBlinnExponentNode.js

@@ -4,10 +4,24 @@
 
 THREE.RoughnessToBlinnExponentNode = function() {
 
-	THREE.TempNode.call( this, 'fv1', { unique: true } );
+	THREE.TempNode.call( this, 'fv1' );
 
 };
 
+THREE.RoughnessToBlinnExponentNode.getSpecularMIPLevel = new THREE.FunctionNode( [
+// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
+"float getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {",
+
+	//float envMapWidth = pow( 2.0, maxMIPLevelScalar );
+	//float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
+	"float maxMIPLevelScalar = float( maxMIPLevel );",
+	"float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );",
+
+	// clamp to allowable LOD ranges.
+	"return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
+"}"
+].join( "\n" ) );
+
 THREE.RoughnessToBlinnExponentNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.RoughnessToBlinnExponentNode.prototype.constructor = THREE.RoughnessToBlinnExponentNode;
 
@@ -17,21 +31,21 @@ THREE.RoughnessToBlinnExponentNode.prototype.generate = function( builder, outpu
 
 	if ( builder.isShader( 'fragment' ) ) {
 
-		if ( material.isDefined( 'STANDARD' ) ) {
+		if ( material.isDefined( 'PHYSICAL' ) ) {
 
-			material.addFragmentNode( 'float specularMIPLevel = GGXRoughnessToBlinnExponent( 1.0 - material.specularRoughness );' );
+			builder.include( THREE.RoughnessToBlinnExponentNode.getSpecularMIPLevel );
+
+			return builder.format( 'getSpecularMIPLevel( Material_BlinnShininessExponent( material ), 8 )', this.type, output );
 
 		}
 		else {
 
-			console.warn( "THREE.RoughnessToBlinnExponentNode is compatible with StandardMaterial only." );
+			console.warn( "THREE.RoughnessToBlinnExponentNode is only compatible with PhysicalMaterial." );
 
-			material.addFragmentNode( 'float specularMIPLevel = 0.0;' );
+			return builder.format( '0.0', this.type, output );
 
 		}
 
-		return builder.format( 'specularMIPLevel', this.type, output );
-
 	}
 	else {
 

+ 2 - 2
examples/webgl_materials_nodes.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<title>WebGL NodeMaterial</title>
+		<title>three.js webgl - node material</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
@@ -1299,7 +1299,7 @@
 
 					}, true );
 
-					addGui( 'hardBody', colorB.value.getHex(), function( val ) {
+					addGui( 'rigidBody', colorB.value.getHex(), function( val ) {
 
 						colorB.value.setHex( val );
 

+ 307 - 0
examples/webgl_mirror_nodes.html

@@ -0,0 +1,307 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - mirror with nodes</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 {
+				color: #888888;
+				font-family:Monospace;
+				font-size:13px;
+
+				background-color: #000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 200px;
+				left: calc(50% - 100px);
+				text-align: center;
+			}
+
+			a {
+				color: #00f;
+			}
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - mirror
+		</div>
+
+		<script src="../build/three.js"></script>
+		<script src="js/Mirror.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<!-- NodeLibrary -->
+		<script src="js/nodes/GLNode.js"></script>
+		<script src="js/nodes/RawNode.js"></script>
+		<script src="js/nodes/TempNode.js"></script>
+		<script src="js/nodes/InputNode.js"></script>
+		<script src="js/nodes/ConstNode.js"></script>
+		<script src="js/nodes/FunctionNode.js"></script>
+		<script src="js/nodes/FunctionCallNode.js"></script>
+		<script src="js/nodes/BuilderNode.js"></script>
+		<script src="js/nodes/NodeLib.js"></script>
+		<script src="js/nodes/NodeMaterial.js"></script>
+
+		<!-- Accessors -->
+		<script src="js/nodes/accessors/PositionNode.js"></script>
+		<script src="js/nodes/accessors/NormalNode.js"></script>
+		<script src="js/nodes/accessors/UVNode.js"></script>
+		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
+		<script src="js/nodes/accessors/ColorsNode.js"></script>
+		<script src="js/nodes/accessors/CameraNode.js"></script>
+		<script src="js/nodes/accessors/ReflectNode.js"></script>
+		<script src="js/nodes/accessors/LightNode.js"></script>
+
+		<!-- Inputs -->
+		<script src="js/nodes/inputs/IntNode.js"></script>
+		<script src="js/nodes/inputs/FloatNode.js"></script>
+		<script src="js/nodes/inputs/ColorNode.js"></script>
+		<script src="js/nodes/inputs/Vector2Node.js"></script>
+		<script src="js/nodes/inputs/Vector3Node.js"></script>
+		<script src="js/nodes/inputs/Vector4Node.js"></script>
+		<script src="js/nodes/inputs/TextureNode.js"></script>
+		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
+		<script src="js/nodes/inputs/Matrix4Node.js"></script>
+		<script src="js/nodes/inputs/MirrorNode.js"></script>
+
+		<!-- Math -->
+		<script src="js/nodes/math/Math1Node.js"></script>
+		<script src="js/nodes/math/Math2Node.js"></script>
+		<script src="js/nodes/math/Math3Node.js"></script>
+		<script src="js/nodes/math/OperatorNode.js"></script>
+
+		<!-- Utils -->
+		<script src="js/nodes/utils/SwitchNode.js"></script>
+		<script src="js/nodes/utils/JoinNode.js"></script>
+		<script src="js/nodes/utils/TimerNode.js"></script>
+		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
+		<script src="js/nodes/utils/VelocityNode.js"></script>
+		<script src="js/nodes/utils/LuminanceNode.js"></script>
+		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
+		<script src="js/nodes/utils/NoiseNode.js"></script>
+		<script src="js/nodes/utils/ResolutionNode.js"></script>
+
+		<!-- Phong Material -->
+		<script src="js/nodes/materials/PhongNode.js"></script>
+		<script src="js/nodes/materials/PhongNodeMaterial.js"></script>
+
+		<script>
+
+			// scene size
+			var WIDTH = window.innerWidth;
+			var HEIGHT = window.innerHeight;
+
+			// camera
+			var VIEW_ANGLE = 45;
+			var ASPECT = WIDTH / HEIGHT;
+			var NEAR = 1;
+			var FAR = 500;
+
+			var decalNormal = new THREE.TextureLoader().load( 'textures/decal/decal-normal.jpg' );
+
+			var decalDiffuse = new THREE.TextureLoader().load( 'textures/decal/decal-diffuse.png' );
+			decalDiffuse.wrapS = decalDiffuse.wrapT = THREE.RepeatWrapping;
+
+			var camera, scene, renderer;
+
+			var cameraControls;
+
+			var groundMirror;
+			var sphereGroup, smallSphere;
+			var groundMirrorMaterial;
+
+			function init() {
+
+				// renderer
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( WIDTH, HEIGHT );
+
+				// scene
+				scene = new THREE.Scene();
+
+				// camera
+				camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
+				camera.position.set( 0, 75, 160 );
+
+				cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
+				cameraControls.target.set( 0, 40, 0);
+				cameraControls.maxDistance = 400;
+				cameraControls.minDistance = 10;
+				cameraControls.update();
+
+				var container = document.getElementById( 'container' );
+				container.appendChild( renderer.domElement );
+
+			}
+
+			function fillScene() {
+
+				var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 );
+
+				// MIRROR planes
+				groundMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } );
+
+				var mask = new THREE.SwitchNode( new THREE.TextureNode( decalDiffuse ), 'w' );
+				var maskFlip = new THREE.Math1Node( mask, THREE.Math1Node.INVERT );
+
+				var mirror = new THREE.MirrorNode( groundMirror );
+
+				var normal = new THREE.TextureNode( decalNormal );
+				var normalXY = new THREE.SwitchNode( normal, 'xy' );
+				var normalXYFlip = new THREE.Math1Node(
+					normalXY,
+					THREE.Math1Node.INVERT
+				);
+
+				var offsetNormal = new THREE.OperatorNode(
+					normalXYFlip,
+					new THREE.FloatNode( .5 ),
+					THREE.OperatorNode.SUB
+				);
+
+				mirror.offset = new THREE.OperatorNode(
+					offsetNormal, // normal
+					new THREE.FloatNode( 6 ),// scale
+					THREE.OperatorNode.MUL
+				);
+
+				var clr = new THREE.Math3Node(
+					mirror,
+					new THREE.ColorNode( 0xFFFFFF ),
+					mask,
+					THREE.Math3Node.MIX
+				);
+
+				groundMirrorMaterial = new THREE.PhongNodeMaterial();
+				groundMirrorMaterial.environment = mirror;
+				groundMirrorMaterial.environmentAlpha = mask;
+				groundMirrorMaterial.normal = normal;
+				//groundMirrorMaterial.normalScale = new THREE.FloatNode( 1 );
+				groundMirrorMaterial.build();
+
+				var mirrorMesh = new THREE.Mesh( planeGeo, groundMirrorMaterial );
+				mirrorMesh.add( groundMirror );
+				mirrorMesh.rotateX( - Math.PI / 2 );
+				scene.add( mirrorMesh );
+
+				sphereGroup = new THREE.Object3D();
+				scene.add( sphereGroup );
+
+				var geometry = new THREE.CylinderGeometry( 0.1, 15 * Math.cos( Math.PI / 180 * 30 ), 0.1, 24, 1 );
+				var material = new THREE.MeshPhongMaterial( { color: 0xffffff, emissive: 0x444444 } );
+				var sphereCap = new THREE.Mesh( geometry, material );
+				sphereCap.position.y = -15 * Math.sin( Math.PI / 180 * 30 ) - 0.05;
+				sphereCap.rotateX(-Math.PI);
+
+				var geometry = new THREE.SphereGeometry( 15, 24, 24, Math.PI / 2, Math.PI * 2, 0, Math.PI / 180 * 120 );
+				var halfSphere = new THREE.Mesh( geometry, material );
+				halfSphere.add( sphereCap );
+				halfSphere.rotateX( - Math.PI / 180 * 135 );
+				halfSphere.rotateZ( - Math.PI / 180 * 20 );
+				halfSphere.position.y = 7.5 + 15 * Math.sin( Math.PI / 180 * 30 );
+
+				sphereGroup.add( halfSphere );
+
+				var geometry = new THREE.IcosahedronGeometry( 5, 0 );
+				var material = new THREE.MeshPhongMaterial( { color: 0xffffff, emissive: 0x333333, shading: THREE.FlatShading } );
+				smallSphere = new THREE.Mesh( geometry, material );
+				scene.add(smallSphere);
+
+				// walls
+				var planeTop = new THREE.Mesh( planeGeo, new THREE.MeshPhongMaterial( { color: 0xffffff } ) );
+				planeTop.position.y = 100;
+				planeTop.rotateX( Math.PI / 2 );
+				scene.add( planeTop );
+
+				var planeBack = new THREE.Mesh( planeGeo, new THREE.MeshPhongMaterial( { color: 0xffffff } ) );
+				planeBack.position.z = -50;
+				planeBack.position.y = 50;
+				scene.add( planeBack );
+
+				var planeFront = new THREE.Mesh( planeGeo, new THREE.MeshPhongMaterial( { color: 0x7f7fff } ) );
+				planeFront.position.z = 50;
+				planeFront.position.y = 50;
+				planeFront.rotateY( Math.PI );
+				scene.add( planeFront );
+
+				var planeRight = new THREE.Mesh( planeGeo, new THREE.MeshPhongMaterial( { color: 0x00ff00 } ) );
+				planeRight.position.x = 50;
+				planeRight.position.y = 50;
+				planeRight.rotateY( - Math.PI / 2 );
+				scene.add( planeRight );
+
+				var planeLeft = new THREE.Mesh( planeGeo, new THREE.MeshPhongMaterial( { color: 0xff0000 } ) );
+				planeLeft.position.x = -50;
+				planeLeft.position.y = 50;
+				planeLeft.rotateY( Math.PI / 2 );
+				scene.add( planeLeft );
+
+				// lights
+				var mainLight = new THREE.PointLight( 0xcccccc, 1.5, 250 );
+				mainLight.position.y = 60;
+				scene.add( mainLight );
+
+				var greenLight = new THREE.PointLight( 0x00ff00, 0.25, 1000 );
+				greenLight.position.set( 550, 50, 0 );
+				scene.add( greenLight );
+
+				var redLight = new THREE.PointLight( 0xff0000, 0.25, 1000 );
+				redLight.position.set( - 550, 50, 0 );
+				scene.add( redLight );
+
+				var blueLight = new THREE.PointLight( 0x7f7fff, 0.25, 1000 );
+				blueLight.position.set( 0, 50, 550 );
+				scene.add( blueLight );
+
+			}
+
+			function render() {
+
+				// render (update) the mirrors
+				groundMirrorMaterial.visible = false;
+
+				groundMirror.render();
+
+				groundMirrorMaterial.visible = true;
+
+				renderer.render(scene, camera);
+
+			}
+
+			function update() {
+
+				requestAnimationFrame( update );
+
+				var timer = Date.now() * 0.01;
+
+				sphereGroup.rotation.y -= 0.002;
+
+				smallSphere.position.set(
+					Math.cos( timer * 0.1 ) * 30,
+					Math.abs( Math.cos( timer * 0.2 ) ) * 20 + 5,
+					Math.sin( timer * 0.1 ) * 30
+				);
+				smallSphere.rotation.y = ( Math.PI / 2 ) - timer * 0.1;
+				smallSphere.rotation.z = timer * 0.8;
+
+				cameraControls.update();
+
+				render();
+			}
+
+			init();
+			fillScene();
+			update();
+
+		</script>
+	</body>
+</html>

+ 4 - 15
examples/webgl_postprocessing_nodes.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<title>three.js webgl - postprocessing</title>
+		<title>three.js webgl - postprocessing with nodes</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
@@ -414,9 +414,6 @@
 						var scale = new THREE.FloatNode( 128 );
 						var fade = new THREE.FloatNode( 1 );
 						var uv = new THREE.UVNode();
-						var tex = new THREE.TextureNode( lensflare2 );
-
-						var mask = new THREE.Math1Node( new THREE.SwitchNode( tex, 'x' ), THREE.Math1Node.INVERT );
 
 						var blocks = new THREE.OperatorNode(
 							uv,
@@ -435,22 +432,14 @@
 							THREE.OperatorNode.DIV
 						);
 
-						var maskAlpha = new THREE.OperatorNode(
-							mask,
-							fade,
-							THREE.OperatorNode.MUL
-						);
-
-						var fadeCoord = new THREE.Math3Node(
+						var fadeScreen = new THREE.Math3Node(
 							uv,
 							coord,
-							maskAlpha,
+							fade,
 							THREE.Math3Node.MIX
 						);
 
-						var screen = new THREE.ScreenNode( fadeCoord );
-
-						nodepass.value = screen;
+						nodepass.value = new THREE.ScreenNode( fadeScreen );
 
 						// GUI