Forráskód Böngészése

NodeMaterial.toJSON()

sunag 7 éve
szülő
commit
76e0ef8080
55 módosított fájl, 1521 hozzáadás és 387 törlés
  1. 21 4
      examples/js/nodes/AttributeNode.js
  2. 27 6
      examples/js/nodes/ConstNode.js
  3. 39 5
      examples/js/nodes/FunctionCallNode.js
  4. 52 10
      examples/js/nodes/FunctionNode.js
  5. 64 11
      examples/js/nodes/GLNode.js
  6. 2 2
      examples/js/nodes/InputNode.js
  7. 32 32
      examples/js/nodes/NodeBuilder.js
  8. 56 56
      examples/js/nodes/NodeLib.js
  9. 147 80
      examples/js/nodes/NodeMaterial.js
  10. 19 2
      examples/js/nodes/RawNode.js
  11. 7 7
      examples/js/nodes/TempNode.js
  12. 20 3
      examples/js/nodes/VarNode.js
  13. 34 2
      examples/js/nodes/accessors/CameraNode.js
  14. 19 3
      examples/js/nodes/accessors/ColorsNode.js
  15. 4 3
      examples/js/nodes/accessors/LightNode.js
  16. 24 5
      examples/js/nodes/accessors/NormalNode.js
  17. 27 6
      examples/js/nodes/accessors/PositionNode.js
  18. 23 3
      examples/js/nodes/accessors/ReflectNode.js
  19. 19 2
      examples/js/nodes/accessors/ScreenUVNode.js
  20. 20 3
      examples/js/nodes/accessors/UVNode.js
  21. 20 1
      examples/js/nodes/inputs/ColorNode.js
  22. 24 4
      examples/js/nodes/inputs/CubeTextureNode.js
  23. 20 3
      examples/js/nodes/inputs/FloatNode.js
  24. 20 3
      examples/js/nodes/inputs/IntNode.js
  25. 18 1
      examples/js/nodes/inputs/Matrix4Node.js
  26. 30 5
      examples/js/nodes/inputs/ReflectorNode.js
  27. 4 3
      examples/js/nodes/inputs/ScreenNode.js
  28. 26 4
      examples/js/nodes/inputs/TextureNode.js
  29. 19 1
      examples/js/nodes/inputs/Vector2Node.js
  30. 20 1
      examples/js/nodes/inputs/Vector3Node.js
  31. 21 1
      examples/js/nodes/inputs/Vector4Node.js
  32. 43 2
      examples/js/nodes/materials/PhongNode.js
  33. 4 2
      examples/js/nodes/materials/PhongNodeMaterial.js
  34. 28 2
      examples/js/nodes/materials/SpriteNode.js
  35. 3 1
      examples/js/nodes/materials/SpriteNodeMaterial.js
  36. 48 4
      examples/js/nodes/materials/StandardNode.js
  37. 4 2
      examples/js/nodes/materials/StandardNodeMaterial.js
  38. 24 3
      examples/js/nodes/math/Math1Node.js
  39. 26 4
      examples/js/nodes/math/Math2Node.js
  40. 24 3
      examples/js/nodes/math/Math3Node.js
  41. 22 3
      examples/js/nodes/math/OperatorNode.js
  42. 44 2
      examples/js/nodes/postprocessing/NodePass.js
  43. 53 31
      examples/js/nodes/utils/BlurNode.js
  44. 29 10
      examples/js/nodes/utils/BumpNode.js
  45. 21 2
      examples/js/nodes/utils/ColorAdjustmentNode.js
  46. 37 4
      examples/js/nodes/utils/JoinNode.js
  47. 19 2
      examples/js/nodes/utils/LuminanceNode.js
  48. 19 2
      examples/js/nodes/utils/NoiseNode.js
  49. 23 2
      examples/js/nodes/utils/NormalMapNode.js
  50. 19 4
      examples/js/nodes/utils/ResolutionNode.js
  51. 12 11
      examples/js/nodes/utils/RoughnessToBlinnExponentNode.js
  52. 22 4
      examples/js/nodes/utils/SwitchNode.js
  53. 19 4
      examples/js/nodes/utils/TimerNode.js
  54. 18 0
      examples/js/nodes/utils/UVTransformNode.js
  55. 82 11
      examples/js/nodes/utils/VelocityNode.js

+ 21 - 4
examples/js/nodes/AttributeNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.AttributeNode = function( name, type ) {
+THREE.AttributeNode = function ( name, type ) {
 
 	THREE.GLNode.call( this, type );
 
@@ -12,14 +12,15 @@ THREE.AttributeNode = function( name, type ) {
 
 THREE.AttributeNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.AttributeNode.prototype.constructor = THREE.AttributeNode;
+THREE.AttributeNode.prototype.nodeType = "Attribute";
 
-THREE.AttributeNode.prototype.getAttributeType = function( builder ) {
+THREE.AttributeNode.prototype.getAttributeType = function ( builder ) {
 
 	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
 
 };
 
-THREE.AttributeNode.prototype.getType = function( builder ) {
+THREE.AttributeNode.prototype.getType = function ( builder ) {
 
 	var type = this.getAttributeType( builder );
 
@@ -27,7 +28,7 @@ THREE.AttributeNode.prototype.getType = function( builder ) {
 
 };
 
-THREE.AttributeNode.prototype.generate = function( builder, output ) {
+THREE.AttributeNode.prototype.generate = function ( builder, output ) {
 
 	var type = this.getAttributeType( builder );
 
@@ -36,3 +37,19 @@ THREE.AttributeNode.prototype.generate = function( builder, output ) {
 	return builder.format( builder.isShader( 'vertex' ) ? this.name : attribute.varying.name, this.getType( builder ), output );
 
 };
+
+THREE.AttributeNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.out = this.type;
+
+	}
+
+	return data;
+
+};

+ 27 - 6
examples/js/nodes/ConstNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ConstNode = function( src, useDefine ) {
+THREE.ConstNode = function ( src, useDefine ) {
 
 	THREE.TempNode.call( this );
 
@@ -19,18 +19,19 @@ THREE.ConstNode.EPSILON = 'EPSILON';
 
 THREE.ConstNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ConstNode.prototype.constructor = THREE.ConstNode;
+THREE.ConstNode.prototype.nodeType = "Const";
 
-THREE.ConstNode.prototype.getType = function( builder ) {
+THREE.ConstNode.prototype.getType = function ( builder ) {
 
 	return builder.getTypeByFormat( this.type );
 
 };
 
-THREE.ConstNode.prototype.eval = function( src, useDefine ) {
+THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
 
 	src = ( src || '' ).trim();
 
-	var name, type, value;
+	var name, type, value = "";
 
 	var rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
 	var match = src.match( rDeclaration );
@@ -56,7 +57,7 @@ THREE.ConstNode.prototype.eval = function( src, useDefine ) {
 
 };
 
-THREE.ConstNode.prototype.build = function( builder, output ) {
+THREE.ConstNode.prototype.build = function ( builder, output ) {
 
 	if ( output === 'source' ) {
 
@@ -82,8 +83,28 @@ THREE.ConstNode.prototype.build = function( builder, output ) {
 
 };
 
-THREE.ConstNode.prototype.generate = function( builder, output ) {
+THREE.ConstNode.prototype.generate = function ( builder, output ) {
 
 	return builder.format( this.name, this.getType( builder ), output );
 
 };
+
+THREE.ConstNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.name = this.name;
+		data.out = this.type;
+
+		if ( this.value ) data.value = this.value;
+		if ( data.useDefine === true ) data.useDefine = true;
+
+	}
+
+	return data;
+
+};

+ 39 - 5
examples/js/nodes/FunctionCallNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.FunctionCallNode = function( func, inputs ) {
+THREE.FunctionCallNode = function ( func, inputs ) {
 
 	THREE.TempNode.call( this );
 
@@ -12,27 +12,28 @@ THREE.FunctionCallNode = function( func, inputs ) {
 
 THREE.FunctionCallNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.FunctionCallNode.prototype.constructor = THREE.FunctionCallNode;
+THREE.FunctionCallNode.prototype.nodeType = "FunctionCall";
 
-THREE.FunctionCallNode.prototype.setFunction = function( func, inputs ) {
+THREE.FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
 
 	this.value = func;
 	this.inputs = inputs || [];
 
 };
 
-THREE.FunctionCallNode.prototype.getFunction = function() {
+THREE.FunctionCallNode.prototype.getFunction = function () {
 
 	return this.value;
 
 };
 
-THREE.FunctionCallNode.prototype.getType = function( builder ) {
+THREE.FunctionCallNode.prototype.getType = function ( builder ) {
 
 	return this.value.getType( builder );
 
 };
 
-THREE.FunctionCallNode.prototype.generate = function( builder, output ) {
+THREE.FunctionCallNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -56,3 +57,36 @@ THREE.FunctionCallNode.prototype.generate = function( builder, output ) {
 	return builder.format( code, type, output );
 
 };
+
+THREE.FunctionCallNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		var func = this.value;
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+
+		if ( func.inputs.length ) {
+
+			data.inputs = {};
+
+			for ( var i = 0; i < func.inputs.length; i ++ ) {
+
+				var inpt = func.inputs[ i ];
+				var node = this.inputs[ i ] || this.inputs[ inpt.name ];
+
+				data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
+
+			}
+
+		}
+
+	}
+
+	return data;
+
+};

+ 52 - 10
examples/js/nodes/FunctionNode.js

@@ -3,7 +3,7 @@
  * @thanks bhouston / https://clara.io/
  */
 
-THREE.FunctionNode = function( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions ) {
+THREE.FunctionNode = function ( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions ) {
 
 	src = src || '';
 
@@ -22,20 +22,21 @@ THREE.FunctionNode.rProperties = /[a-z_0-9]+/ig;
 
 THREE.FunctionNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.FunctionNode.prototype.constructor = THREE.FunctionNode;
+THREE.FunctionNode.prototype.nodeType = "Function";
 
-THREE.FunctionNode.prototype.isShared = function( builder, output ) {
+THREE.FunctionNode.prototype.isShared = function ( builder, output ) {
 
 	return ! this.isMethod;
 
 };
 
-THREE.FunctionNode.prototype.getType = function( builder ) {
+THREE.FunctionNode.prototype.getType = function ( builder ) {
 
 	return builder.getTypeByFormat( this.type );
 
 };
 
-THREE.FunctionNode.prototype.getInputByName = function( name ) {
+THREE.FunctionNode.prototype.getInputByName = function ( name ) {
 
 	var i = this.inputs.length;
 
@@ -48,7 +49,7 @@ THREE.FunctionNode.prototype.getInputByName = function( name ) {
 
 };
 
-THREE.FunctionNode.prototype.getIncludeByName = function( name ) {
+THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
 
 	var i = this.includes.length;
 
@@ -61,7 +62,7 @@ THREE.FunctionNode.prototype.getIncludeByName = function( name ) {
 
 };
 
-THREE.FunctionNode.prototype.generate = function( builder, output ) {
+THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 	var match, offset = 0, src = this.value;
 
@@ -136,7 +137,7 @@ THREE.FunctionNode.prototype.generate = function( builder, output ) {
 
 };
 
-THREE.FunctionNode.prototype.eval = function( src, includes, extensions, keywords ) {
+THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
 
 	src = ( src || '' ).trim();
 
@@ -180,9 +181,9 @@ THREE.FunctionNode.prototype.eval = function( src, includes, extensions, keyword
 					name = inputs[ i ++ ];
 
 					this.inputs.push( {
-						name : name,
-						type : type,
-						qualifier : qualifier
+						name: name,
+						type: type,
+						qualifier: qualifier
 					} );
 
 				}
@@ -201,3 +202,44 @@ THREE.FunctionNode.prototype.eval = function( src, includes, extensions, keyword
 	this.value = src;
 
 };
+
+THREE.FunctionNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.src = this.value;
+		data.isMethod = this.isMethod;
+		data.useKeywords = this.useKeywords;
+
+		if ( ! this.isMethod ) data.out = this.type;
+
+		data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
+		data.keywords = {};
+
+		for ( var keyword in this.keywords ) {
+
+			data.keywords[ keyword ] = this.keywords[ keyword ].toJSON( meta ).uuid;
+
+		}
+
+		if ( this.includes.length ) {
+
+			data.includes = [];
+
+			for ( var i = 0; i < this.includes.length; i ++ ) {
+
+				data.includes.push( this.includes[ i ].toJSON( meta ).uuid );
+
+			}
+
+		}
+
+	}
+
+	return data;
+
+};

+ 64 - 11
examples/js/nodes/GLNode.js

@@ -2,18 +2,22 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.GLNode = function( type ) {
+THREE.GLNode = function ( type ) {
 
 	this.uuid = THREE.Math.generateUUID();
 
+	this.name = "";
 	this.allows = {};
-	this.requestUpdate = false;
 
 	this.type = type;
 
+	this.userData = {};
+
 };
 
-THREE.GLNode.prototype.parse = function( builder, context ) {
+THREE.GLNode.prototype.isNode = true;
+
+THREE.GLNode.prototype.parse = function ( builder, context ) {
 
 	context = context || {};
 
@@ -32,7 +36,7 @@ THREE.GLNode.prototype.parse = function( builder, context ) {
 
 };
 
-THREE.GLNode.prototype.parseAndBuildCode = function( builder, output, context ) {
+THREE.GLNode.prototype.parseAndBuildCode = function ( builder, output, context ) {
 
 	context = context || {};
 
@@ -42,13 +46,13 @@ THREE.GLNode.prototype.parseAndBuildCode = function( builder, output, context )
 
 };
 
-THREE.GLNode.prototype.buildCode = function( builder, output, context ) {
+THREE.GLNode.prototype.buildCode = function ( builder, output, context ) {
 
 	context = context || {};
 
 	var material = builder.material;
 
-	var data = { result : this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), output ) };
+	var data = { result: this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), output ) };
 
 	if ( builder.isShader( 'vertex' ) ) data.code = material.clearVertexNode();
 	else data.code = material.clearFragmentNode();
@@ -59,7 +63,7 @@ THREE.GLNode.prototype.buildCode = function( builder, output, context ) {
 
 };
 
-THREE.GLNode.prototype.build = function( builder, output, uuid ) {
+THREE.GLNode.prototype.build = function ( builder, output, uuid ) {
 
 	output = output || this.getType( builder, output );
 
@@ -73,9 +77,15 @@ THREE.GLNode.prototype.build = function( builder, output, uuid ) {
 
 	}
 
-	if ( this.requestUpdate && material.requestUpdate.indexOf( this ) === - 1 ) {
+	if ( material.nodes.indexOf( this ) === - 1 ) {
 
-		material.requestUpdate.push( this );
+		material.nodes.push( this );
+
+	}
+
+	if ( this.updateFrame !== undefined && material.updaters.indexOf( this ) === - 1 ) {
+
+		material.updaters.push( this );
 
 	}
 
@@ -83,7 +93,7 @@ THREE.GLNode.prototype.build = function( builder, output, uuid ) {
 
 };
 
-THREE.GLNode.prototype.appendDepsNode = function( builder, data, output ) {
+THREE.GLNode.prototype.appendDepsNode = function ( builder, data, output ) {
 
 	data.deps = ( data.deps || 0 ) + 1;
 
@@ -98,8 +108,51 @@ THREE.GLNode.prototype.appendDepsNode = function( builder, data, output ) {
 
 };
 
-THREE.GLNode.prototype.getType = function( builder, output ) {
+THREE.GLNode.prototype.getType = function ( builder, output ) {
 
 	return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
 
 };
+
+THREE.GLNode.prototype.getJSONNode = function ( meta ) {
+
+	var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+	if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
+
+		return meta.nodes[ this.uuid ];
+
+	}
+
+};
+
+THREE.GLNode.prototype.createJSONNode = function ( meta ) {
+
+	var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+	var data = {};
+
+	if ( typeof this.nodeType !== "string" ) throw new Error( "Node does not allow serialization." );
+
+	data.uuid = this.uuid;
+	data.type = this.nodeType + "Node";
+
+	if ( this.name !== "" ) data.name = this.name;
+
+	if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+	if ( ! isRootObject ) {
+
+		meta.nodes[ this.uuid ] = data;
+
+	}
+
+	return data;
+
+};
+
+THREE.GLNode.prototype.toJSON = function ( meta ) {
+
+	return this.getJSONNode( meta ) || this.createJSONNode( meta );
+
+};

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

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.InputNode = function( type, params ) {
+THREE.InputNode = function ( type, params ) {
 
 	params = params || {};
 	params.shared = params.shared !== undefined ? params.shared : false;
@@ -14,7 +14,7 @@ THREE.InputNode = function( type, params ) {
 THREE.InputNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.InputNode.prototype.constructor = THREE.InputNode;
 
-THREE.InputNode.prototype.generate = function( builder, output, uuid, type, ns, needsUpdate ) {
+THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	var material = builder.material;
 

+ 32 - 32
examples/js/nodes/NodeBuilder.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodeBuilder = function( material ) {
+THREE.NodeBuilder = function ( material ) {
 
 	this.material = material;
 
@@ -19,12 +19,12 @@ THREE.NodeBuilder = function( material ) {
 };
 
 THREE.NodeBuilder.type = {
-	float : 'fv1',
-	vec2 : 'v2',
-	vec3 : 'v3',
-	vec4 : 'v4',
-	mat4 : 'v4',
-	int : 'iv1'
+	float: 'fv1',
+	vec2: 'v2',
+	vec3: 'v3',
+	vec4: 'v4',
+	mat4: 'v4',
+	int: 'iv1'
 };
 
 THREE.NodeBuilder.constructors = [
@@ -45,18 +45,18 @@ THREE.NodeBuilder.prototype = {
 
 	constructor: THREE.NodeBuilder,
 
-	addCache : function( name, requires ) {
+	addCache: function ( name, requires ) {
 
 		this.caches.push( {
-			name : name || '',
-			requires : requires || {}
+			name: name || '',
+			requires: requires || {}
 		} );
 
 		return this.update();
 
 	},
 
-	removeCache : function() {
+	removeCache: function () {
 
 		this.caches.pop();
 
@@ -64,17 +64,17 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	addSlot : function( name ) {
+	addSlot: function ( name ) {
 
 		this.slots.push( {
-			name : name || ''
+			name: name || ''
 		} );
 
 		return this.update();
 
 	},
 
-	removeSlot : function() {
+	removeSlot: function () {
 
 		this.slots.pop();
 
@@ -82,7 +82,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	isCache : function( name ) {
+	isCache: function ( name ) {
 
 		var i = this.caches.length;
 
@@ -96,7 +96,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	isSlot : function( name ) {
+	isSlot: function ( name ) {
 
 		var i = this.slots.length;
 
@@ -110,7 +110,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	update : function() {
+	update: function () {
 
 		var cache = this.caches[ this.caches.length - 1 ];
 		var slot = this.slots[ this.slots.length - 1 ];
@@ -123,7 +123,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	require : function( name, node ) {
+	require: function ( name, node ) {
 
 		this.requires[ name ] = node;
 
@@ -131,7 +131,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	include : function( node, parent, source ) {
+	include: function ( node, parent, source ) {
 
 		this.material.include( this, node, parent, source );
 
@@ -139,37 +139,37 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	colorToVector : function( color ) {
+	colorToVector: function ( color ) {
 
 		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
 
 	},
 
-	getConstructorFromLength : function( len ) {
+	getConstructorFromLength: function ( len ) {
 
 		return THREE.NodeBuilder.constructors[ len - 1 ];
 
 	},
 
-	getFormatName : function( format ) {
+	getFormatName: function ( format ) {
 
 		return format.replace( /c/g, 'v3' ).replace( /fv1/g, 'v1' ).replace( /iv1/g, 'i' );
 
 	},
 
-	isFormatMatrix : function( format ) {
+	isFormatMatrix: function ( format ) {
 
 		return /^m/.test( format );
 
 	},
 
-	getFormatLength : function( format ) {
+	getFormatLength: function ( format ) {
 
 		return parseInt( this.getFormatName( format ).substr( 1 ) );
 
 	},
 
-	getFormatFromLength : function( len ) {
+	getFormatFromLength: function ( len ) {
 
 		if ( len == 1 ) return 'fv1';
 
@@ -177,7 +177,7 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	format : function( code, from, to ) {
+	format: function ( code, from, to ) {
 
 		var format = this.getFormatName( to + '=' + from );
 
@@ -214,13 +214,13 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	getTypeByFormat : function( format ) {
+	getTypeByFormat: function ( format ) {
 
 		return THREE.NodeBuilder.type[ format ] || format;
 
 	},
 
-	getUuid : function( uuid, useCache ) {
+	getUuid: function ( uuid, useCache ) {
 
 		useCache = useCache !== undefined ? useCache : true;
 
@@ -230,25 +230,25 @@ THREE.NodeBuilder.prototype = {
 
 	},
 
-	getElementByIndex : function( index ) {
+	getElementByIndex: function ( index ) {
 
 		return THREE.NodeBuilder.elements[ index ];
 
 	},
 
-	getIndexByElement : function( elm ) {
+	getIndexByElement: function ( elm ) {
 
 		return THREE.NodeBuilder.elements.indexOf( elm );
 
 	},
 
-	isShader : function( shader ) {
+	isShader: function ( shader ) {
 
 		return this.shader == shader;
 
 	},
 
-	setShader : function( shader ) {
+	setShader: function ( shader ) {
 
 		this.shader = shader;
 

+ 56 - 56
examples/js/nodes/NodeLib.js

@@ -7,57 +7,57 @@ THREE.NodeLib = {
 	nodes: {},
 	keywords: {},
 
-	add: function( node ) {
+	add: function ( node ) {
 
 		this.nodes[ node.name ] = node;
 
 	},
 
-	addKeyword: function( name, callback, cache ) {
+	addKeyword: function ( name, callback, cache ) {
 
 		cache = cache !== undefined ? cache : true;
 
-		this.keywords[ name ] = { callback : callback, cache : cache };
+		this.keywords[ name ] = { callback: callback, cache: cache };
 
 	},
 
-	remove: function( node ) {
+	remove: function ( node ) {
 
 		delete this.nodes[ node.name ];
 
 	},
 
-	removeKeyword: function( name ) {
+	removeKeyword: function ( name ) {
 
 		delete this.keywords[ name ];
 
 	},
 
-	get: function( name ) {
+	get: function ( name ) {
 
 		return this.nodes[ name ];
 
 	},
 
-	getKeyword: function( name, material ) {
+	getKeyword: function ( name, material ) {
 
 		return this.keywords[ name ].callback.call( this, material );
 
 	},
 
-	getKeywordData: function( name ) {
+	getKeywordData: function ( name ) {
 
 		return this.keywords[ name ];
 
 	},
 
-	contains: function( name ) {
+	contains: function ( name ) {
 
 		return this.nodes[ name ] != undefined;
 
 	},
 
-	containsKeyword: function( name ) {
+	containsKeyword: function ( name ) {
 
 		return this.keywords[ name ] != undefined;
 
@@ -69,55 +69,55 @@ THREE.NodeLib = {
 //	Keywords
 //
 
-THREE.NodeLib.addKeyword( 'uv', function() {
+THREE.NodeLib.addKeyword( 'uv', function () {
 
 	return new THREE.UVNode();
 
 } );
 
-THREE.NodeLib.addKeyword( 'uv2', function() {
+THREE.NodeLib.addKeyword( 'uv2', function () {
 
 	return new THREE.UVNode( 1 );
 
 } );
 
-THREE.NodeLib.addKeyword( 'position', function() {
+THREE.NodeLib.addKeyword( 'position', function () {
 
 	return new THREE.PositionNode();
 
 } );
 
-THREE.NodeLib.addKeyword( 'worldPosition', function() {
+THREE.NodeLib.addKeyword( 'worldPosition', function () {
 
 	return new THREE.PositionNode( THREE.PositionNode.WORLD );
 
 } );
 
-THREE.NodeLib.addKeyword( 'normal', function() {
+THREE.NodeLib.addKeyword( 'normal', function () {
 
 	return new THREE.NormalNode();
 
 } );
 
-THREE.NodeLib.addKeyword( 'worldNormal', function() {
+THREE.NodeLib.addKeyword( 'worldNormal', function () {
 
 	return new THREE.NormalNode( THREE.NormalNode.WORLD );
 
 } );
 
-THREE.NodeLib.addKeyword( 'viewPosition', function() {
+THREE.NodeLib.addKeyword( 'viewPosition', function () {
 
 	return new THREE.PositionNode( THREE.NormalNode.VIEW );
 
 } );
 
-THREE.NodeLib.addKeyword( 'viewNormal', function() {
+THREE.NodeLib.addKeyword( 'viewNormal', function () {
 
 	return new THREE.NormalNode( THREE.NormalNode.VIEW );
 
 } );
 
-THREE.NodeLib.addKeyword( 'time', function() {
+THREE.NodeLib.addKeyword( 'time', function () {
 
 	return new THREE.TimerNode();
 
@@ -136,19 +136,19 @@ THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA vec3(0.2125, 0.7154, 0.0721)"
 THREE.NodeLib.add( new THREE.FunctionNode( [
 // Per-Pixel Tangent Space Normal Mapping
 // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
-"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
-"	vec3 q0 = dFdx( eye_pos );",
-"	vec3 q1 = dFdy( eye_pos );",
-"	vec2 st0 = dFdx( mUv.st );",
-"	vec2 st1 = dFdy( mUv.st );",
-"	vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
-"	vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
-"	vec3 N = normalize( surf_norm );",
-"	vec3 mapN = map * 2.0 - 1.0;",
-"	mapN.xy = scale * mapN.xy;",
-"	mat3 tsn = mat3( S, T, N );",
-"	return normalize( tsn * mapN );",
-"}"
+	"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
+	"	vec3 q0 = dFdx( eye_pos );",
+	"	vec3 q1 = dFdy( eye_pos );",
+	"	vec2 st0 = dFdx( mUv.st );",
+	"	vec2 st1 = dFdy( mUv.st );",
+	"	vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
+	"	vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
+	"	vec3 N = normalize( surf_norm );",
+	"	vec3 mapN = map * 2.0 - 1.0;",
+	"	mapN.xy = scale * mapN.xy;",
+	"	mat3 tsn = mat3( S, T, N );",
+	"	return normalize( tsn * mapN );",
+	"}"
 ].join( "\n" ), null, { derivatives: true } ) );
 
 //
@@ -156,9 +156,9 @@ THREE.NodeLib.add( new THREE.FunctionNode( [
 //
 
 THREE.NodeLib.add( new THREE.FunctionNode( [
-"float snoise(vec2 co) {",
-"	return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
-"}"
+	"float snoise(vec2 co) {",
+	"	return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
+	"}"
 ].join( "\n" ) ) );
 
 //
@@ -166,14 +166,14 @@ THREE.NodeLib.add( new THREE.FunctionNode( [
 //
 
 THREE.NodeLib.add( new THREE.FunctionNode( [
-"vec3 hue_rgb(vec3 rgb, float adjustment) {",
-"	const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
-"	const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
-"	vec3 yiq = RGBtoYIQ * rgb;",
-"	float hue = atan(yiq.z, yiq.y) + adjustment;",
-"	float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
-"	return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
-"}"
+	"vec3 hue_rgb(vec3 rgb, float adjustment) {",
+	"	const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
+	"	const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
+	"	vec3 yiq = RGBtoYIQ * rgb;",
+	"	float hue = atan(yiq.z, yiq.y) + adjustment;",
+	"	float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
+	"	return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
+	"}"
 ].join( "\n" ) ) );
 
 //
@@ -182,10 +182,10 @@ THREE.NodeLib.add( new THREE.FunctionNode( [
 
 THREE.NodeLib.add( new THREE.FunctionNode( [
 // Algorithm from Chapter 16 of OpenGL Shading Language
-"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
-"	vec3 intensity = vec3(dot(rgb, LUMA));",
-"	return mix(intensity, rgb, adjustment);",
-"}"
+	"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
+	"	vec3 intensity = vec3(dot(rgb, LUMA));",
+	"	return mix(intensity, rgb, adjustment);",
+	"}"
 ].join( "\n" ) ) );
 
 //
@@ -194,9 +194,9 @@ THREE.NodeLib.add( new THREE.FunctionNode( [
 
 THREE.NodeLib.add( new THREE.FunctionNode( [
 // Algorithm from Chapter 10 of Graphics Shaders
-"float luminance_rgb(vec3 rgb) {",
-"	return dot(rgb, LUMA);",
-"}"
+	"float luminance_rgb(vec3 rgb) {",
+	"	return dot(rgb, LUMA);",
+	"}"
 ].join( "\n" ) ) );
 
 //
@@ -205,10 +205,10 @@ THREE.NodeLib.add( new THREE.FunctionNode( [
 
 THREE.NodeLib.add( new THREE.FunctionNode( [
 // Shader by Evan Wallace adapted by @lo-th
-"vec3 vibrance_rgb(vec3 rgb, float adjustment) {",
-"	float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
-"	float mx = max(rgb.r, max(rgb.g, rgb.b));",
-"	float amt = (mx - average) * (-3.0 * adjustment);",
-"	return mix(rgb.rgb, vec3(mx), amt);",
-"}"
+	"vec3 vibrance_rgb(vec3 rgb, float adjustment) {",
+	"	float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
+	"	float mx = max(rgb.r, max(rgb.g, rgb.b));",
+	"	float amt = (mx - average) * (-3.0 * adjustment);",
+	"	return mix(rgb.rgb, vec3(mx), amt);",
+	"}"
 ].join( "\n" ) ) );

+ 147 - 80
examples/js/nodes/NodeMaterial.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodeMaterial = function( vertex, fragment ) {
+THREE.NodeMaterial = function ( vertex, fragment ) {
 
 	THREE.ShaderMaterial.call( this );
 
@@ -12,29 +12,29 @@ THREE.NodeMaterial = function( vertex, fragment ) {
 };
 
 THREE.NodeMaterial.types = {
-	t : 'sampler2D',
-	tc : 'samplerCube',
-	bv1 : 'bool',
-	iv1 : 'int',
-	fv1 : 'float',
-	c : 'vec3',
-	v2 : 'vec2',
-	v3 : 'vec3',
-	v4 : 'vec4',
-	m4 : 'mat4'
+	t: 'sampler2D',
+	tc: 'samplerCube',
+	bv1: 'bool',
+	iv1: 'int',
+	fv1: 'float',
+	c: 'vec3',
+	v2: 'vec2',
+	v3: 'vec3',
+	v4: 'vec4',
+	m4: 'mat4'
 };
 
-THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
+THREE.NodeMaterial.addShortcuts = function ( proto, prop, list ) {
 
 	function applyShortcut( prop, name ) {
 
 		return {
-			get: function() {
+			get: function () {
 
 				return this[ prop ][ name ];
 
 			},
-			set: function( val ) {
+			set: function ( val ) {
 
 				this[ prop ][ name ] = val;
 
@@ -43,7 +43,7 @@ THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
 
 	}
 
-	return ( function() {
+	return ( function () {
 
 		var shortcuts = {};
 
@@ -63,28 +63,31 @@ THREE.NodeMaterial.addShortcuts = function( proto, prop, list ) {
 
 THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
 THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
+THREE.NodeMaterial.prototype.type = "NodeMaterial";
 
-THREE.NodeMaterial.prototype.updateFrame = function( delta ) {
+THREE.NodeMaterial.prototype.updateFrame = function ( delta ) {
 
-	for ( var i = 0; i < this.requestUpdate.length; ++ i ) {
+	for ( var i = 0; i < this.updaters.length; ++ i ) {
 
-		this.requestUpdate[ i ].updateFrame( delta );
+		this.updaters[ i ].updateFrame( delta );
 
 	}
 
 };
 
-THREE.NodeMaterial.prototype.build = function() {
+THREE.NodeMaterial.prototype.build = function () {
 
 	var vertex, fragment;
 
+	this.nodes = [];
+
 	this.defines = {};
 	this.uniforms = {};
 	this.attributes = {};
 
 	this.extensions = {};
 
-	this.nodeData = {};	
+	this.nodeData = {};
 
 	this.vertexUniform = [];
 	this.fragmentUniform = [];
@@ -98,11 +101,13 @@ THREE.NodeMaterial.prototype.build = function() {
 	this.consts = [];
 	this.functions = [];
 
-	this.requestUpdate = [];
+	this.updaters = [];
 
-	this.requestAttribs = {
+	this.requires = {
 		uv: [],
-		color: []
+		color: [],
+		lights: this.lights,
+		fog: this.fog
 	};
 
 	this.vertexPars = '';
@@ -115,25 +120,25 @@ THREE.NodeMaterial.prototype.build = function() {
 	this.fragmentNode = '';
 
 	this.prefixCode = [
-	"#ifdef GL_EXT_shader_texture_lod",
+		"#ifdef GL_EXT_shader_texture_lod",
 
-	"	#define texCube(a, b) textureCube(a, b)",
-	"	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
+		"	#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)",
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
 
-	"#else",
+		"#else",
 
-	"	#define texCube(a, b) textureCube(a, b)",
-	"	#define texCubeBias(a, b, c) textureCube(a, b, c)",
+		"	#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)",
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2D(a, b, c)",
 
-	"#endif",
+		"#endif",
 
-	"#include <packing>"
+		"#include <packing>"
 
 	].join( "\n" );
 
@@ -142,7 +147,7 @@ THREE.NodeMaterial.prototype.build = function() {
 	vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
 	fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
 
-	if ( this.requestAttribs.uv[ 0 ] ) {
+	if ( this.requires.uv[ 0 ] ) {
 
 		this.addVertexPars( 'varying vec2 vUv;' );
 		this.addFragmentPars( 'varying vec2 vUv;' );
@@ -151,7 +156,7 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.uv[ 1 ] ) {
+	if ( this.requires.uv[ 1 ] ) {
 
 		this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
 		this.addFragmentPars( 'varying vec2 vUv2;' );
@@ -160,7 +165,7 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.color[ 0 ] ) {
+	if ( this.requires.color[ 0 ] ) {
 
 		this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
 		this.addFragmentPars( 'varying vec4 vColor;' );
@@ -169,7 +174,7 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.color[ 1 ] ) {
+	if ( this.requires.color[ 1 ] ) {
 
 		this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
 		this.addFragmentPars( 'varying vec4 vColor2;' );
@@ -178,7 +183,7 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.position ) {
+	if ( this.requires.position ) {
 
 		this.addVertexPars( 'varying vec3 vPosition;' );
 		this.addFragmentPars( 'varying vec3 vPosition;' );
@@ -187,16 +192,16 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.worldPosition ) {
+	if ( this.requires.worldPosition ) {
 
 		this.addVertexPars( 'varying vec3 vWPosition;' );
 		this.addFragmentPars( 'varying vec3 vWPosition;' );
 
-		this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( position, 1.0 ) ).xyz;' );
+		this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
 
 	}
 
-	if ( this.requestAttribs.normal ) {
+	if ( this.requires.normal ) {
 
 		this.addVertexPars( 'varying vec3 vObjectNormal;' );
 		this.addFragmentPars( 'varying vec3 vObjectNormal;' );
@@ -205,7 +210,7 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	if ( this.requestAttribs.worldNormal ) {
+	if ( this.requires.worldNormal ) {
 
 		this.addVertexPars( 'varying vec3 vWNormal;' );
 		this.addFragmentPars( 'varying vec3 vWNormal;' );
@@ -214,8 +219,10 @@ THREE.NodeMaterial.prototype.build = function() {
 
 	}
 
-	this.lights = this.requestAttribs.light;
-	this.transparent = this.requestAttribs.transparent || this.blending > THREE.NormalBlending;
+	this.fog = this.requires.fog;
+	this.lights = this.requires.lights;
+
+	this.transparent = this.requires.transparent || this.blending > THREE.NormalBlending;
 
 	this.vertexShader = [
 		this.prefixCode,
@@ -250,19 +257,19 @@ THREE.NodeMaterial.prototype.build = function() {
 
 };
 
-THREE.NodeMaterial.prototype.define = function( name, value ) {
+THREE.NodeMaterial.prototype.define = function ( name, value ) {
 
 	this.defines[ name ] = value == undefined ? 1 : value;
 
 };
 
-THREE.NodeMaterial.prototype.isDefined = function( name ) {
+THREE.NodeMaterial.prototype.isDefined = function ( name ) {
 
 	return this.defines[ name ] != undefined;
 
 };
 
-THREE.NodeMaterial.prototype.mergeUniform = function( uniforms ) {
+THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
 
 	for ( var name in uniforms ) {
 
@@ -272,15 +279,15 @@ THREE.NodeMaterial.prototype.mergeUniform = function( uniforms ) {
 
 };
 
-THREE.NodeMaterial.prototype.createUniform = function( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createUniform = function ( type, value, ns, needsUpdate ) {
 
 	var index = this.uniformList.length;
 
 	var uniform = {
-		type : type,
-		value : value,
-		name : ns ? ns : 'nVu' + index,
-		needsUpdate : needsUpdate
+		type: type,
+		value: value,
+		name: ns ? ns : 'nVu' + index,
+		needsUpdate: needsUpdate
 	};
 
 	this.uniformList.push( uniform );
@@ -289,7 +296,7 @@ THREE.NodeMaterial.prototype.createUniform = function( type, value, ns, needsUpd
 
 };
 
-THREE.NodeMaterial.prototype.getVertexTemp = function( uuid, type, ns ) {
+THREE.NodeMaterial.prototype.getVertexTemp = function ( uuid, type, ns ) {
 
 	var data = this.vertexTemps[ uuid ];
 
@@ -298,7 +305,7 @@ THREE.NodeMaterial.prototype.getVertexTemp = function( uuid, type, ns ) {
 		var index = this.vertexTemps.length,
 			name = ns ? ns : 'nVt' + index;
 
-		data = { name : name, type : type };
+		data = { name: name, type: type };
 
 		this.vertexTemps.push( data );
 		this.vertexTemps[ uuid ] = data;
@@ -309,7 +316,7 @@ THREE.NodeMaterial.prototype.getVertexTemp = function( uuid, type, ns ) {
 
 };
 
-THREE.NodeMaterial.prototype.getFragmentTemp = function( uuid, type, ns ) {
+THREE.NodeMaterial.prototype.getFragmentTemp = function ( uuid, type, ns ) {
 
 	var data = this.fragmentTemps[ uuid ];
 
@@ -318,7 +325,7 @@ THREE.NodeMaterial.prototype.getFragmentTemp = function( uuid, type, ns ) {
 		var index = this.fragmentTemps.length,
 			name = ns ? ns : 'nVt' + index;
 
-		data = { name : name, type : type };
+		data = { name: name, type: type };
 
 		this.fragmentTemps.push( data );
 		this.fragmentTemps[ uuid ] = data;
@@ -329,7 +336,7 @@ THREE.NodeMaterial.prototype.getFragmentTemp = function( uuid, type, ns ) {
 
 };
 
-THREE.NodeMaterial.prototype.getVar = function( uuid, type, ns ) {
+THREE.NodeMaterial.prototype.getVar = function ( uuid, type, ns ) {
 
 	var data = this.vars[ uuid ];
 
@@ -338,7 +345,7 @@ THREE.NodeMaterial.prototype.getVar = function( uuid, type, ns ) {
 		var index = this.vars.length,
 			name = ns ? ns : 'nVv' + index;
 
-		data = { name : name, type : type };
+		data = { name: name, type: type };
 
 		this.vars.push( data );
 		this.vars[ uuid ] = data;
@@ -352,7 +359,7 @@ THREE.NodeMaterial.prototype.getVar = function( uuid, type, ns ) {
 
 };
 
-THREE.NodeMaterial.prototype.getAttribute = function( name, type ) {
+THREE.NodeMaterial.prototype.getAttribute = function ( name, type ) {
 
 	if ( ! this.attributes[ name ] ) {
 
@@ -361,7 +368,7 @@ THREE.NodeMaterial.prototype.getAttribute = function( name, type ) {
 		this.addVertexPars( 'attribute ' + type + ' ' + name + ';' );
 		this.addVertexCode( varying.name + ' = ' + name + ';' );
 
-		this.attributes[ name ] = { varying : varying, name : name, type : type };
+		this.attributes[ name ] = { varying: varying, name: name, type: type };
 
 	}
 
@@ -369,7 +376,7 @@ THREE.NodeMaterial.prototype.getAttribute = function( name, type ) {
 
 };
 
-THREE.NodeMaterial.prototype.getIncludes = function() {
+THREE.NodeMaterial.prototype.getIncludes = function () {
 
 	function sortByPosition( a, b ) {
 
@@ -377,7 +384,7 @@ THREE.NodeMaterial.prototype.getIncludes = function() {
 
 	}
 
-	return function( incs ) {
+	return function ( incs ) {
 
 		if ( ! incs ) return '';
 
@@ -391,41 +398,41 @@ THREE.NodeMaterial.prototype.getIncludes = function() {
 
 		return code;
 
-	}
+	};
 
 }();
 
-THREE.NodeMaterial.prototype.addVertexPars = function( code ) {
+THREE.NodeMaterial.prototype.addVertexPars = function ( code ) {
 
 	this.vertexPars += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.addFragmentPars = function( code ) {
+THREE.NodeMaterial.prototype.addFragmentPars = function ( code ) {
 
 	this.fragmentPars += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.addVertexCode = function( code ) {
+THREE.NodeMaterial.prototype.addVertexCode = function ( code ) {
 
 	this.vertexCode += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.addFragmentCode = function( code ) {
+THREE.NodeMaterial.prototype.addFragmentCode = function ( code ) {
 
 	this.fragmentCode += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.addVertexNode = function( code ) {
+THREE.NodeMaterial.prototype.addVertexNode = function ( code ) {
 
 	this.vertexNode += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.clearVertexNode = function() {
+THREE.NodeMaterial.prototype.clearVertexNode = function () {
 
 	var code = this.vertexNode;
 
@@ -435,13 +442,13 @@ THREE.NodeMaterial.prototype.clearVertexNode = function() {
 
 };
 
-THREE.NodeMaterial.prototype.addFragmentNode = function( code ) {
+THREE.NodeMaterial.prototype.addFragmentNode = function ( code ) {
 
 	this.fragmentNode += code + '\n';
 
 };
 
-THREE.NodeMaterial.prototype.clearFragmentNode = function() {
+THREE.NodeMaterial.prototype.clearFragmentNode = function () {
 
 	var code = this.fragmentNode;
 
@@ -451,7 +458,7 @@ THREE.NodeMaterial.prototype.clearFragmentNode = function() {
 
 };
 
-THREE.NodeMaterial.prototype.getCodePars = function( pars, prefix ) {
+THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
 
 	prefix = prefix || '';
 
@@ -477,7 +484,7 @@ THREE.NodeMaterial.prototype.getCodePars = function( pars, prefix ) {
 
 };
 
-THREE.NodeMaterial.prototype.createVertexUniform = function( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createVertexUniform = function ( type, value, ns, needsUpdate ) {
 
 	var uniform = this.createUniform( type, value, ns, needsUpdate );
 
@@ -490,7 +497,7 @@ THREE.NodeMaterial.prototype.createVertexUniform = function( type, value, ns, ne
 
 };
 
-THREE.NodeMaterial.prototype.createFragmentUniform = function( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, value, ns, needsUpdate ) {
 
 	var uniform = this.createUniform( type, value, ns, needsUpdate );
 
@@ -503,13 +510,13 @@ THREE.NodeMaterial.prototype.createFragmentUniform = function( type, value, ns,
 
 };
 
-THREE.NodeMaterial.prototype.getDataNode = function( uuid ) {
+THREE.NodeMaterial.prototype.getDataNode = function ( uuid ) {
 
 	return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
 
 };
 
-THREE.NodeMaterial.prototype.include = function( builder, node, parent, source ) {
+THREE.NodeMaterial.prototype.include = function ( builder, node, parent, source ) {
 
 	var includes;
 
@@ -530,8 +537,8 @@ THREE.NodeMaterial.prototype.include = function( builder, node, parent, source )
 	if ( ! included ) {
 
 		included = includes[ node.name ] = {
-			node : node,
-			deps : []
+			node: node,
+			deps: []
 		};
 
 		includes.push( included );
@@ -565,3 +572,63 @@ THREE.NodeMaterial.prototype.include = function( builder, node, parent, source )
 	}
 
 };
+
+THREE.NodeMaterial.prototype.toJSON = function ( meta ) {
+
+	var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+	if ( isRootObject ) {
+
+		meta = {
+			nodes: {}
+		};
+
+	}
+
+	if ( meta && ! meta.materials ) meta.materials = {};
+
+	if ( ! meta.materials[ this.uuid ] ) {
+
+		var data = {};
+
+		data.uuid = this.uuid;
+		data.type = this.type;
+
+		meta.materials[ data.uuid ] = data;
+
+		if ( this.name !== "" ) data.name = this.name;
+
+		if ( this.blending !== THREE.NormalBlending ) data.blending = this.blending;
+		if ( this.flatShading === true ) data.flatShading = this.flatShading;
+		if ( this.side !== THREE.FrontSide ) data.side = this.side;
+
+		if ( this.transparent === true ) data.transparent = this.transparent;
+
+		data.depthFunc = this.depthFunc;
+		data.depthTest = this.depthTest;
+		data.depthWrite = this.depthWrite;
+
+		if ( this.wireframe === true ) data.wireframe = this.wireframe;
+		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
+		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
+		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
+
+		if ( this.morphTargets === true ) data.morphTargets = true;
+		if ( this.skinning === true ) data.skinning = true;
+
+		data.fog = this.fog;
+		data.lights = this.lights;
+
+		if ( this.visible === false ) data.visible = false;
+		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+		data.vertex = this.vertex.toJSON( meta ).uuid;
+		data.fragment = this.fragment.toJSON( meta ).uuid;
+
+	}
+
+	meta.material = this.uuid;
+
+	return meta;
+
+};

+ 19 - 2
examples/js/nodes/RawNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.RawNode = function( value ) {
+THREE.RawNode = function ( value ) {
 
 	THREE.GLNode.call( this, 'v4' );
 
@@ -12,8 +12,9 @@ THREE.RawNode = function( value ) {
 
 THREE.RawNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.RawNode.prototype.constructor = THREE.RawNode;
+THREE.RawNode.prototype.nodeType = "Raw";
 
-THREE.GLNode.prototype.generate = function( builder ) {
+THREE.RawNode.prototype.generate = function ( builder ) {
 
 	var material = builder.material;
 
@@ -34,3 +35,19 @@ THREE.GLNode.prototype.generate = function( builder ) {
 	return code;
 
 };
+
+THREE.RawNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 7 - 7
examples/js/nodes/TempNode.js

@@ -3,7 +3,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TempNode = function( type, params ) {
+THREE.TempNode = function ( type, params ) {
 
 	THREE.GLNode.call( this, type );
 
@@ -17,7 +17,7 @@ THREE.TempNode = function( type, params ) {
 THREE.TempNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.TempNode.prototype.constructor = THREE.TempNode;
 
-THREE.TempNode.prototype.build = function( builder, output, uuid, ns ) {
+THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
 
 	output = output || this.getType( builder );
 
@@ -89,19 +89,19 @@ THREE.TempNode.prototype.build = function( builder, output, uuid, ns ) {
 
 };
 
-THREE.TempNode.prototype.isShared = function( builder, output ) {
+THREE.TempNode.prototype.isShared = function ( builder, output ) {
 
 	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
 
 };
 
-THREE.TempNode.prototype.isUnique = function( builder, output ) {
+THREE.TempNode.prototype.isUnique = function ( builder, output ) {
 
 	return this.unique;
 
 };
 
-THREE.TempNode.prototype.getUuid = function( unique ) {
+THREE.TempNode.prototype.getUuid = function ( unique ) {
 
 	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
 
@@ -111,7 +111,7 @@ THREE.TempNode.prototype.getUuid = function( unique ) {
 
 };
 
-THREE.TempNode.prototype.getTemp = function( builder, uuid ) {
+THREE.TempNode.prototype.getTemp = function ( builder, uuid ) {
 
 	uuid = uuid || this.uuid;
 
@@ -122,7 +122,7 @@ THREE.TempNode.prototype.getTemp = function( builder, uuid ) {
 
 };
 
-THREE.TempNode.prototype.generate = function( builder, output, uuid, type, ns ) {
+THREE.TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
 
 	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
 

+ 20 - 3
examples/js/nodes/VarNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.VarNode = function( type ) {
+THREE.VarNode = function ( type ) {
 
 	THREE.GLNode.call( this, type );
 
@@ -10,17 +10,34 @@ THREE.VarNode = function( type ) {
 
 THREE.VarNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.VarNode.prototype.constructor = THREE.VarNode;
+THREE.VarNode.prototype.nodeType = "Var";
 
-THREE.VarNode.prototype.getType = function( builder ) {
+THREE.VarNode.prototype.getType = function ( builder ) {
 
 	return builder.getTypeByFormat( this.type );
 
 };
 
-THREE.VarNode.prototype.generate = function( builder, output ) {
+THREE.VarNode.prototype.generate = function ( builder, output ) {
 
 	var varying = builder.material.getVar( this.uuid, this.type );
 
 	return builder.format( varying.name, this.getType( builder ), output );
 
 };
+
+THREE.VarNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.out = this.type;
+
+	}
+
+	return data;
+
+};

+ 34 - 2
examples/js/nodes/accessors/CameraNode.js

@@ -28,11 +28,12 @@ THREE.CameraNode.TO_VERTEX = 'toVertex';
 
 THREE.CameraNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.CameraNode.prototype.constructor = THREE.CameraNode;
+THREE.CameraNode.prototype.nodeType = "Camera";
 
 THREE.CameraNode.prototype.setCamera = function ( camera ) {
 
 	this.camera = camera;
-	this.requestUpdate = camera !== undefined;
+	this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
 
 };
 
@@ -56,6 +57,7 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
 		case THREE.CameraNode.DEPTH:
 
 			var camera = this.camera;
+
 			this.near = new THREE.FloatNode( camera ? camera.near : 1 );
 			this.far = new THREE.FloatNode( camera ? camera.far : 1200 );
 
@@ -140,13 +142,14 @@ THREE.CameraNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.CameraNode.prototype.updateFrame = function ( delta ) {
+THREE.CameraNode.prototype.onUpdateFrame = function ( delta ) {
 
 	switch ( this.scope ) {
 
 		case THREE.CameraNode.DEPTH:
 
 			var camera = this.camera;
+
 			this.near.number = camera.near;
 			this.far.number = camera.far;
 
@@ -155,3 +158,32 @@ THREE.CameraNode.prototype.updateFrame = function ( delta ) {
 	}
 
 };
+
+THREE.CameraNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.scope = this.scope;
+
+		if ( this.camera ) data.camera = this.camera.uuid;
+
+		switch ( this.scope ) {
+
+			case THREE.CameraNode.DEPTH:
+
+				data.near = this.near.number;
+				data.far = this.far.number;
+
+				break;
+
+		}
+
+	}
+
+	return data;
+
+};

+ 19 - 3
examples/js/nodes/accessors/ColorsNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ColorsNode = function( index ) {
+THREE.ColorsNode = function ( index ) {
 
 	THREE.TempNode.call( this, 'v4', { shared: false } );
 
@@ -16,12 +16,12 @@ THREE.ColorsNode.fragmentDict = [ 'vColor', 'vColor2' ];
 THREE.ColorsNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ColorsNode.prototype.constructor = THREE.ColorsNode;
 
-THREE.ColorsNode.prototype.generate = function( builder, output ) {
+THREE.ColorsNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 	var result;
 
-	material.requestAttribs.color[ this.index ] = true;
+	material.requires.color[ this.index ] = true;
 
 	if ( builder.isShader( 'vertex' ) ) result = THREE.ColorsNode.vertexDict[ this.index ];
 	else result = THREE.ColorsNode.fragmentDict[ this.index ];
@@ -29,3 +29,19 @@ THREE.ColorsNode.prototype.generate = function( builder, output ) {
 	return builder.format( result, this.getType( builder ), output );
 
 };
+
+THREE.ColorsNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.index = this.index;
+
+	}
+
+	return data;
+
+};

+ 4 - 3
examples/js/nodes/accessors/LightNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.LightNode = function() {
+THREE.LightNode = function () {
 
 	THREE.TempNode.call( this, 'v3', { shared: false } );
 
@@ -10,12 +10,13 @@ THREE.LightNode = function() {
 
 THREE.LightNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.LightNode.prototype.constructor = THREE.LightNode;
+THREE.LightNode.prototype.nodeType = "Light";
 
-THREE.LightNode.prototype.generate = function( builder, output ) {
+THREE.LightNode.prototype.generate = function ( builder, output ) {
 
 	if ( builder.isCache( 'light' ) ) {
 
-		return builder.format( 'reflectedLight.directDiffuse', this.getType( builder ), output )
+		return builder.format( 'reflectedLight.directDiffuse', this.getType( builder ), output );
 
 	} else {
 

+ 24 - 5
examples/js/nodes/accessors/NormalNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NormalNode = function( scope ) {
+THREE.NormalNode = function ( scope ) {
 
 	THREE.TempNode.call( this, 'v3' );
 
@@ -16,19 +16,22 @@ THREE.NormalNode.VIEW = 'view';
 
 THREE.NormalNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.NormalNode.prototype.constructor = THREE.NormalNode;
+THREE.NormalNode.prototype.nodeType = "Normal";
 
-THREE.NormalNode.prototype.isShared = function( builder ) {
+THREE.NormalNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
+
 		case THREE.NormalNode.WORLD:
 			return true;
+
 	}
 
 	return false;
 
 };
 
-THREE.NormalNode.prototype.generate = function( builder, output ) {
+THREE.NormalNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 	var result;
@@ -37,7 +40,7 @@ THREE.NormalNode.prototype.generate = function( builder, output ) {
 
 		case THREE.NormalNode.LOCAL:
 
-			material.requestAttribs.normal = true;
+			material.requires.normal = true;
 
 			if ( builder.isShader( 'vertex' ) ) result = 'normal';
 			else result = 'vObjectNormal';
@@ -46,7 +49,7 @@ THREE.NormalNode.prototype.generate = function( builder, output ) {
 
 		case THREE.NormalNode.WORLD:
 
-			material.requestAttribs.worldNormal = true;
+			material.requires.worldNormal = true;
 
 			if ( builder.isShader( 'vertex' ) ) result = '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz';
 			else result = 'vWNormal';
@@ -64,3 +67,19 @@ THREE.NormalNode.prototype.generate = function( builder, output ) {
 	return builder.format( result, this.getType( builder ), output );
 
 };
+
+THREE.NormalNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.scope = this.scope;
+
+	}
+
+	return data;
+
+};

+ 27 - 6
examples/js/nodes/accessors/PositionNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PositionNode = function( scope ) {
+THREE.PositionNode = function ( scope ) {
 
 	THREE.TempNode.call( this, 'v3' );
 
@@ -17,31 +17,36 @@ THREE.PositionNode.PROJECTION = 'projection';
 
 THREE.PositionNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.PositionNode.prototype.constructor = THREE.PositionNode;
+THREE.PositionNode.prototype.nodeType = "Position";
 
-THREE.PositionNode.prototype.getType = function( builder ) {
+THREE.PositionNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
+
 		case THREE.PositionNode.PROJECTION:
 			return 'v4';
+
 	}
 
 	return this.type;
 
 };
 
-THREE.PositionNode.prototype.isShared = function( builder ) {
+THREE.PositionNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
+
 		case THREE.PositionNode.LOCAL:
 		case THREE.PositionNode.WORLD:
 			return false;
+
 	}
 
 	return true;
 
 };
 
-THREE.PositionNode.prototype.generate = function( builder, output ) {
+THREE.PositionNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 	var result;
@@ -50,7 +55,7 @@ THREE.PositionNode.prototype.generate = function( builder, output ) {
 
 		case THREE.PositionNode.LOCAL:
 
-			material.requestAttribs.position = true;
+			material.requires.position = true;
 
 			if ( builder.isShader( 'vertex' ) ) result = 'transformed';
 			else result = 'vPosition';
@@ -59,7 +64,7 @@ THREE.PositionNode.prototype.generate = function( builder, output ) {
 
 		case THREE.PositionNode.WORLD:
 
-			material.requestAttribs.worldPosition = true;
+			material.requires.worldPosition = true;
 
 			if ( builder.isShader( 'vertex' ) ) result = 'vWPosition';
 			else result = 'vWPosition';
@@ -85,3 +90,19 @@ THREE.PositionNode.prototype.generate = function( builder, output ) {
 	return builder.format( result, this.getType( builder ), output );
 
 };
+
+THREE.PositionNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.scope = this.scope;
+
+	}
+
+	return data;
+
+};

+ 23 - 3
examples/js/nodes/accessors/ReflectNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ReflectNode = function( scope ) {
+THREE.ReflectNode = function ( scope ) {
 
 	THREE.TempNode.call( this, 'v3', { unique: true } );
 
@@ -16,19 +16,22 @@ THREE.ReflectNode.VECTOR = 'vector';
 
 THREE.ReflectNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ReflectNode.prototype.constructor = THREE.ReflectNode;
+THREE.ReflectNode.prototype.nodeType = "Reflect";
 
-THREE.ReflectNode.prototype.getType = function( builder ) {
+THREE.ReflectNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
+
 		case THREE.ReflectNode.SPHERE:
 			return 'v2';
+
 	}
 
 	return this.type;
 
 };
 
-THREE.ReflectNode.prototype.generate = function( builder, output ) {
+THREE.ReflectNode.prototype.generate = function ( builder, output ) {
 
 	var result;
 
@@ -61,8 +64,25 @@ THREE.ReflectNode.prototype.generate = function( builder, output ) {
 			result = 'reflectSphereVec';
 
 			break;
+
 	}
 
 	return builder.format( result, this.getType( this.type ), output );
 
 };
+
+THREE.ReflectNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.scope = this.scope;
+
+	}
+
+	return data;
+
+};

+ 19 - 2
examples/js/nodes/accessors/ScreenUVNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ScreenUVNode = function( resolution ) {
+THREE.ScreenUVNode = function ( resolution ) {
 
 	THREE.TempNode.call( this, 'v2' );
 
@@ -12,8 +12,9 @@ THREE.ScreenUVNode = function( resolution ) {
 
 THREE.ScreenUVNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ScreenUVNode.prototype.constructor = THREE.ScreenUVNode;
+THREE.ScreenUVNode.prototype.nodeType = "ScreenUV";
 
-THREE.ScreenUVNode.prototype.generate = function( builder, output ) {
+THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 	var result;
@@ -33,3 +34,19 @@ THREE.ScreenUVNode.prototype.generate = function( builder, output ) {
 	return builder.format( result, this.getType( builder ), output );
 
 };
+
+THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.resolution = this.resolution.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 20 - 3
examples/js/nodes/accessors/UVNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.UVNode = function( index ) {
+THREE.UVNode = function ( index ) {
 
 	THREE.TempNode.call( this, 'v2', { shared: false } );
 
@@ -15,13 +15,14 @@ THREE.UVNode.fragmentDict = [ 'vUv', 'vUv2' ];
 
 THREE.UVNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.UVNode.prototype.constructor = THREE.UVNode;
+THREE.UVNode.prototype.nodeType = "UV";
 
-THREE.UVNode.prototype.generate = function( builder, output ) {
+THREE.UVNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 	var result;
 
-	material.requestAttribs.uv[ this.index ] = true;
+	material.requires.uv[ this.index ] = true;
 
 	if ( builder.isShader( 'vertex' ) ) result = THREE.UVNode.vertexDict[ this.index ];
 	else result = THREE.UVNode.fragmentDict[ this.index ];
@@ -29,3 +30,19 @@ THREE.UVNode.prototype.generate = function( builder, output ) {
 	return builder.format( result, this.getType( builder ), output );
 
 };
+
+THREE.UVNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.index = this.index;
+
+	}
+
+	return data;
+
+};

+ 20 - 1
examples/js/nodes/inputs/ColorNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ColorNode = function( color ) {
+THREE.ColorNode = function ( color ) {
 
 	THREE.InputNode.call( this, 'c' );
 
@@ -12,5 +12,24 @@ THREE.ColorNode = function( color ) {
 
 THREE.ColorNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.ColorNode.prototype.constructor = THREE.ColorNode;
+THREE.ColorNode.prototype.nodeType = "Color";
 
 THREE.NodeMaterial.addShortcuts( THREE.ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
+
+THREE.ColorNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.r = this.r;
+		data.g = this.g;
+		data.b = this.b;
+
+	}
+
+	return data;
+
+};

+ 24 - 4
examples/js/nodes/inputs/CubeTextureNode.js

@@ -2,9 +2,9 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.CubeTextureNode = function( value, coord, bias ) {
+THREE.CubeTextureNode = function ( value, coord, bias ) {
 
-	THREE.InputNode.call( this, 'v4', { shared : true } );
+	THREE.InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
 	this.coord = coord || new THREE.ReflectNode();
@@ -14,14 +14,15 @@ THREE.CubeTextureNode = function( value, coord, bias ) {
 
 THREE.CubeTextureNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.CubeTextureNode.prototype.constructor = THREE.CubeTextureNode;
+THREE.CubeTextureNode.prototype.nodeType = "CubeTexture";
 
-THREE.CubeTextureNode.prototype.getTexture = function( builder, output ) {
+THREE.CubeTextureNode.prototype.getTexture = function ( builder, output ) {
 
 	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
 
 };
 
-THREE.CubeTextureNode.prototype.generate = function( builder, output ) {
+THREE.CubeTextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'samplerCube' ) {
 
@@ -61,3 +62,22 @@ THREE.CubeTextureNode.prototype.generate = function( builder, output ) {
 	return builder.format( code, this.type, output );
 
 };
+
+THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.uuid;
+		data.coord = this.coord.toJSON( meta ).uuid;
+
+		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 20 - 3
examples/js/nodes/inputs/FloatNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.FloatNode = function( value ) {
+THREE.FloatNode = function ( value ) {
 
 	THREE.InputNode.call( this, 'fv1' );
 
@@ -12,18 +12,35 @@ THREE.FloatNode = function( value ) {
 
 THREE.FloatNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.FloatNode.prototype.constructor = THREE.FloatNode;
+THREE.FloatNode.prototype.nodeType = "Float";
 
 Object.defineProperties( THREE.FloatNode.prototype, {
 	number: {
-		get: function() {
+		get: function () {
 
 			return this.value[ 0 ];
 
 		},
-		set: function( val ) {
+		set: function ( val ) {
 
 			this.value[ 0 ] = val;
 
 		}
 	}
 } );
+
+THREE.FloatNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.number = this.number;
+
+	}
+
+	return data;
+
+};

+ 20 - 3
examples/js/nodes/inputs/IntNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.IntNode = function( value ) {
+THREE.IntNode = function ( value ) {
 
 	THREE.InputNode.call( this, 'iv1' );
 
@@ -12,18 +12,35 @@ THREE.IntNode = function( value ) {
 
 THREE.IntNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.IntNode.prototype.constructor = THREE.IntNode;
+THREE.IntNode.prototype.nodeType = "Int";
 
 Object.defineProperties( THREE.IntNode.prototype, {
 	number: {
-		get: function() {
+		get: function () {
 
 			return this.value[ 0 ];
 
 		},
-		set: function( val ) {
+		set: function ( val ) {
 
 			this.value[ 0 ] = Math.floor( val );
 
 		}
 	}
 } );
+
+THREE.IntNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.number = this.number;
+
+	}
+
+	return data;
+
+};

+ 18 - 1
examples/js/nodes/inputs/Matrix4Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Matrix4Node = function( matrix ) {
+THREE.Matrix4Node = function ( matrix ) {
 
 	THREE.InputNode.call( this, 'm4' );
 
@@ -12,3 +12,20 @@ THREE.Matrix4Node = function( matrix ) {
 
 THREE.Matrix4Node.prototype = Object.create( THREE.InputNode.prototype );
 THREE.Matrix4Node.prototype.constructor = THREE.Matrix4Node;
+THREE.Matrix4Node.prototype.nodeType = "Matrix4";
+
+THREE.Matrix4Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.elements = this.value.elements.concat();
+
+	}
+
+	return data;
+
+};

+ 30 - 5
examples/js/nodes/inputs/ReflectorNode.js

@@ -1,7 +1,17 @@
-THREE.ReflectorNode = function( mirror, camera, options ) {
+THREE.ReflectorNode = function ( mirror ) {
 
 	THREE.TempNode.call( this, 'v4' );
 
+	if ( mirror ) this.setMirror( mirror );
+
+};
+
+THREE.ReflectorNode.prototype = Object.create( THREE.TempNode.prototype );
+THREE.ReflectorNode.prototype.constructor = THREE.ReflectorNode;
+THREE.ReflectorNode.prototype.nodeType = "Reflector";
+
+THREE.ReflectorNode.prototype.setMirror = function ( mirror ) {
+
 	this.mirror = mirror;
 
 	this.textureMatrix = new THREE.Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
@@ -15,10 +25,7 @@ THREE.ReflectorNode = function( mirror, camera, options ) {
 
 };
 
-THREE.ReflectorNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ReflectorNode.prototype.constructor = THREE.ReflectorNode;
-
-THREE.ReflectorNode.prototype.generate = function( builder, output ) {
+THREE.ReflectorNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -44,3 +51,21 @@ THREE.ReflectorNode.prototype.generate = function( builder, output ) {
 	}
 
 };
+
+THREE.ReflectorNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.mirror = this.mirror.uuid;
+
+		if ( this.offset ) data.offset = this.offset.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 4 - 3
examples/js/nodes/inputs/ScreenNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ScreenNode = function( coord ) {
+THREE.ScreenNode = function ( coord ) {
 
 	THREE.TextureNode.call( this, undefined, coord );
 
@@ -10,14 +10,15 @@ THREE.ScreenNode = function( coord ) {
 
 THREE.ScreenNode.prototype = Object.create( THREE.TextureNode.prototype );
 THREE.ScreenNode.prototype.constructor = THREE.ScreenNode;
+THREE.ScreenNode.prototype.nodeType = "Screen";
 
-THREE.ScreenNode.prototype.isUnique = function() {
+THREE.ScreenNode.prototype.isUnique = function () {
 
 	return true;
 
 };
 
-THREE.ScreenNode.prototype.getTexture = function( builder, output ) {
+THREE.ScreenNode.prototype.getTexture = function ( builder, output ) {
 
 	return THREE.InputNode.prototype.generate.call( this, builder, output, this.getUuid(), 't', 'renderTexture' );
 

+ 26 - 4
examples/js/nodes/inputs/TextureNode.js

@@ -2,9 +2,9 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TextureNode = function( value, coord, bias, project ) {
+THREE.TextureNode = function ( value, coord, bias, project ) {
 
-	THREE.InputNode.call( this, 'v4', { shared : true } );
+	THREE.InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
 	this.coord = coord || new THREE.UVNode();
@@ -15,14 +15,15 @@ THREE.TextureNode = function( value, coord, bias, project ) {
 
 THREE.TextureNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.TextureNode.prototype.constructor = THREE.TextureNode;
+THREE.TextureNode.prototype.nodeType = "Texture";
 
-THREE.TextureNode.prototype.getTexture = function( builder, output ) {
+THREE.TextureNode.prototype.getTexture = function ( builder, output ) {
 
 	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
 
 };
 
-THREE.TextureNode.prototype.generate = function( builder, output ) {
+THREE.TextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'sampler2D' ) {
 
@@ -65,3 +66,24 @@ THREE.TextureNode.prototype.generate = function( builder, output ) {
 	return builder.format( code, this.type, output );
 
 };
+
+THREE.TextureNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		if ( this.value ) data.value = this.value.uuid;
+
+		data.coord = this.coord.toJSON( meta ).uuid;
+		data.project = this.project;
+
+		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 19 - 1
examples/js/nodes/inputs/Vector2Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector2Node = function( x, y ) {
+THREE.Vector2Node = function ( x, y ) {
 
 	THREE.InputNode.call( this, 'v2' );
 
@@ -12,5 +12,23 @@ THREE.Vector2Node = function( x, y ) {
 
 THREE.Vector2Node.prototype = Object.create( THREE.InputNode.prototype );
 THREE.Vector2Node.prototype.constructor = THREE.Vector2Node;
+THREE.Vector2Node.prototype.nodeType = "Vector2";
 
 THREE.NodeMaterial.addShortcuts( THREE.Vector2Node.prototype, 'value', [ 'x', 'y' ] );
+
+THREE.Vector2Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.x = this.x;
+		data.y = this.y;
+
+	}
+
+	return data;
+
+};

+ 20 - 1
examples/js/nodes/inputs/Vector3Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector3Node = function( x, y, z ) {
+THREE.Vector3Node = function ( x, y, z ) {
 
 	THREE.InputNode.call( this, 'v3' );
 
@@ -13,5 +13,24 @@ THREE.Vector3Node = function( x, y, z ) {
 
 THREE.Vector3Node.prototype = Object.create( THREE.InputNode.prototype );
 THREE.Vector3Node.prototype.constructor = THREE.Vector3Node;
+THREE.Vector3Node.prototype.nodeType = "Vector3";
 
 THREE.NodeMaterial.addShortcuts( THREE.Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
+
+THREE.Vector3Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.x = this.x;
+		data.y = this.y;
+		data.z = this.z;
+
+	}
+
+	return data;
+
+};

+ 21 - 1
examples/js/nodes/inputs/Vector4Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector4Node = function( x, y, z, w ) {
+THREE.Vector4Node = function ( x, y, z, w ) {
 
 	THREE.InputNode.call( this, 'v4' );
 
@@ -12,5 +12,25 @@ THREE.Vector4Node = function( x, y, z, w ) {
 
 THREE.Vector4Node.prototype = Object.create( THREE.InputNode.prototype );
 THREE.Vector4Node.prototype.constructor = THREE.Vector4Node;
+THREE.Vector4Node.prototype.nodeType = "Vector4";
 
 THREE.NodeMaterial.addShortcuts( THREE.Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
+
+THREE.Vector4Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.x = this.x;
+		data.y = this.y;
+		data.z = this.z;
+		data.w = this.w;
+
+	}
+
+	return data;
+
+};

+ 43 - 2
examples/js/nodes/materials/PhongNode.js

@@ -14,6 +14,7 @@ THREE.PhongNode = function () {
 
 THREE.PhongNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.PhongNode.prototype.constructor = THREE.PhongNode;
+THREE.PhongNode.prototype.nodeType = "Phong";
 
 THREE.PhongNode.prototype.build = function ( builder ) {
 
@@ -23,7 +24,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 	material.define( 'PHONG' );
 	material.define( 'ALPHATEST', '0.0' );
 
-	material.requestAttribs.light = true;
+	material.requires.lights = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
@@ -137,7 +138,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot: 'environment' } ) : undefined;
 		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'fv1' ) : undefined;
 
-		material.requestAttribs.transparent = alpha != undefined;
+		material.requires.transparent = alpha != undefined;
 
 		material.addFragmentPars( [
 			"#include <common>",
@@ -308,3 +309,43 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 	return code;
 
 };
+
+
+THREE.PhongNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		// vertex
+
+		if ( this.transform ) data.transform = this.transform.toJSON( meta ).uuid;
+
+		// fragment
+
+		data.color = this.color.toJSON( meta ).uuid;
+		data.specular = this.specular.toJSON( meta ).uuid;
+		data.shininess = this.shininess.toJSON( meta ).uuid;
+
+		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+
+		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
+		if ( this.normalScale ) data.normalScale = this.normalScale.toJSON( meta ).uuid;
+
+		if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
+
+		if ( this.ao ) data.ao = this.ao.toJSON( meta ).uuid;
+		if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
+		if ( this.shadow ) data.shadow = this.shadow.toJSON( meta ).uuid;
+		if ( this.emissive ) data.emissive = this.emissive.toJSON( meta ).uuid;
+
+		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
+		if ( this.environmentAlpha ) data.environmentAlpha = this.environmentAlpha.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 4 - 2
examples/js/nodes/materials/PhongNodeMaterial.js

@@ -2,16 +2,18 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNodeMaterial = function() {
+THREE.PhongNodeMaterial = function () {
 
 	this.node = new THREE.PhongNode();
 
 	THREE.NodeMaterial.call( this, this.node, this.node );
 
+	this.type = "PhongNodeMaterial";
+
 };
 
 THREE.PhongNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
 THREE.PhongNodeMaterial.prototype.constructor = THREE.PhongNodeMaterial;
 
 THREE.NodeMaterial.addShortcuts( THREE.PhongNodeMaterial.prototype, 'node',
-[ 'color', 'alpha', 'specular', 'shininess', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'environmentAlpha', 'transform' ] );
+	[ 'color', 'alpha', 'specular', 'shininess', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'environmentAlpha', 'transform' ] );

+ 28 - 2
examples/js/nodes/materials/SpriteNode.js

@@ -13,6 +13,7 @@ THREE.SpriteNode = function () {
 
 THREE.SpriteNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.SpriteNode.prototype.constructor = THREE.SpriteNode;
+THREE.SpriteNode.prototype.nodeType = "Sprite";
 
 THREE.SpriteNode.prototype.build = function ( builder ) {
 
@@ -21,8 +22,8 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 	material.define( 'SPRITE' );
 
-	material.requestAttribs.light = false;
-	material.requestAttribs.transparent = this.alpha != undefined;
+	material.requires.lights = false;
+	material.requires.transparent = this.alpha != undefined;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
@@ -137,3 +138,28 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 	return output.join( "\n" );
 
 };
+
+THREE.SpriteNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		// vertex
+
+		if ( this.transform ) data.transform = this.transform.toJSON( meta ).uuid;
+
+		// fragment
+
+		data.color = this.color.toJSON( meta ).uuid;
+		if ( this.spherical === false ) data.spherical = false;
+
+		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 3 - 1
examples/js/nodes/materials/SpriteNodeMaterial.js

@@ -8,10 +8,12 @@ THREE.SpriteNodeMaterial = function () {
 
 	THREE.NodeMaterial.call( this, this.node, this.node );
 
+	this.type = "SpriteNodeMaterial";
+
 };
 
 THREE.SpriteNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
 THREE.SpriteNodeMaterial.prototype.constructor = THREE.SpriteNodeMaterial;
 
 THREE.NodeMaterial.addShortcuts( THREE.SpriteNodeMaterial.prototype, 'node',
-[ 'color', 'alpha', 'transform', 'spherical' ] );
+	[ 'color', 'alpha', 'transform', 'spherical' ] );

+ 48 - 4
examples/js/nodes/materials/StandardNode.js

@@ -14,6 +14,7 @@ THREE.StandardNode = function () {
 
 THREE.StandardNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.StandardNode.prototype.constructor = THREE.StandardNode;
+THREE.StandardNode.prototype.nodeType = "Standard";
 
 THREE.StandardNode.prototype.build = function ( builder ) {
 
@@ -26,7 +27,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 	material.define( 'ALPHATEST', '0.0' );
 
-	material.requestAttribs.light = true;
+	material.requires.lights = true;
 
 	material.extensions.shaderTextureLOD = true;
 
@@ -166,7 +167,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', requires: requires, slot: 'environment' } ) : undefined;
 
-		material.requestAttribs.transparent = alpha != undefined;
+		material.requires.transparent = alpha != undefined;
 
 		material.addFragmentPars( [
 
@@ -189,10 +190,10 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 		].join( "\n" ) );
 
 		var output = [
-				// prevent undeclared normal
+			// prevent undeclared normal
 			"	#include <normal_fragment>",
 
-				// prevent undeclared material
+			// prevent undeclared material
 			"	PhysicalMaterial material;",
 			"	material.diffuseColor = vec3( 1.0 );",
 
@@ -393,3 +394,46 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 	return code;
 
 };
+
+THREE.StandardNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		// vertex
+
+		if ( this.transform ) data.transform = this.transform.toJSON( meta ).uuid;
+
+		// fragment
+
+		data.color = this.color.toJSON( meta ).uuid;
+		data.roughness = this.roughness.toJSON( meta ).uuid;
+		data.metalness = this.metalness.toJSON( meta ).uuid;
+
+		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+
+		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
+		if ( this.normalScale ) data.normalScale = this.normalScale.toJSON( meta ).uuid;
+
+		if ( this.clearCoat ) data.clearCoat = this.clearCoat.toJSON( meta ).uuid;
+		if ( this.clearCoatRoughness ) data.clearCoatRoughness = this.clearCoatRoughness.toJSON( meta ).uuid;
+
+		if ( this.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
+
+		if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
+
+		if ( this.ao ) data.ao = this.ao.toJSON( meta ).uuid;
+		if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
+		if ( this.shadow ) data.shadow = this.shadow.toJSON( meta ).uuid;
+		if ( this.emissive ) data.emissive = this.emissive.toJSON( meta ).uuid;
+
+		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 4 - 2
examples/js/nodes/materials/StandardNodeMaterial.js

@@ -2,16 +2,18 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNodeMaterial = function() {
+THREE.StandardNodeMaterial = function () {
 
 	this.node = new THREE.StandardNode();
 
 	THREE.NodeMaterial.call( this, this.node, this.node );
 
+	this.type = "StandardNodeMaterial";
+
 };
 
 THREE.StandardNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
 THREE.StandardNodeMaterial.prototype.constructor = THREE.StandardNodeMaterial;
 
 THREE.NodeMaterial.addShortcuts( THREE.StandardNodeMaterial.prototype, 'node',
-[ 'color', 'alpha', 'roughness', 'metalness', 'reflectivity', 'clearCoat', 'clearCoatRoughness', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'transform' ] );
+	[ 'color', 'alpha', 'roughness', 'metalness', 'reflectivity', 'clearCoat', 'clearCoatRoughness', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'transform' ] );

+ 24 - 3
examples/js/nodes/math/Math1Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Math1Node = function( a, method ) {
+THREE.Math1Node = function ( a, method ) {
 
 	THREE.TempNode.call( this );
 
@@ -39,19 +39,22 @@ THREE.Math1Node.INVERT = 'invert';
 
 THREE.Math1Node.prototype = Object.create( THREE.TempNode.prototype );
 THREE.Math1Node.prototype.constructor = THREE.Math1Node;
+THREE.Math1Node.prototype.nodeType = "Math1";
 
-THREE.Math1Node.prototype.getType = function( builder ) {
+THREE.Math1Node.prototype.getType = function ( builder ) {
 
 	switch ( this.method ) {
+
 		case THREE.Math1Node.LENGTH:
 			return 'fv1';
+
 	}
 
 	return this.a.getType( builder );
 
 };
 
-THREE.Math1Node.prototype.generate = function( builder, output ) {
+THREE.Math1Node.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -72,8 +75,26 @@ THREE.Math1Node.prototype.generate = function( builder, output ) {
 		default:
 			result = this.method + '(' + result + ')';
 			break;
+
 	}
 
 	return builder.format( result, type, output );
 
 };
+
+THREE.Math1Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.a = this.a.toJSON( meta ).uuid;
+		data.method = this.method;
+
+	}
+
+	return data;
+
+};

+ 26 - 4
examples/js/nodes/math/Math2Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Math2Node = function( a, b, method ) {
+THREE.Math2Node = function ( a, b, method ) {
 
 	THREE.TempNode.call( this );
 
@@ -25,8 +25,9 @@ THREE.Math2Node.POW = 'pow';
 
 THREE.Math2Node.prototype = Object.create( THREE.TempNode.prototype );
 THREE.Math2Node.prototype.constructor = THREE.Math2Node;
+THREE.Math2Node.prototype.nodeType = "Math2";
 
-THREE.Math2Node.prototype.getInputType = function( builder ) {
+THREE.Math2Node.prototype.getInputType = function ( builder ) {
 
 	// use the greater length vector
 	if ( builder.getFormatLength( this.b.getType( builder ) ) > builder.getFormatLength( this.a.getType( builder ) ) ) {
@@ -39,22 +40,24 @@ THREE.Math2Node.prototype.getInputType = function( builder ) {
 
 };
 
-THREE.Math2Node.prototype.getType = function( builder ) {
+THREE.Math2Node.prototype.getType = function ( builder ) {
 
 	switch ( this.method ) {
+
 		case THREE.Math2Node.DISTANCE:
 		case THREE.Math2Node.DOT:
 			return 'fv1';
 
 		case THREE.Math2Node.CROSS:
 			return 'v3';
+
 	}
 
 	return this.getInputType( builder );
 
 };
 
-THREE.Math2Node.prototype.generate = function( builder, output ) {
+THREE.Math2Node.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -67,6 +70,7 @@ THREE.Math2Node.prototype.generate = function( builder, output ) {
 	// optimzer
 
 	switch ( this.method ) {
+
 		case THREE.Math2Node.CROSS:
 			a = this.a.build( builder, 'v3' );
 			b = this.b.build( builder, 'v3' );
@@ -94,3 +98,21 @@ THREE.Math2Node.prototype.generate = function( builder, output ) {
 	return builder.format( this.method + '(' + a + ',' + b + ')', this.getType( builder ), output );
 
 };
+
+THREE.Math2Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.a = this.a.toJSON( meta ).uuid;
+		data.b = this.b.toJSON( meta ).uuid;
+		data.method = this.method;
+
+	}
+
+	return data;
+
+};

+ 24 - 3
examples/js/nodes/math/Math3Node.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Math3Node = function( a, b, c, method ) {
+THREE.Math3Node = function ( a, b, c, method ) {
 
 	THREE.TempNode.call( this );
 
@@ -21,8 +21,9 @@ THREE.Math3Node.FACEFORWARD = 'faceforward';
 
 THREE.Math3Node.prototype = Object.create( THREE.TempNode.prototype );
 THREE.Math3Node.prototype.constructor = THREE.Math3Node;
+THREE.Math3Node.prototype.nodeType = "Math3";
 
-THREE.Math3Node.prototype.getType = function( builder ) {
+THREE.Math3Node.prototype.getType = function ( builder ) {
 
 	var a = builder.getFormatLength( this.a.getType( builder ) );
 	var b = builder.getFormatLength( this.b.getType( builder ) );
@@ -35,7 +36,7 @@ THREE.Math3Node.prototype.getType = function( builder ) {
 
 };
 
-THREE.Math3Node.prototype.generate = function( builder, output ) {
+THREE.Math3Node.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -49,6 +50,7 @@ THREE.Math3Node.prototype.generate = function( builder, output ) {
 	// optimzer
 
 	switch ( this.method ) {
+
 		case THREE.Math3Node.REFRACT:
 			a = this.a.build( builder, type );
 			b = this.b.build( builder, type );
@@ -72,3 +74,22 @@ THREE.Math3Node.prototype.generate = function( builder, output ) {
 	return builder.format( this.method + '(' + a + ',' + b + ',' + c + ')', type, output );
 
 };
+
+THREE.Math3Node.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.a = this.a.toJSON( meta ).uuid;
+		data.b = this.b.toJSON( meta ).uuid;
+		data.c = this.c.toJSON( meta ).uuid;
+		data.method = this.method;
+
+	}
+
+	return data;
+
+};

+ 22 - 3
examples/js/nodes/math/OperatorNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.OperatorNode = function( a, b, op ) {
+THREE.OperatorNode = function ( a, b, op ) {
 
 	THREE.TempNode.call( this );
 
@@ -19,8 +19,9 @@ THREE.OperatorNode.DIV = '/';
 
 THREE.OperatorNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.OperatorNode.prototype.constructor = THREE.OperatorNode;
+THREE.OperatorNode.prototype.nodeType = "Operator";
 
-THREE.OperatorNode.prototype.getType = function( builder ) {
+THREE.OperatorNode.prototype.getType = function ( builder ) {
 
 	var a = this.a.getType( builder );
 	var b = this.b.getType( builder );
@@ -41,7 +42,7 @@ THREE.OperatorNode.prototype.getType = function( builder ) {
 
 };
 
-THREE.OperatorNode.prototype.generate = function( builder, output ) {
+THREE.OperatorNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material,
 		data = material.getDataNode( this.uuid );
@@ -54,3 +55,21 @@ THREE.OperatorNode.prototype.generate = function( builder, output ) {
 	return builder.format( '(' + a + this.op + b + ')', type, output );
 
 };
+
+THREE.OperatorNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.a = this.a.toJSON( meta ).uuid;
+		data.b = this.b.toJSON( meta ).uuid;
+		data.op = this.op;
+
+	}
+
+	return data;
+
+};

+ 44 - 2
examples/js/nodes/postprocessing/NodePass.js

@@ -2,10 +2,15 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodePass = function() {
+THREE.NodePass = function () {
 
 	THREE.ShaderPass.call( this );
 
+	this.name = "";
+	this.uuid = THREE.Math.generateUUID();
+
+	this.userData = {};
+
 	this.textureID = 'renderTexture';
 
 	this.fragment = new THREE.RawNode( new THREE.ScreenNode() );
@@ -22,7 +27,7 @@ THREE.NodePass.prototype.constructor = THREE.NodePass;
 
 THREE.NodeMaterial.addShortcuts( THREE.NodePass.prototype, 'fragment', [ 'value' ] );
 
-THREE.NodePass.prototype.build = function() {
+THREE.NodePass.prototype.build = function () {
 
 	this.node.build();
 
@@ -30,3 +35,40 @@ THREE.NodePass.prototype.build = function() {
 	this.material = this.node;
 
 };
+
+THREE.NodePass.prototype.toJSON = function ( meta ) {
+
+	var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+	if ( isRootObject ) {
+
+		meta = {
+			nodes: {}
+		};
+
+	}
+
+	if ( meta && ! meta.passes ) meta.passes = {};
+
+	if ( ! meta.passes[ this.uuid ] ) {
+
+		var data = {};
+
+		data.uuid = this.uuid;
+		data.type = "NodePass";
+
+		meta.passes[ this.uuid ] = data;
+
+		if ( this.name !== "" ) data.name = this.name;
+
+		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+		data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	meta.pass = this.uuid;
+
+	return meta;
+
+};

+ 53 - 31
examples/js/nodes/utils/BlurNode.js

@@ -2,12 +2,10 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.BlurNode = function( value, coord, radius, size ) {
+THREE.BlurNode = function ( value, coord, radius, size ) {
 
 	THREE.TempNode.call( this, 'v4' );
 
-	this.requestUpdate = true;
-
 	this.value = value;
 	this.coord = coord || new THREE.UVNode();
 	this.radius = new THREE.Vector2Node( 1, 1 );
@@ -22,41 +20,42 @@ THREE.BlurNode = function( value, coord, radius, size ) {
 };
 
 THREE.BlurNode.fBlurX = new THREE.FunctionNode( [
-"vec4 blurX( sampler2D texture, vec2 uv, float s ) {",
-"	vec4 sum = vec4( 0.0 );",
-"	sum += texture2D( texture, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;",
-"	sum += texture2D( texture, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;",
-"	sum += texture2D( texture, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;",
-"	sum += texture2D( texture, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
-"	sum += texture2D( texture, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;",
-"	sum += texture2D( texture, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;",
-"	sum += texture2D( texture, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;",
-"	sum += texture2D( texture, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;",
-"	return sum;",
-"}"
+	"vec4 blurX( sampler2D texture, vec2 uv, float s ) {",
+	"	vec4 sum = vec4( 0.0 );",
+	"	sum += texture2D( texture, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;",
+	"	sum += texture2D( texture, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;",
+	"	sum += texture2D( texture, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;",
+	"	sum += texture2D( texture, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
+	"	sum += texture2D( texture, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;",
+	"	sum += texture2D( texture, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;",
+	"	sum += texture2D( texture, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;",
+	"	sum += texture2D( texture, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;",
+	"	return sum;",
+	"}"
 ].join( "\n" ) );
 
 THREE.BlurNode.fBlurY = new THREE.FunctionNode( [
-"vec4 blurY( sampler2D texture, vec2 uv, float s ) {",
-"	vec4 sum = vec4( 0.0 );",
-"	sum += texture2D( texture, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;",
-"	sum += texture2D( texture, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;",
-"	return sum;",
-"}"
+	"vec4 blurY( sampler2D texture, vec2 uv, float s ) {",
+	"	vec4 sum = vec4( 0.0 );",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;",
+	"	sum += texture2D( texture, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;",
+	"	return sum;",
+	"}"
 ].join( "\n" ) );
 
 THREE.BlurNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.BlurNode.prototype.constructor = THREE.BlurNode;
+THREE.BlurNode.prototype.nodeType = "Blur";
 
-THREE.BlurNode.prototype.updateFrame = function( delta ) {
+THREE.BlurNode.prototype.updateFrame = function ( delta ) {
 
 	if ( this.size ) {
 
@@ -74,7 +73,7 @@ THREE.BlurNode.prototype.updateFrame = function( delta ) {
 
 };
 
-THREE.BlurNode.prototype.generate = function( builder, output ) {
+THREE.BlurNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material, blurX = THREE.BlurNode.fBlurX, blurY = THREE.BlurNode.fBlurY;
 
@@ -112,3 +111,26 @@ THREE.BlurNode.prototype.generate = function( builder, output ) {
 	}
 
 };
+
+THREE.BlurNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.coord = this.coord.toJSON( meta ).uuid;
+		data.radius = this.radius.toJSON( meta ).uuid;
+
+		if ( this.size ) data.size = { x: this.size.x, y: this.size.y };
+
+		data.blurX = this.blurX;
+		data.blurY = this.blurY;
+
+	}
+
+	return data;
+
+};

+ 29 - 10
examples/js/nodes/utils/BumpNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.BumpNode = function( value, coord, scale ) {
+THREE.BumpNode = function ( value, coord, scale ) {
 
 	THREE.TempNode.call( this, 'v3' );
 
@@ -13,20 +13,21 @@ THREE.BumpNode = function( value, coord, scale ) {
 };
 
 THREE.BumpNode.fBumpToNormal = new THREE.FunctionNode( [
-"vec3 bumpToNormal( sampler2D bumpMap, vec2 uv, vec2 scale ) {",
-"	vec2 dSTdx = dFdx( uv );",
-"	vec2 dSTdy = dFdy( uv );",
-"	float Hll = texture2D( bumpMap, uv ).x;",
-"	float dBx = texture2D( bumpMap, uv + dSTdx ).x - Hll;",
-"	float dBy = texture2D( bumpMap, uv + dSTdy ).x - Hll;",
-"	return vec3( .5 + ( dBx * scale.x ), .5 + ( dBy * scale.y ), 1.0 );",
-"}"
+	"vec3 bumpToNormal( sampler2D bumpMap, vec2 uv, vec2 scale ) {",
+	"	vec2 dSTdx = dFdx( uv );",
+	"	vec2 dSTdy = dFdy( uv );",
+	"	float Hll = texture2D( bumpMap, uv ).x;",
+	"	float dBx = texture2D( bumpMap, uv + dSTdx ).x - Hll;",
+	"	float dBy = texture2D( bumpMap, uv + dSTdy ).x - Hll;",
+	"	return vec3( .5 + ( dBx * scale.x ), .5 + ( dBy * scale.y ), 1.0 );",
+	"}"
 ].join( "\n" ), null, { derivatives: true } );
 
 THREE.BumpNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.BumpNode.prototype.constructor = THREE.BumpNode;
+THREE.BumpNode.prototype.nodeType = "Bump";
 
-THREE.BumpNode.prototype.generate = function( builder, output ) {
+THREE.BumpNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material, func = THREE.BumpNode.fBumpToNormal;
 
@@ -47,3 +48,21 @@ THREE.BumpNode.prototype.generate = function( builder, output ) {
 	}
 
 };
+
+THREE.BumpNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.coord = this.coord.toJSON( meta ).uuid;
+		data.scale = this.scale.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 21 - 2
examples/js/nodes/utils/ColorAdjustmentNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ColorAdjustmentNode = function( rgb, adjustment, method ) {
+THREE.ColorAdjustmentNode = function ( rgb, adjustment, method ) {
 
 	THREE.TempNode.call( this, 'v3' );
 
@@ -21,8 +21,9 @@ THREE.ColorAdjustmentNode.CONTRAST = 'contrast';
 
 THREE.ColorAdjustmentNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.ColorAdjustmentNode.prototype.constructor = THREE.ColorAdjustmentNode;
+THREE.ColorAdjustmentNode.prototype.nodeType = "ColorAdjustment";
 
-THREE.ColorAdjustmentNode.prototype.generate = function( builder, output ) {
+THREE.ColorAdjustmentNode.prototype.generate = function ( builder, output ) {
 
 	var rgb = this.rgb.build( builder, 'v3' );
 	var adjustment = this.adjustment.build( builder, 'fv1' );
@@ -68,3 +69,21 @@ THREE.ColorAdjustmentNode.prototype.generate = function( builder, output ) {
 	return builder.format( name + '(' + rgb + ',' + adjustment + ')', this.getType( builder ), output );
 
 };
+
+THREE.ColorAdjustmentNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.rgb = this.rgb.toJSON( meta ).uuid;
+		data.adjustment = this.adjustment.toJSON( meta ).uuid;
+		data.method = this.method;
+
+	}
+
+	return data;
+
+};

+ 37 - 4
examples/js/nodes/utils/JoinNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.JoinNode = function( x, y, z, w ) {
+THREE.JoinNode = function ( x, y, z, w ) {
 
 	THREE.TempNode.call( this, 'fv1' );
 
@@ -17,8 +17,9 @@ THREE.JoinNode.inputs = [ 'x', 'y', 'z', 'w' ];
 
 THREE.JoinNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.JoinNode.prototype.constructor = THREE.JoinNode;
+THREE.JoinNode.prototype.nodeType = "Join";
 
-THREE.JoinNode.prototype.getNumElements = function() {
+THREE.JoinNode.prototype.getNumElements = function () {
 
 	var inputs = THREE.JoinNode.inputs;
 	var i = inputs.length;
@@ -38,13 +39,13 @@ THREE.JoinNode.prototype.getNumElements = function() {
 
 };
 
-THREE.JoinNode.prototype.getType = function( builder ) {
+THREE.JoinNode.prototype.getType = function ( builder ) {
 
 	return builder.getFormatFromLength( this.getNumElements() );
 
 };
 
-THREE.JoinNode.prototype.generate = function( builder, output ) {
+THREE.JoinNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -67,3 +68,35 @@ THREE.JoinNode.prototype.generate = function( builder, output ) {
 	return builder.format( code, type, output );
 
 };
+
+THREE.JoinNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.inputs = {};
+
+		var length = this.getNumElements();
+		var inputs = THREE.JoinNode.inputs;
+
+		for ( var i = 0; i < length; i ++ ) {
+
+			var elm = this[ inputs[ i ] ];
+
+			if ( elm ) {
+
+				data.inputs[ inputs[ i ] ] = elm.toJSON( meta ).uuid;
+
+			}
+
+		}
+
+
+	}
+
+	return data;
+
+};

+ 19 - 2
examples/js/nodes/utils/LuminanceNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.LuminanceNode = function( rgb ) {
+THREE.LuminanceNode = function ( rgb ) {
 
 	THREE.TempNode.call( this, 'fv1' );
 
@@ -12,11 +12,28 @@ THREE.LuminanceNode = function( rgb ) {
 
 THREE.LuminanceNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.LuminanceNode.prototype.constructor = THREE.LuminanceNode;
+THREE.LuminanceNode.prototype.nodeType = "Luminance";
 
-THREE.LuminanceNode.prototype.generate = function( builder, output ) {
+THREE.LuminanceNode.prototype.generate = function ( builder, output ) {
 
 	builder.include( 'luminance_rgb' );
 
 	return builder.format( 'luminance_rgb(' + this.rgb.build( builder, 'v3' ) + ')', this.getType( builder ), output );
 
 };
+
+THREE.LuminanceNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.rgb = this.rgb.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 19 - 2
examples/js/nodes/utils/NoiseNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NoiseNode = function( coord ) {
+THREE.NoiseNode = function ( coord ) {
 
 	THREE.TempNode.call( this, 'fv1' );
 
@@ -12,11 +12,28 @@ THREE.NoiseNode = function( coord ) {
 
 THREE.NoiseNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.NoiseNode.prototype.constructor = THREE.NoiseNode;
+THREE.NoiseNode.prototype.nodeType = "Noise";
 
-THREE.NoiseNode.prototype.generate = function( builder, output ) {
+THREE.NoiseNode.prototype.generate = function ( builder, output ) {
 
 	builder.include( 'snoise' );
 
 	return builder.format( 'snoise(' + this.coord.build( builder, 'v2' ) + ')', this.getType( builder ), output );
 
 };
+
+THREE.NoiseNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.coord = this.coord.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 23 - 2
examples/js/nodes/utils/NormalMapNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NormalMapNode = function( value, uv, scale, normal, position ) {
+THREE.NormalMapNode = function ( value, uv, scale, normal, position ) {
 
 	THREE.TempNode.call( this, 'v3' );
 
@@ -16,8 +16,9 @@ THREE.NormalMapNode = function( value, uv, scale, normal, position ) {
 
 THREE.NormalMapNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.NormalMapNode.prototype.constructor = THREE.NormalMapNode;
+THREE.NormalMapNode.prototype.nodeType = "NormalMap";
 
-THREE.NormalMapNode.prototype.generate = function( builder, output ) {
+THREE.NormalMapNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -40,3 +41,23 @@ THREE.NormalMapNode.prototype.generate = function( builder, output ) {
 	}
 
 };
+
+THREE.NormalMapNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.uuid;
+		data.scale = this.scale.toJSON( meta ).uuid;
+
+		data.normal = this.normal.toJSON( meta ).uuid;
+		data.position = this.position.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};

+ 19 - 4
examples/js/nodes/utils/ResolutionNode.js

@@ -2,20 +2,19 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ResolutionNode = function( renderer ) {
+THREE.ResolutionNode = function ( renderer ) {
 
 	THREE.Vector2Node.call( this );
 
-	this.requestUpdate = true;
-
 	this.renderer = renderer;
 
 };
 
 THREE.ResolutionNode.prototype = Object.create( THREE.Vector2Node.prototype );
 THREE.ResolutionNode.prototype.constructor = THREE.ResolutionNode;
+THREE.ResolutionNode.prototype.nodeType = "Resolution";
 
-THREE.ResolutionNode.prototype.updateFrame = function( delta ) {
+THREE.ResolutionNode.prototype.updateFrame = function ( delta ) {
 
 	var size = this.renderer.getSize(),
 		pixelRatio = this.renderer.getPixelRatio();
@@ -24,3 +23,19 @@ THREE.ResolutionNode.prototype.updateFrame = function( delta ) {
 	this.y = size.height * pixelRatio;
 
 };
+
+THREE.ResolutionNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.renderer = this.renderer.uuid;
+
+	}
+
+	return data;
+
+};

+ 12 - 11
examples/js/nodes/utils/RoughnessToBlinnExponentNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.RoughnessToBlinnExponentNode = function() {
+THREE.RoughnessToBlinnExponentNode = function () {
 
 	THREE.TempNode.call( this, 'fv1' );
 
@@ -10,22 +10,23 @@ THREE.RoughnessToBlinnExponentNode = function() {
 
 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 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 );",
+	//	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 );",
-"}"
+	"	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
+	"}"
 ].join( "\n" ) );
 
 THREE.RoughnessToBlinnExponentNode.prototype = Object.create( THREE.TempNode.prototype );
 THREE.RoughnessToBlinnExponentNode.prototype.constructor = THREE.RoughnessToBlinnExponentNode;
+THREE.RoughnessToBlinnExponentNode.prototype.nodeType = "RoughnessToBlinnExponent";
 
-THREE.RoughnessToBlinnExponentNode.prototype.generate = function( builder, output ) {
+THREE.RoughnessToBlinnExponentNode.prototype.generate = function ( builder, output ) {
 
 	var material = builder.material;
 
@@ -40,9 +41,9 @@ THREE.RoughnessToBlinnExponentNode.prototype.generate = function( builder, outpu
 				return builder.format( 'getSpecularMIPLevel( Material_ClearCoat_BlinnShininessExponent( material ), 8 )', this.type, output );
 
 			} else {
-				
+
 				return builder.format( 'getSpecularMIPLevel( Material_BlinnShininessExponent( material ), 8 )', this.type, output );
-				
+
 			}
 
 		} else {

+ 22 - 4
examples/js/nodes/utils/SwitchNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SwitchNode = function( node, components ) {
+THREE.SwitchNode = function ( node, components ) {
 
 	THREE.GLNode.call( this );
 
@@ -13,14 +13,15 @@ THREE.SwitchNode = function( node, components ) {
 
 THREE.SwitchNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.SwitchNode.prototype.constructor = THREE.SwitchNode;
+THREE.SwitchNode.prototype.nodeType = "Switch";
 
-THREE.SwitchNode.prototype.getType = function( builder ) {
+THREE.SwitchNode.prototype.getType = function ( builder ) {
 
 	return builder.getFormatFromLength( this.components.length );
 
 };
 
-THREE.SwitchNode.prototype.generate = function( builder, output ) {
+THREE.SwitchNode.prototype.generate = function ( builder, output ) {
 
 	var type = this.node.getType( builder );
 	var inputLength = builder.getFormatLength( type ) - 1;
@@ -65,8 +66,25 @@ THREE.SwitchNode.prototype.generate = function( builder, output ) {
 
 		// join
 
-		return builder.format( node, type, output )
+		return builder.format( node, type, output );
 
 	}
 
 };
+
+THREE.SwitchNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.node = this.node.toJSON( meta ).uuid;
+		data.components = this.components;
+
+	}
+
+	return data;
+
+};

+ 19 - 4
examples/js/nodes/utils/TimerNode.js

@@ -2,21 +2,36 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TimerNode = function( value, scale ) {
+THREE.TimerNode = function ( value, scale ) {
 
 	THREE.FloatNode.call( this, value );
 
-	this.requestUpdate = true;
-
 	this.scale = scale !== undefined ? scale : 1;
 
 };
 
 THREE.TimerNode.prototype = Object.create( THREE.FloatNode.prototype );
 THREE.TimerNode.prototype.constructor = THREE.TimerNode;
+THREE.TimerNode.prototype.nodeType = "Timer";
 
-THREE.TimerNode.prototype.updateFrame = function( delta ) {
+THREE.TimerNode.prototype.updateFrame = function ( delta ) {
 
 	this.number += delta * this.scale;
 
 };
+
+THREE.TimerNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.scale = this.scale;
+
+	}
+
+	return data;
+
+};

+ 18 - 0
examples/js/nodes/utils/UVTransformNode.js

@@ -13,6 +13,7 @@ THREE.UVTransformNode = function () {
 
 THREE.UVTransformNode.prototype = Object.create( THREE.FunctionNode.prototype );
 THREE.UVTransformNode.prototype.constructor = THREE.UVTransformNode;
+THREE.UVTransformNode.prototype.nodeType = "UVTransform";
 
 THREE.UVTransformNode.prototype.generate = function ( builder, output ) {
 
@@ -46,3 +47,20 @@ THREE.UVTransformNode.prototype.compose = function () {
 	};
 
 }();
+
+THREE.UVTransformNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.uv = this.uv.toJSON( meta ).uuid;
+		data.elements = this.transform.value.elements.concat();
+
+	}
+
+	return data;
+
+};

+ 82 - 11
examples/js/nodes/utils/VelocityNode.js

@@ -6,14 +6,38 @@ THREE.VelocityNode = function ( target, params ) {
 
 	THREE.Vector3Node.call( this );
 
-	this.requestUpdate = true;
+	this.params = {};
 
-	this.target = target;
-	this.params = params || {};
-
-	this.position = this.target.position.clone();
 	this.velocity = new THREE.Vector3();
 
+	this.setTarget( target );
+	this.setParams( params );
+
+};
+
+THREE.VelocityNode.prototype = Object.create( THREE.Vector3Node.prototype );
+THREE.VelocityNode.prototype.constructor = THREE.VelocityNode;
+THREE.VelocityNode.prototype.nodeType = "Velocity";
+
+THREE.VelocityNode.prototype.setParams = function ( params ) {
+
+	switch ( this.params.type ) {
+
+		case "elastic":
+
+			delete this.moment;
+
+			delete this.speed;
+			delete this.springVelocity;
+
+			delete this.lastVelocity;
+
+			break;
+
+	}
+
+	this.params = params || {};
+
 	switch ( this.params.type ) {
 
 		case "elastic":
@@ -31,26 +55,54 @@ THREE.VelocityNode = function ( target, params ) {
 
 };
 
-THREE.VelocityNode.prototype = Object.create( THREE.Vector3Node.prototype );
-THREE.VelocityNode.prototype.constructor = THREE.VelocityNode;
+THREE.VelocityNode.prototype.setTarget = function ( target ) {
+
+	if ( this.target ) {
+
+		delete this.position;
+		delete this.oldPosition;
+
+	}
+
+	this.target = target;
+
+	if ( target ) {
+
+		this.position = target.getWorldPosition();
+		this.oldPosition = this.position.clone();
+
+	}
+
+};
+
+THREE.VelocityNode.prototype.updateFrameVelocity = function ( delta ) {
+
+	if ( this.target ) {
+
+		this.position = this.target.getWorldPosition();
+		this.velocity.subVectors( this.position, this.oldPosition );
+		this.oldPosition.copy( this.position );
+
+	}
+
+};
 
 THREE.VelocityNode.prototype.updateFrame = function ( delta ) {
 
-	this.velocity.subVectors( this.target.position, this.position );
-	this.position.copy( this.target.position );
+	this.updateFrameVelocity( delta );
 
 	switch ( this.params.type ) {
 
 		case "elastic":
 
 			// convert to real scale: 0 at 1 values
-			var deltaFps = delta * (this.params.fps || 60);
+			var deltaFps = delta * ( this.params.fps || 60 );
 
 			var spring = Math.pow( this.params.spring, deltaFps ),
 				damping = Math.pow( this.params.damping, deltaFps );
 
 			// fix relative frame-rate
-			this.velocity.multiplyScalar( Math.exp( -this.params.damping * deltaFps ) );
+			this.velocity.multiplyScalar( Math.exp( - this.params.damping * deltaFps ) );
 
 			// elastic
 			this.velocity.add( this.springVelocity );
@@ -81,3 +133,22 @@ THREE.VelocityNode.prototype.updateFrame = function ( delta ) {
 	}
 
 };
+
+THREE.VelocityNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		if ( this.target ) data.target = this.target.uuid;
+
+		// clone params
+		data.params = JSON.parse( JSON.stringify( this.params ) );
+
+	}
+
+	return data;
+
+};