Ver código fonte

Merge pull request #14333 from sunag/dev-nodematerial-r7

NodeMaterial - r7
Mr.doob 7 anos atrás
pai
commit
12d309160c
100 arquivos alterados com 5913 adições e 3904 exclusões
  1. 74 405
      examples/js/loaders/NodeMaterialLoader.js
  2. 0 55
      examples/js/nodes/AttributeNode.js
  3. 0 110
      examples/js/nodes/ConstNode.js
  4. 0 92
      examples/js/nodes/FunctionCallNode.js
  5. 0 158
      examples/js/nodes/GLNode.js
  6. 0 65
      examples/js/nodes/InputNode.js
  7. 0 259
      examples/js/nodes/NodeBuilder.js
  8. 0 34
      examples/js/nodes/NodeFrame.js
  9. 0 216
      examples/js/nodes/NodeLib.js
  10. 0 661
      examples/js/nodes/NodeMaterial.js
  11. 106 0
      examples/js/nodes/Nodes.js
  12. 0 53
      examples/js/nodes/RawNode.js
  13. 205 0
      examples/js/nodes/THREE.Nodes.js
  14. 0 134
      examples/js/nodes/TempNode.js
  15. 0 43
      examples/js/nodes/VarNode.js
  16. 97 50
      examples/js/nodes/accessors/CameraNode.js
  17. 25 16
      examples/js/nodes/accessors/ColorsNode.js
  18. 21 9
      examples/js/nodes/accessors/LightNode.js
  19. 53 24
      examples/js/nodes/accessors/NormalNode.js
  20. 60 32
      examples/js/nodes/accessors/PositionNode.js
  21. 46 31
      examples/js/nodes/accessors/ReflectNode.js
  22. 53 0
      examples/js/nodes/accessors/ResolutionNode.js
  23. 21 9
      examples/js/nodes/accessors/ScreenUVNode.js
  24. 37 16
      examples/js/nodes/accessors/UVNode.js
  25. 50 0
      examples/js/nodes/bsdfs/BlinnExponentToRoughnessNode.js
  26. 31 0
      examples/js/nodes/bsdfs/BlinnShininessExponentNode.js
  27. 91 0
      examples/js/nodes/bsdfs/RoughnessToBlinnExponentNode.js
  28. 70 0
      examples/js/nodes/core/AttributeNode.js
  29. 125 0
      examples/js/nodes/core/ConstNode.js
  30. 108 0
      examples/js/nodes/core/FunctionCallNode.js
  31. 56 34
      examples/js/nodes/core/FunctionNode.js
  32. 176 0
      examples/js/nodes/core/GLNode.js
  33. 85 0
      examples/js/nodes/core/InputNode.js
  34. 1007 0
      examples/js/nodes/core/NodeBuilder.js
  35. 42 0
      examples/js/nodes/core/NodeFrame.js
  36. 68 0
      examples/js/nodes/core/NodeLib.js
  37. 9 2
      examples/js/nodes/core/NodeUniform.js
  38. 75 0
      examples/js/nodes/core/NodeUtils.js
  39. 107 0
      examples/js/nodes/core/StructNode.js
  40. 133 0
      examples/js/nodes/core/TempNode.js
  41. 66 0
      examples/js/nodes/core/VarNode.js
  42. 168 0
      examples/js/nodes/effects/BlurNode.js
  43. 136 0
      examples/js/nodes/effects/ColorAdjustmentNode.js
  44. 73 0
      examples/js/nodes/effects/LuminanceNode.js
  45. 22 9
      examples/js/nodes/inputs/ColorNode.js
  46. 33 28
      examples/js/nodes/inputs/CubeTextureNode.js
  47. 19 9
      examples/js/nodes/inputs/FloatNode.js
  48. 19 7
      examples/js/nodes/inputs/IntNode.js
  49. 40 9
      examples/js/nodes/inputs/Matrix3Node.js
  50. 39 9
      examples/js/nodes/inputs/Matrix4Node.js
  51. 57 0
      examples/js/nodes/inputs/PropertyNode.js
  52. 37 19
      examples/js/nodes/inputs/ReflectorNode.js
  53. 13 8
      examples/js/nodes/inputs/ScreenNode.js
  54. 36 29
      examples/js/nodes/inputs/TextureNode.js
  55. 22 9
      examples/js/nodes/inputs/Vector2Node.js
  56. 22 10
      examples/js/nodes/inputs/Vector3Node.js
  57. 22 9
      examples/js/nodes/inputs/Vector4Node.js
  58. 34 0
      examples/js/nodes/materials/MeshStandardNodeMaterial.js
  59. 189 0
      examples/js/nodes/materials/NodeMaterial.js
  60. 26 7
      examples/js/nodes/materials/PhongNodeMaterial.js
  61. 17 7
      examples/js/nodes/materials/SpriteNodeMaterial.js
  62. 28 7
      examples/js/nodes/materials/StandardNodeMaterial.js
  63. 109 0
      examples/js/nodes/materials/nodes/MeshStandardNode.js
  64. 76 37
      examples/js/nodes/materials/nodes/PhongNode.js
  65. 62 0
      examples/js/nodes/materials/nodes/RawNode.js
  66. 41 17
      examples/js/nodes/materials/nodes/SpriteNode.js
  67. 99 64
      examples/js/nodes/materials/nodes/StandardNode.js
  68. 64 47
      examples/js/nodes/math/Math1Node.js
  69. 62 40
      examples/js/nodes/math/Math2Node.js
  70. 59 34
      examples/js/nodes/math/Math3Node.js
  71. 35 23
      examples/js/nodes/math/OperatorNode.js
  72. 166 0
      examples/js/nodes/misc/BumpMapNode.js
  73. 117 0
      examples/js/nodes/misc/NormalMapNode.js
  74. 64 0
      examples/js/nodes/misc/TextureCubeNode.js
  75. 209 0
      examples/js/nodes/misc/TextureCubeUVNode.js
  76. 21 8
      examples/js/nodes/postprocessing/NodePass.js
  77. 69 0
      examples/js/nodes/procedural/NoiseNode.js
  78. 0 136
      examples/js/nodes/utils/BlurNode.js
  79. 0 68
      examples/js/nodes/utils/BumpNode.js
  80. 85 0
      examples/js/nodes/utils/BypassNode.js
  81. 0 89
      examples/js/nodes/utils/ColorAdjustmentNode.js
  82. 35 23
      examples/js/nodes/utils/JoinNode.js
  83. 0 39
      examples/js/nodes/utils/LuminanceNode.js
  84. 61 0
      examples/js/nodes/utils/MaxMIPLevelNode.js
  85. 0 39
      examples/js/nodes/utils/NoiseNode.js
  86. 0 63
      examples/js/nodes/utils/NormalMapNode.js
  87. 0 41
      examples/js/nodes/utils/ResolutionNode.js
  88. 0 65
      examples/js/nodes/utils/RoughnessToBlinnExponentNode.js
  89. 27 15
      examples/js/nodes/utils/SwitchNode.js
  90. 41 18
      examples/js/nodes/utils/TimerNode.js
  91. 26 11
      examples/js/nodes/utils/UVTransformNode.js
  92. 25 11
      examples/js/nodes/utils/VelocityNode.js
  93. 0 0
      examples/nodes/caustic.json
  94. 0 0
      examples/nodes/displace.json
  95. 0 0
      examples/nodes/wave.json
  96. 0 0
      examples/nodes/xray.json
  97. 4 69
      examples/webgl_loader_nodes.html
  98. 3 62
      examples/webgl_materials_compile.html
  99. 195 134
      examples/webgl_materials_nodes.html
  100. 9 67
      examples/webgl_mirror_nodes.html

+ 74 - 405
examples/js/loaders/NodeMaterialLoader.js

@@ -91,7 +91,11 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 	getObjectById: function ( uuid ) {
 
-		return this.library[ uuid ] || this.nodes[ uuid ] || this.names[ uuid ];
+		return this.library[ uuid ] || 
+			this.nodes[ uuid ] || 
+			this.materials[ uuid ] ||
+			this.passes[ uuid ] || 
+			this.names[ uuid ];
 
 	},
 
@@ -109,15 +113,62 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 	},
 
-	parse: function ( json ) {
-
-		var uuid, node, object, prop, i;
+	resolve: function( json ) {
+		
+		switch( typeof json ) {
+			
+			case "boolean":
+			case "number":
+			
+				return json;
+			
+			case "string":
+			
+				if (/^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/i.test(json) || this.library[ json ]) {
+					
+					return this.getNode( json );
+					
+				}
+				
+				return json;
+
+			default:
+			
+				if ( Array.isArray( json ) ) {
+			
+					for(var i = 0; i < json.length; i++) {
+						
+						json[i] = this.resolve( json[i] );
+						
+					}
+					
+				} else {
+					
+					for ( var prop in json ) {
+						
+						if (prop === "uuid") continue;
+						
+						json[ prop ] = this.resolve( json[ prop ] );
+						
+					}
+					
+				}
+				
+		}
+		
+		return json;
+		
+	},
+	
+	declare: function( json ) {
+		
+		var uuid, node, object;
 
 		for ( uuid in json.nodes ) {
 
 			node = json.nodes[ uuid ];
 
-			object = new THREE[ node.type ]();
+			object = new THREE[ node.nodeType + "Node" ]();
 
 			if ( node.name ) {
 
@@ -125,15 +176,8 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 				this.names[ object.name ] = object;
 
-			} else {
-
-				// ignore "uniform" shader input ( for optimization )
-				object.readonly = true;
-
 			}
 
-			if ( node.readonly !== undefined ) object.readonly = node.readonly;
-
 			this.nodes[ uuid ] = object;
 
 		}
@@ -174,410 +218,35 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 		}
 
-		if ( json.material ) this.material = this.materials[ uuid ];
-		if ( json.pass ) this.pass = this.passes[ uuid ];
+		if ( json.material ) this.material = this.materials[ json.material ];
+		
+		if ( json.pass ) this.pass = this.passes[ json.pass ];
+		
+		return json;
+		
+	},
+	
+	parse: function ( json ) {
 
+		var uuid;
+	
+		json = this.resolve( this.declare( json ) );
+		
 		for ( uuid in json.nodes ) {
 
-			node = json.nodes[ uuid ];
-			object = this.nodes[ uuid ];
-
-			switch ( node.type ) {
-
-				case "IntNode":
-				case "FloatNode":
-
-					object.value = node.value;
-
-					break;
-
-				case "ColorNode":
-
-					object.value.copy( node );
-
-					break;
-
-				case "Vector2Node":
-
-					object.x = node.x;
-					object.y = node.y;
-
-					break;
-
-
-				case "Vector3Node":
-
-					object.x = node.x;
-					object.y = node.y;
-					object.z = node.z;
-
-					break;
-
-				case "Vector4Node":
-
-					object.x = node.x;
-					object.y = node.y;
-					object.z = node.z;
-					object.w = node.w;
-
-					break;
-
-				case "Matrix3Node":
-				case "Matrix4Node":
-
-					object.value.fromArray( node.elements );
-
-					break;
-
-				case "OperatorNode":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.op = node.op;
-
-					break;
-
-				case "Math1Node":
-
-					object.a = this.getNode( node.a );
-					object.method = node.method;
-
-					break;
-
-				case "Math2Node":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.method = node.method;
-
-					break;
-
-				case "Math3Node":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.c = this.getNode( node.c );
-					object.method = node.method;
-
-					break;
-
-				case "UVNode":
-				case "ColorsNode":
-
-					object.index = node.index;
-
-					break;
-
-
-				case "LuminanceNode":
-
-					object.rgb = this.getNode( node.rgb );
-
-					break;
-
-				case "PositionNode":
-				case "NormalNode":
-				case "ReflectNode":
-				case "LightNode":
-
-					object.scope = node.scope;
-
-					break;
-
-				case "SwitchNode":
-
-					object.node = this.getNode( node.node );
-					object.components = node.components;
-
-					break;
-
-				case "JoinNode":
-
-					for ( prop in node.inputs ) {
-
-						object[ prop ] = this.getNode( node.inputs[ prop ] );
-
-					}
-
-					break;
-
-				case "CameraNode":
-
-					object.setScope( node.scope );
-
-					if ( node.camera ) object.setCamera( this.getNode( node.camera ) );
-
-					switch ( node.scope ) {
-
-						case THREE.CameraNode.DEPTH:
-
-							object.near.number = node.near;
-							object.far.number = node.far;
-
-							break;
-
-					}
-
-					break;
-
-				case "ColorAdjustmentNode":
-
-					object.rgb = this.getNode( node.rgb );
-					object.adjustment = this.getNode( node.adjustment );
-					object.method = node.method;
-
-					break;
-
-				case "UVTransformNode":
-
-					object.uv = this.getNode( node.uv );
-					object.transform = this.getNode( node.transform );
-
-					break;
-
-				case "BumpNode":
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.scale = this.getNode( node.scale );
-
-					break;
-
-				case "BlurNode":
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.scale = this.getNode( node.scale );
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.radius = this.getNode( node.radius );
-
-					if ( node.size !== undefined ) object.size = new THREE.Vector2( node.size.x, node.size.y );
-
-					object.blurX = node.blurX;
-					object.blurY = node.blurY;
-
-					break;
-
-				case "ResolutionNode":
-
-					object.renderer = this.getNode( node.renderer );
-
-					break;
-
-				case "ScreenUVNode":
-
-					object.resolution = this.getNode( node.resolution );
-
-					break;
-
-				case "VelocityNode":
-
-					if ( node.target ) object.setTarget( this.getNode( node.target ) );
-					object.setParams( node.params );
-
-					break;
-
-				case "TimerNode":
-
-					object.scope = node.scope;
-					object.scale = node.scale;
-
-					break;
-
-				case "ConstNode":
-
-					object.name = node.name;
-					object.type = node.out;
-					object.value = node.value;
-					object.useDefine = node.useDefine === true;
-
-					break;
-
-				case "AttributeNode":
-				case "VarNode":
-
-					object.type = node.out;
-
-					break;
-
-
-				case "ReflectorNode":
-
-					object.setMirror( this.getNode( node.mirror ) );
-
-					if ( node.offset ) object.offset = this.getNode( node.offset );
-
-					break;
-
-				case "NoiseNode":
-
-					object.coord = this.getNode( node.coord );
-
-					break;
-
-				case "FunctionNode":
-
-					object.isMethod = node.isMethod;
-					object.useKeywords = node.useKeywords;
-
-					object.extensions = node.extensions;
-					object.keywords = {};
-
-					for ( prop in node.keywords ) {
-
-						object.keywords[ prop ] = this.getNode( node.keywords[ prop ] );
-
-					}
-
-					if ( node.includes ) {
-
-						for ( i = 0; i < node.includes.length; i ++ ) {
-
-							object.includes.push( this.getNode( node.includes[ i ] ) );
-
-						}
-
-					}
-
-					object.eval( node.src, object.includes, object.extensions, object.keywords );
-
-					if ( ! object.isMethod ) object.type = node.out;
-
-					break;
-
-				case "FunctionCallNode":
-
-					for ( prop in node.inputs ) {
-
-						object.inputs[ prop ] = this.getNode( node.inputs[ prop ] );
-
-					}
-
-					object.value = this.getNode( node.value );
-
-					break;
-
-				case "TextureNode":
-				case "CubeTextureNode":
-				case "ScreenNode":
-
-					if ( node.value ) object.value = this.getNode( node.value );
-
-					object.coord = this.getNode( node.coord );
-
-					if ( node.bias ) object.bias = this.getNode( node.bias );
-					if ( object.project !== undefined ) object.project = node.project;
-
-					break;
-
-				case "RoughnessToBlinnExponentNode":
-					break;
-
-				case "RawNode":
-
-					object.value = this.getNode( node.value );
-
-					break;
-
-				case "StandardNode":
-				case "PhongNode":
-				case "SpriteNode":
-
-					object.color = this.getNode( node.color );
-
-					if ( node.alpha ) object.alpha = this.getNode( node.alpha );
-
-					if ( node.specular ) object.specular = this.getNode( node.specular );
-					if ( node.shininess ) object.shininess = this.getNode( node.shininess );
-
-					if ( node.roughness ) object.roughness = this.getNode( node.roughness );
-					if ( node.metalness ) object.metalness = this.getNode( node.metalness );
-
-					if ( node.reflectivity ) object.reflectivity = this.getNode( node.reflectivity );
-
-					if ( node.clearCoat ) object.clearCoat = this.getNode( node.clearCoat );
-					if ( node.clearCoatRoughness ) object.clearCoatRoughness = this.getNode( node.clearCoatRoughness );
-
-					if ( node.normal ) object.normal = this.getNode( node.normal );
-					if ( node.normalScale ) object.normalScale = this.getNode( node.normalScale );
-
-					if ( node.emissive ) object.emissive = this.getNode( node.emissive );
-					if ( node.ambient ) object.ambient = this.getNode( node.ambient );
-
-					if ( node.shadow ) object.shadow = this.getNode( node.shadow );
-					if ( node.light ) object.light = this.getNode( node.light );
-
-					if ( node.ao ) object.ao = this.getNode( node.ao );
-
-					if ( node.environment ) object.environment = this.getNode( node.environment );
-					if ( node.environmentAlpha ) object.environmentAlpha = this.getNode( node.environmentAlpha );
-
-					if ( node.transform ) object.transform = this.getNode( node.transform );
-
-					if ( node.spherical === false ) object.spherical = false;
-
-					break;
-
-				default:
-
-					console.warn( node.type, "not supported." );
-
-			}
+			this.nodes[ uuid ].copy( json.nodes[ uuid ] );
 
 		}
-
+		
 		for ( uuid in json.materials ) {
 
-			node = json.materials[ uuid ];
-			object = this.materials[ uuid ];
-
-			if ( node.name !== undefined ) object.name = node.name;
-
-			if ( node.blending !== undefined ) object.blending = node.blending;
-			if ( node.flatShading !== undefined ) object.flatShading = node.flatShading;
-			if ( node.side !== undefined ) object.side = node.side;
-
-			object.depthFunc = node.depthFunc;
-			object.depthTest = node.depthTest;
-			object.depthWrite = node.depthWrite;
-
-			if ( node.wireframe !== undefined ) object.wireframe = node.wireframe;
-			if ( node.wireframeLinewidth !== undefined ) object.wireframeLinewidth = node.wireframeLinewidth;
-			if ( node.wireframeLinecap !== undefined ) object.wireframeLinecap = node.wireframeLinecap;
-			if ( node.wireframeLinejoin !== undefined ) object.wireframeLinejoin = node.wireframeLinejoin;
-
-			if ( node.skinning !== undefined ) object.skinning = node.skinning;
-			if ( node.morphTargets !== undefined ) object.morphTargets = node.morphTargets;
-
-			if ( node.visible !== undefined ) object.visible = node.visible;
-			if ( node.userData !== undefined ) object.userData = node.userData;
-
-			object.vertex = this.getNode( node.vertex );
-			object.fragment = this.getNode( node.fragment );
-
-			if ( object.vertex === object.fragment ) {
-
-				// replace main node
-
-				object.node = object.vertex;
-
-			}
-
-			if ( node.fog !== undefined ) object.fog = node.fog;
-			if ( node.lights !== undefined ) object.lights = node.lights;
-
-			if ( node.transparent !== undefined ) object.transparent = node.transparent;
+			this.materials[ uuid ].copy( json.materials[ uuid ] );
 
 		}
-
+		
 		for ( uuid in json.passes ) {
 
-			node = json.passes[ uuid ];
-			object = this.passes[ uuid ];
-
-			object.value = this.getNode( node.value );
+			this.passes[ uuid ].copy( json.passes[ uuid ] );
 
 		}
 

+ 0 - 55
examples/js/nodes/AttributeNode.js

@@ -1,55 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.AttributeNode = function ( name, type ) {
-
-	THREE.GLNode.call( this, type );
-
-	this.name = name;
-
-};
-
-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 ) {
-
-	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
-
-};
-
-THREE.AttributeNode.prototype.getType = function ( builder ) {
-
-	var type = this.getAttributeType( builder );
-
-	return builder.getTypeByFormat( type );
-
-};
-
-THREE.AttributeNode.prototype.generate = function ( builder, output ) {
-
-	var type = this.getAttributeType( builder );
-
-	var attribute = builder.material.getAttribute( this.name, type );
-
-	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;
-
-};

+ 0 - 110
examples/js/nodes/ConstNode.js

@@ -1,110 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.ConstNode = function ( src, useDefine ) {
-
-	THREE.TempNode.call( this );
-
-	this.eval( src || THREE.ConstNode.PI, useDefine );
-
-};
-
-THREE.ConstNode.PI = 'PI';
-THREE.ConstNode.PI2 = 'PI2';
-THREE.ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
-THREE.ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
-THREE.ConstNode.LOG2 = 'LOG2';
-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 ) {
-
-	return builder.getTypeByFormat( this.type );
-
-};
-
-THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
-
-	src = ( src || '' ).trim();
-
-	var name, type, value = "";
-
-	var rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
-	var match = src.match( rDeclaration );
-
-	this.useDefine = useDefine;
-
-	if ( match && match.length > 1 ) {
-
-		type = match[ 1 ];
-		name = match[ 2 ];
-		value = match[ 3 ];
-
-	} else {
-
-		name = src;
-		type = 'fv1';
-
-	}
-
-	this.name = name;
-	this.type = type;
-	this.value = value;
-
-};
-
-THREE.ConstNode.prototype.build = function ( builder, output ) {
-
-	if ( output === 'source' ) {
-
-		if ( this.value ) {
-
-			if ( this.useDefine ) {
-
-				return '#define ' + this.name + ' ' + this.value;
-
-			}
-
-			return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
-
-		}
-
-	} else {
-
-		builder.include( this );
-
-		return builder.format( this.name, this.getType( 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;
-
-};

+ 0 - 92
examples/js/nodes/FunctionCallNode.js

@@ -1,92 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.FunctionCallNode = function ( func, inputs ) {
-
-	THREE.TempNode.call( this );
-
-	this.setFunction( 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 ) {
-
-	this.value = func;
-	this.inputs = inputs || [];
-
-};
-
-THREE.FunctionCallNode.prototype.getFunction = function () {
-
-	return this.value;
-
-};
-
-THREE.FunctionCallNode.prototype.getType = function ( builder ) {
-
-	return this.value.getType( builder );
-
-};
-
-THREE.FunctionCallNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getType( builder );
-	var func = this.value;
-
-	var code = func.build( builder, output ) + '(';
-	var params = [];
-
-	for ( var i = 0; i < func.inputs.length; i ++ ) {
-
-		var inpt = func.inputs[ i ];
-		var param = this.inputs[ i ] || this.inputs[ inpt.name ];
-
-		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
-
-	}
-
-	code += params.join( ',' ) + ')';
-
-	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;
-
-};

+ 0 - 158
examples/js/nodes/GLNode.js

@@ -1,158 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.GLNode = function ( type ) {
-
-	this.uuid = THREE.Math.generateUUID();
-
-	this.name = "";
-	this.allows = {};
-
-	this.type = type;
-
-	this.userData = {};
-
-};
-
-THREE.GLNode.prototype.isNode = true;
-
-THREE.GLNode.prototype.parse = function ( builder, context ) {
-
-	context = context || {};
-
-	builder.parsing = true;
-
-	var material = builder.material;
-
-	this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), 'v4' );
-
-	material.clearVertexNode();
-	material.clearFragmentNode();
-
-	builder.removeCache().removeSlot();
-
-	builder.parsing = false;
-
-};
-
-THREE.GLNode.prototype.parseAndBuildCode = function ( builder, output, context ) {
-
-	context = context || {};
-
-	this.parse( builder, context );
-
-	return this.buildCode( 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 ) };
-
-	if ( builder.isShader( 'vertex' ) ) data.code = material.clearVertexNode();
-	else data.code = material.clearFragmentNode();
-
-	builder.removeCache().removeSlot();
-
-	return data;
-
-};
-
-THREE.GLNode.prototype.build = function ( builder, output, uuid ) {
-
-	output = output || this.getType( builder, output );
-
-	var material = builder.material, data = material.getDataNode( uuid || this.uuid );
-
-	if ( builder.parsing ) this.appendDepsNode( builder, data, output );
-
-	if ( this.allows[ builder.shader ] === false ) {
-
-		throw new Error( 'Shader ' + shader + ' is not compatible with this node.' );
-
-	}
-
-	if ( material.nodes.indexOf( this ) === - 1 ) {
-
-		material.nodes.push( this );
-
-	}
-
-	if ( this.updateFrame !== undefined && material.updaters.indexOf( this ) === - 1 ) {
-
-		material.updaters.push( this );
-
-	}
-
-	return this.generate( builder, output, uuid );
-
-};
-
-THREE.GLNode.prototype.appendDepsNode = function ( builder, data, output ) {
-
-	data.deps = ( data.deps || 0 ) + 1;
-
-	var outputLen = builder.getFormatLength( output );
-
-	if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
-
-		data.outputMax = outputLen;
-		data.output = 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 );
-
-};

+ 0 - 65
examples/js/nodes/InputNode.js

@@ -1,65 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.InputNode = function ( type, params ) {
-
-	params = params || {};
-	params.shared = params.shared !== undefined ? params.shared : false;
-
-	THREE.TempNode.call( this, type, params );
-
-	this.readonly = false;
-
-};
-
-THREE.InputNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.InputNode.prototype.constructor = THREE.InputNode;
-
-THREE.InputNode.prototype.isReadonly = function ( builder ) {
-
-	return this.readonly;
-
-};
-
-THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
-
-	var material = builder.material;
-
-	uuid = builder.getUuid( uuid || this.getUuid() );
-	type = type || this.getType( builder );
-
-	var data = material.getDataNode( uuid ),
-		readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
-
-	if ( readonly ) {
-
-		return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
-
-	} else {
-
-		if ( builder.isShader( 'vertex' ) ) {
-
-			if ( ! data.vertex ) {
-
-				data.vertex = material.createVertexUniform( type, this, ns, needsUpdate );
-
-			}
-
-			return builder.format( data.vertex.name, type, output );
-
-		} else {
-
-			if ( ! data.fragment ) {
-
-				data.fragment = material.createFragmentUniform( type, this, ns, needsUpdate );
-
-			}
-
-			return builder.format( data.fragment.name, type, output );
-
-		}
-
-	}
-
-};

+ 0 - 259
examples/js/nodes/NodeBuilder.js

@@ -1,259 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeBuilder = function ( material, renderer ) {
-
-	this.material = material;
-	this.renderer = renderer;
-
-	this.caches = [];
-	this.slots = [];
-
-	this.keywords = {};
-
-	this.parsing = false;
-	this.optimize = true;
-
-	this.update();
-
-};
-
-THREE.NodeBuilder.type = {
-	float: 'fv1',
-	vec2: 'v2',
-	vec3: 'v3',
-	vec4: 'v4',
-	mat4: 'v4',
-	int: 'iv1'
-};
-
-THREE.NodeBuilder.constructors = [
-	'float',
-	'vec2',
-	'vec3',
-	'vec4'
-];
-
-THREE.NodeBuilder.elements = [
-	'x',
-	'y',
-	'z',
-	'w'
-];
-
-THREE.NodeBuilder.prototype = {
-
-	constructor: THREE.NodeBuilder,
-
-	addCache: function ( name, requires ) {
-
-		this.caches.push( {
-			name: name || '',
-			requires: requires || {}
-		} );
-
-		return this.update();
-
-	},
-
-	removeCache: function () {
-
-		this.caches.pop();
-
-		return this.update();
-
-	},
-
-	addSlot: function ( name ) {
-
-		this.slots.push( {
-			name: name || ''
-		} );
-
-		return this.update();
-
-	},
-
-	removeSlot: function () {
-
-		this.slots.pop();
-
-		return this.update();
-
-	},
-
-	isCache: function ( name ) {
-
-		var i = this.caches.length;
-
-		while ( i -- ) {
-
-			if ( this.caches[ i ].name == name ) return true;
-
-		}
-
-		return false;
-
-	},
-
-	isSlot: function ( name ) {
-
-		var i = this.slots.length;
-
-		while ( i -- ) {
-
-			if ( this.slots[ i ].name == name ) return true;
-
-		}
-
-		return false;
-
-	},
-
-	update: function () {
-
-		var cache = this.caches[ this.caches.length - 1 ];
-		var slot = this.slots[ this.slots.length - 1 ];
-
-		this.slot = slot ? slot.name : '';
-		this.cache = cache ? cache.name : '';
-		this.requires = cache ? cache.requires : {};
-
-		return this;
-
-	},
-
-	require: function ( name, node ) {
-
-		this.requires[ name ] = node;
-
-		return this;
-
-	},
-
-	include: function ( node, parent, source ) {
-
-		this.material.include( this, node, parent, source );
-
-		return this;
-
-	},
-
-	colorToVector: function ( color ) {
-
-		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
-
-	},
-
-	getConstructorFromLength: function ( len ) {
-
-		return THREE.NodeBuilder.constructors[ len - 1 ];
-
-	},
-
-	getFormatName: function ( format ) {
-
-		return format.replace( /c/g, 'v3' ).replace( /fv1/g, 'v1' ).replace( /iv1/g, 'i' );
-
-	},
-
-	isFormatMatrix: function ( format ) {
-
-		return /^m/.test( format );
-
-	},
-
-	getFormatLength: function ( format ) {
-
-		return parseInt( this.getFormatName( format ).substr( 1 ) );
-
-	},
-
-	getFormatFromLength: function ( len ) {
-
-		if ( len == 1 ) return 'fv1';
-
-		return 'v' + len;
-
-	},
-
-	format: function ( code, from, to ) {
-
-		var format = this.getFormatName( to + '=' + from );
-
-		switch ( format ) {
-
-			case 'v1=v2': return code + '.x';
-			case 'v1=v3': return code + '.x';
-			case 'v1=v4': return code + '.x';
-			case 'v1=i': return 'float(' + code + ')';
-
-			case 'v2=v1': return 'vec2(' + code + ')';
-			case 'v2=v3': return code + '.xy';
-			case 'v2=v4': return code + '.xy';
-			case 'v2=i': return 'vec2(float(' + code + '))';
-
-			case 'v3=v1': return 'vec3(' + code + ')';
-			case 'v3=v2': return 'vec3(' + code + ',0.0)';
-			case 'v3=v4': return code + '.xyz';
-			case 'v3=i': return 'vec2(float(' + code + '))';
-
-			case 'v4=v1': return 'vec4(' + code + ')';
-			case 'v4=v2': return 'vec4(' + code + ',0.0,1.0)';
-			case 'v4=v3': return 'vec4(' + code + ',1.0)';
-			case 'v4=i': return 'vec4(float(' + code + '))';
-
-			case 'i=v1': return 'int(' + code + ')';
-			case 'i=v2': return 'int(' + code + '.x)';
-			case 'i=v3': return 'int(' + code + '.x)';
-			case 'i=v4': return 'int(' + code + '.x)';
-
-		}
-
-		return code;
-
-	},
-
-	getTypeByFormat: function ( format ) {
-
-		return THREE.NodeBuilder.type[ format ] || format;
-
-	},
-
-	getUuid: function ( uuid, useCache ) {
-
-		useCache = useCache !== undefined ? useCache : true;
-
-		if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
-
-		return uuid;
-
-	},
-
-	getElementByIndex: function ( index ) {
-
-		return THREE.NodeBuilder.elements[ index ];
-
-	},
-
-	getIndexByElement: function ( elm ) {
-
-		return THREE.NodeBuilder.elements.indexOf( elm );
-
-	},
-
-	isShader: function ( shader ) {
-
-		return this.shader == shader;
-
-	},
-
-	setShader: function ( shader ) {
-
-		this.shader = shader;
-
-		return this;
-
-	}
-};

+ 0 - 34
examples/js/nodes/NodeFrame.js

@@ -1,34 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeFrame = function ( time ) {
-
-	this.time = time !== undefined ? time : 0;
-
-	this.frameId = 0;
-
-};
-
-THREE.NodeFrame.prototype.update = function ( delta ) {
-
-	++this.frameId;
-
-	this.time += delta;
-	this.delta = delta;
-
-	return this;
-
-};
-
-THREE.NodeFrame.prototype.updateNode = function ( node ) {
-
-	if ( node.frameId === this.frameId ) return this;
-
-	node.updateFrame( this );
-
-	node.frameId = this.frameId;
-
-	return this;
-
-};

+ 0 - 216
examples/js/nodes/NodeLib.js

@@ -1,216 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeLib = {
-
-	nodes: {},
-	keywords: {},
-
-	add: function ( node ) {
-
-		this.nodes[ node.name ] = node;
-
-	},
-
-	addKeyword: function ( name, callback, cache ) {
-
-		cache = cache !== undefined ? cache : true;
-
-		this.keywords[ name ] = { callback: callback, cache: cache };
-
-	},
-
-	remove: function ( node ) {
-
-		delete this.nodes[ node.name ];
-
-	},
-
-	removeKeyword: function ( name ) {
-
-		delete this.keywords[ name ];
-
-	},
-
-	get: function ( name ) {
-
-		return this.nodes[ name ];
-
-	},
-
-	getKeyword: function ( name, material ) {
-
-		return this.keywords[ name ].callback.call( this, material );
-
-	},
-
-	getKeywordData: function ( name ) {
-
-		return this.keywords[ name ];
-
-	},
-
-	contains: function ( name ) {
-
-		return this.nodes[ name ] != undefined;
-
-	},
-
-	containsKeyword: function ( name ) {
-
-		return this.keywords[ name ] != undefined;
-
-	}
-
-};
-
-//
-//	Keywords
-//
-
-THREE.NodeLib.addKeyword( 'uv', function () {
-
-	return new THREE.UVNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'uv2', function () {
-
-	return new THREE.UVNode( 1 );
-
-} );
-
-THREE.NodeLib.addKeyword( 'position', function () {
-
-	return new THREE.PositionNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'worldPosition', function () {
-
-	return new THREE.PositionNode( THREE.PositionNode.WORLD );
-
-} );
-
-THREE.NodeLib.addKeyword( 'normal', function () {
-
-	return new THREE.NormalNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'worldNormal', function () {
-
-	return new THREE.NormalNode( THREE.NormalNode.WORLD );
-
-} );
-
-THREE.NodeLib.addKeyword( 'viewPosition', function () {
-
-	return new THREE.PositionNode( THREE.NormalNode.VIEW );
-
-} );
-
-THREE.NodeLib.addKeyword( 'viewNormal', function () {
-
-	return new THREE.NormalNode( THREE.NormalNode.VIEW );
-
-} );
-
-THREE.NodeLib.addKeyword( 'time', function () {
-
-	return new THREE.TimerNode();
-
-} );
-
-//
-//	Luma
-//
-
-THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA vec3(0.2125, 0.7154, 0.0721)" ) );
-
-//
-//	NormalMap
-//
-
-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 );",
-	"	float factor = sign( st1.t * st0.s - st0.t * st1.s );",
-	"	factor *= float( gl_FrontFacing ) * 2.0 - 1.0;",
-	"	vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * factor );",
-	"	vec3 T = normalize( ( -q0 * st1.s + q1 * st0.s ) * factor );",
-	"	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 } ) );
-
-//
-//	Noise
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-	"float snoise(vec2 co) {",
-	"	return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Hue
-//
-
-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));",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Saturation
-//
-
-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);",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Luminance
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-// Algorithm from Chapter 10 of Graphics Shaders
-	"float luminance_rgb(vec3 rgb) {",
-	"	return dot(rgb, LUMA);",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Vibrance
-//
-
-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);",
-	"}"
-].join( "\n" ) ) );

+ 0 - 661
examples/js/nodes/NodeMaterial.js

@@ -1,661 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeMaterial = function ( vertex, fragment ) {
-
-	THREE.ShaderMaterial.call( this );
-
-	this.defines.UUID = this.uuid;
-
-	this.vertex = vertex || new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) );
-	this.fragment = fragment || new THREE.RawNode( new THREE.ColorNode( 0xFF0000 ) );
-
-	this.updaters = [];
-
-};
-
-THREE.NodeMaterial.types = {
-	t: 'sampler2D',
-	tc: 'samplerCube',
-	bv1: 'bool',
-	iv1: 'int',
-	fv1: 'float',
-	c: 'vec3',
-	v2: 'vec2',
-	v3: 'vec3',
-	v4: 'vec4',
-	m3: 'mat3',
-	m4: 'mat4'
-};
-
-THREE.NodeMaterial.addShortcuts = function ( proto, prop, list ) {
-
-	function applyShortcut( prop, name ) {
-
-		return {
-			get: function () {
-
-				return this[ prop ][ name ];
-
-			},
-			set: function ( val ) {
-
-				this[ prop ][ name ] = val;
-
-			}
-		};
-
-	}
-
-	return ( function () {
-
-		var shortcuts = {};
-
-		for ( var i = 0; i < list.length; ++ i ) {
-
-			var name = list[ i ];
-
-			shortcuts[ name ] = applyShortcut( prop, name );
-
-		}
-
-		Object.defineProperties( proto, shortcuts );
-
-	} )();
-
-};
-
-THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
-THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
-THREE.NodeMaterial.prototype.type = "NodeMaterial";
-
-THREE.NodeMaterial.prototype.updateFrame = function ( frame ) {
-
-	for ( var i = 0; i < this.updaters.length; ++ i ) {
-
-		frame.updateNode( this.updaters[ i ] );
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
-
-	if ( this.needsUpdate ) {
-
-		this.build( { dispose: false, renderer: renderer } );
-
-		shader.uniforms = this.uniforms;
-		shader.vertexShader = this.vertexShader;
-		shader.fragmentShader = this.fragmentShader;
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.build = function ( params ) {
-
-	params = params || {};
-	params.dispose = params.dispose !== undefined ? params.dispose : true;
-
-	var vertex, fragment;
-
-	this.nodes = [];
-
-	this.defines = { UUID: this.uuid };
-	this.uniforms = {};
-	this.attributes = {};
-
-	this.extensions = {};
-
-	this.nodeData = {};
-
-	this.vertexUniform = [];
-	this.fragmentUniform = [];
-
-	this.vars = [];
-	this.vertexTemps = [];
-	this.fragmentTemps = [];
-
-	this.uniformList = [];
-
-	this.consts = [];
-	this.functions = [];
-
-	this.updaters = [];
-
-	this.requires = {
-		uv: [],
-		color: [],
-		lights: this.lights,
-		fog: this.fog
-	};
-
-	this.vertexPars = '';
-	this.fragmentPars = '';
-
-	this.vertexCode = '';
-	this.fragmentCode = '';
-
-	this.vertexNode = '';
-	this.fragmentNode = '';
-
-	this.prefixCode = [
-		"#ifdef GL_EXT_shader_texture_lod",
-
-		"	#define texCube(a, b) textureCube(a, b)",
-		"	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
-
-		"	#define tex2D(a, b) texture2D(a, b)",
-		"	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
-
-		"#else",
-
-		"	#define texCube(a, b) textureCube(a, b)",
-		"	#define texCubeBias(a, b, c) textureCube(a, b, c)",
-
-		"	#define tex2D(a, b) texture2D(a, b)",
-		"	#define tex2DBias(a, b, c) texture2D(a, b, c)",
-
-		"#endif",
-
-		"#include <packing>"
-
-	].join( "\n" );
-
-	var builder = new THREE.NodeBuilder( this, params.renderer );
-
-	vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
-	fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
-
-	if ( this.requires.uv[ 0 ] ) {
-
-		this.addVertexPars( 'varying vec2 vUv;' );
-		this.addFragmentPars( 'varying vec2 vUv;' );
-
-		this.addVertexCode( 'vUv = uv;' );
-
-	}
-
-	if ( this.requires.uv[ 1 ] ) {
-
-		this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
-		this.addFragmentPars( 'varying vec2 vUv2;' );
-
-		this.addVertexCode( 'vUv2 = uv2;' );
-
-	}
-
-	if ( this.requires.color[ 0 ] ) {
-
-		this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
-		this.addFragmentPars( 'varying vec4 vColor;' );
-
-		this.addVertexCode( 'vColor = color;' );
-
-	}
-
-	if ( this.requires.color[ 1 ] ) {
-
-		this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
-		this.addFragmentPars( 'varying vec4 vColor2;' );
-
-		this.addVertexCode( 'vColor2 = color2;' );
-
-	}
-
-	if ( this.requires.position ) {
-
-		this.addVertexPars( 'varying vec3 vPosition;' );
-		this.addFragmentPars( 'varying vec3 vPosition;' );
-
-		this.addVertexCode( 'vPosition = transformed;' );
-
-	}
-
-	if ( this.requires.worldPosition ) {
-
-		this.addVertexPars( 'varying vec3 vWPosition;' );
-		this.addFragmentPars( 'varying vec3 vWPosition;' );
-
-		this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
-
-	}
-
-	if ( this.requires.normal ) {
-
-		this.addVertexPars( 'varying vec3 vObjectNormal;' );
-		this.addFragmentPars( 'varying vec3 vObjectNormal;' );
-
-		this.addVertexCode( 'vObjectNormal = normal;' );
-
-	}
-
-	if ( this.requires.worldNormal ) {
-
-		this.addVertexPars( 'varying vec3 vWNormal;' );
-		this.addFragmentPars( 'varying vec3 vWNormal;' );
-
-		this.addVertexCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
-
-	}
-
-	this.fog = this.requires.fog;
-	this.lights = this.requires.lights;
-
-	this.transparent = this.requires.transparent || this.blending > THREE.NormalBlending;
-
-	this.vertexShader = [
-		this.prefixCode,
-		this.vertexPars,
-		this.getCodePars( this.vertexUniform, 'uniform' ),
-		this.getIncludes( this.consts[ 'vertex' ] ),
-		this.getIncludes( this.functions[ 'vertex' ] ),
-		'void main(){',
-		this.getCodePars( this.vertexTemps ),
-		vertex,
-		this.vertexCode,
-		'}'
-	].join( "\n" );
-
-	this.fragmentShader = [
-		this.prefixCode,
-		this.fragmentPars,
-		this.getCodePars( this.fragmentUniform, 'uniform' ),
-		this.getIncludes( this.consts[ 'fragment' ] ),
-		this.getIncludes( this.functions[ 'fragment' ] ),
-		'void main(){',
-		this.getCodePars( this.fragmentTemps ),
-		this.fragmentCode,
-		fragment,
-		'}'
-	].join( "\n" );
-
-	if ( params.dispose ) {
-
-		// force update
-
-		this.dispose();
-
-	}
-
-	return this;
-
-};
-
-THREE.NodeMaterial.prototype.define = function ( name, value ) {
-
-	this.defines[ name ] = value == undefined ? 1 : value;
-
-};
-
-THREE.NodeMaterial.prototype.isDefined = function ( name ) {
-
-	return this.defines[ name ] != undefined;
-
-};
-
-THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
-
-	for ( var name in uniforms ) {
-
-		this.uniforms[ name ] = uniforms[ name ];
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.createUniform = function ( type, node, ns, needsUpdate ) {
-
-	var index = this.uniformList.length;
-
-	var uniform = new THREE.NodeUniform( {
-		type: type,
-		name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
-		node: node,
-		needsUpdate: needsUpdate
-	} );
-
-	this.uniformList.push( uniform );
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.getVertexTemp = function ( uuid, type, ns ) {
-
-	var data = this.vertexTemps[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.vertexTemps.length,
-			name = ns ? ns : 'nVt' + index;
-
-		data = { name: name, type: type };
-
-		this.vertexTemps.push( data );
-		this.vertexTemps[ uuid ] = data;
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getFragmentTemp = function ( uuid, type, ns ) {
-
-	var data = this.fragmentTemps[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.fragmentTemps.length,
-			name = ns ? ns : 'nVt' + index;
-
-		data = { name: name, type: type };
-
-		this.fragmentTemps.push( data );
-		this.fragmentTemps[ uuid ] = data;
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getVar = function ( uuid, type, ns ) {
-
-	var data = this.vars[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.vars.length,
-			name = ns ? ns : 'nVv' + index;
-
-		data = { name: name, type: type };
-
-		this.vars.push( data );
-		this.vars[ uuid ] = data;
-
-		this.addVertexPars( 'varying ' + type + ' ' + name + ';' );
-		this.addFragmentPars( 'varying ' + type + ' ' + name + ';' );
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getAttribute = function ( name, type ) {
-
-	if ( ! this.attributes[ name ] ) {
-
-		var varying = this.getVar( name, type );
-
-		this.addVertexPars( 'attribute ' + type + ' ' + name + ';' );
-		this.addVertexCode( varying.name + ' = ' + name + ';' );
-
-		this.attributes[ name ] = { varying: varying, name: name, type: type };
-
-	}
-
-	return this.attributes[ name ];
-
-};
-
-THREE.NodeMaterial.prototype.getIncludes = function () {
-
-	function sortByPosition( a, b ) {
-
-		return a.deps.length - b.deps.length;
-
-	}
-
-	return function ( incs ) {
-
-		if ( ! incs ) return '';
-
-		var code = '', incs = incs.sort( sortByPosition );
-
-		for ( var i = 0; i < incs.length; i ++ ) {
-
-			if ( incs[ i ].src ) code += incs[ i ].src + '\n';
-
-		}
-
-		return code;
-
-	};
-
-}();
-
-THREE.NodeMaterial.prototype.addVertexPars = function ( code ) {
-
-	this.vertexPars += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentPars = function ( code ) {
-
-	this.fragmentPars += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addVertexCode = function ( code ) {
-
-	this.vertexCode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentCode = function ( code ) {
-
-	this.fragmentCode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addVertexNode = function ( code ) {
-
-	this.vertexNode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.clearVertexNode = function () {
-
-	var code = this.vertexNode;
-
-	this.vertexNode = '';
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentNode = function ( code ) {
-
-	this.fragmentNode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.clearFragmentNode = function () {
-
-	var code = this.fragmentNode;
-
-	this.fragmentNode = '';
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
-
-	prefix = prefix || '';
-
-	var code = '';
-
-	for ( var i = 0, l = pars.length; i < l; ++ i ) {
-
-		var parsType = pars[ i ].type;
-		var parsName = pars[ i ].name;
-		var parsValue = pars[ i ].value;
-
-		if ( parsType == 't' && parsValue instanceof THREE.CubeTexture ) parsType = 'tc';
-
-		var type = THREE.NodeMaterial.types[ parsType ];
-
-		if ( type == undefined ) throw new Error( "Node pars " + parsType + " not found." );
-
-		code += prefix + ' ' + type + ' ' + parsName + ';\n';
-
-	}
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.createVertexUniform = function ( type, node, ns, needsUpdate ) {
-
-	var uniform = this.createUniform( type, node, ns, needsUpdate );
-
-	this.vertexUniform.push( uniform );
-	this.vertexUniform[ uniform.name ] = uniform;
-
-	this.uniforms[ uniform.name ] = uniform;
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, node, ns, needsUpdate ) {
-
-	var uniform = this.createUniform( type, node, ns, needsUpdate );
-
-	this.fragmentUniform.push( uniform );
-	this.fragmentUniform[ uniform.name ] = uniform;
-
-	this.uniforms[ uniform.name ] = uniform;
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.getDataNode = function ( uuid ) {
-
-	return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
-
-};
-
-THREE.NodeMaterial.prototype.include = function ( builder, node, parent, source ) {
-
-	var includes;
-
-	node = typeof node === 'string' ? THREE.NodeLib.get( node ) : node;
-
-	if ( node instanceof THREE.FunctionNode ) {
-
-		includes = this.functions[ builder.shader ] = this.functions[ builder.shader ] || [];
-
-	} else if ( node instanceof THREE.ConstNode ) {
-
-		includes = this.consts[ builder.shader ] = this.consts[ builder.shader ] || [];
-
-	}
-
-	var included = includes[ node.name ];
-
-	if ( ! included ) {
-
-		included = includes[ node.name ] = {
-			node: node,
-			deps: []
-		};
-
-		includes.push( included );
-
-		included.src = node.build( builder, 'source' );
-
-	}
-
-	if ( node instanceof THREE.FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
-
-		includes[ parent.name ].deps.push( node );
-
-		if ( node.includes && node.includes.length ) {
-
-			var i = 0;
-
-			do {
-
-				this.include( builder, node.includes[ i ++ ], parent );
-
-			} while ( i < node.includes.length );
-
-		}
-
-	}
-
-	if ( source ) {
-
-		included.src = 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;
-
-};

+ 106 - 0
examples/js/nodes/Nodes.js

@@ -0,0 +1,106 @@
+// TODO: all nodes
+
+// core
+
+export { GLNode } from './core/GLNode.js';
+export { TempNode } from './core/TempNode.js';
+export { InputNode } from './core/InputNode.js';
+export { ConstNode } from './core/ConstNode.js';
+export { VarNode } from './core/VarNode.js';
+export { StructNode } from './core/StructNode.js';
+export { AttributeNode } from './core/AttributeNode.js';
+export { FunctionNode } from './core/FunctionNode.js';
+export { FunctionCallNode } from './core/FunctionCallNode.js';
+export { NodeLib } from './core/NodeLib.js';
+export { NodeUtils } from './core/NodeUtils.js';
+export { NodeFrame } from './core/NodeFrame.js';
+export { NodeUniform } from './core/NodeUniform.js';
+export { NodeBuilder } from './core/NodeBuilder.js';
+
+// inputs
+
+export { IntNode } from './inputs/IntNode.js';
+export { FloatNode } from './inputs/FloatNode.js';
+export { Vector2Node } from './inputs/Vector2Node.js';
+export { Vector3Node } from './inputs/Vector3Node.js';
+export { Vector4Node } from './inputs/Vector4Node.js';
+export { ColorNode } from './inputs/ColorNode.js';
+export { Matrix3Node } from './inputs/Matrix3Node.js';
+export { Matrix4Node } from './inputs/Matrix4Node.js';
+export { TextureNode } from './inputs/TextureNode.js';
+export { CubeTextureNode } from './inputs/CubeTextureNode.js';
+export { ScreenNode } from './inputs/ScreenNode.js';
+export { ReflectorNode } from './inputs/ReflectorNode.js';
+export { PropertyNode } from './inputs/PropertyNode.js';
+
+// accessors
+
+export { UVNode } from './accessors/UVNode.js';
+export { ColorsNode } from './accessors/ColorsNode.js';
+export { PositionNode } from './accessors/PositionNode.js';
+export { NormalNode } from './accessors/NormalNode.js';
+export { CameraNode } from './accessors/CameraNode.js';
+export { LightNode } from './accessors/LightNode.js';
+export { ReflectNode } from './accessors/ReflectNode.js';
+export { ScreenUVNode } from './accessors/ScreenUVNode.js';
+export { ResolutionNode } from './accessors/ResolutionNode.js';
+
+// math
+
+export { Math1Node } from './math/Math1Node.js';
+export { Math2Node } from './math/Math2Node.js';
+export { Math3Node } from './math/Math3Node.js';
+export { OperatorNode } from './math/OperatorNode.js';
+
+// procedural
+
+export { NoiseNode } from './procedural/NoiseNode.js';
+
+// bsdfs
+
+export { BlinnShininessExponentNode } from './bsdfs/BlinnShininessExponentNode.js';
+export { BlinnExponentToRoughnessNode } from './bsdfs/BlinnExponentToRoughnessNode.js';
+export { RoughnessToBlinnExponentNode } from './bsdfs/RoughnessToBlinnExponentNode.js';
+
+// misc
+
+export { TextureCubeUVNode } from './misc/TextureCubeUVNode.js';
+export { TextureCubeNode } from './misc/TextureCubeNode.js';
+export { NormalMapNode } from './misc/NormalMapNode.js';
+export { BumpMapNode } from './misc/BumpMapNode.js';
+
+// utils
+
+export { BypassNode } from './utils/BypassNode.js';
+export { JoinNode } from './utils/JoinNode.js';
+export { SwitchNode } from './utils/SwitchNode.js';
+export { TimerNode } from './utils/TimerNode.js';
+export { VelocityNode } from './utils/VelocityNode.js';
+export { UVTransformNode } from './utils/UVTransformNode.js';
+export { MaxMIPLevelNode } from './utils/MaxMIPLevelNode.js';
+
+// effects
+
+export { BlurNode } from './effects/BlurNode.js';
+export { ColorAdjustmentNode } from './effects/ColorAdjustmentNode.js';
+export { LuminanceNode } from './effects/LuminanceNode.js';
+
+// material nodes
+
+export { RawNode } from './materials/nodes/RawNode.js';
+export { SpriteNode } from './materials/nodes/SpriteNode.js';
+export { PhongNode } from './materials/nodes/PhongNode.js';
+export { StandardNode } from './materials/nodes/StandardNode.js';
+export { MeshStandardNode } from './materials/nodes/MeshStandardNode.js';
+
+// materials
+
+export { NodeMaterial } from './materials/NodeMaterial.js';
+export { SpriteNodeMaterial } from './materials/SpriteNodeMaterial.js';
+export { PhongNodeMaterial } from './materials/PhongNodeMaterial.js';
+export { StandardNodeMaterial } from './materials/StandardNodeMaterial.js';
+export { MeshStandardNodeMaterial } from './materials/MeshStandardNodeMaterial.js';
+
+// postprocessing
+
+//export { NodePass } from './postprocessing/NodePass.js';

+ 0 - 53
examples/js/nodes/RawNode.js

@@ -1,53 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.RawNode = function ( value ) {
-
-	THREE.GLNode.call( this, 'v4' );
-
-	this.value = value;
-
-};
-
-THREE.RawNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.RawNode.prototype.constructor = THREE.RawNode;
-THREE.RawNode.prototype.nodeType = "Raw";
-
-THREE.RawNode.prototype.generate = function ( builder ) {
-
-	var material = builder.material;
-
-	var data = this.value.parseAndBuildCode( builder, this.type );
-
-	var code = data.code + '\n';
-
-	if ( builder.shader == 'vertex' ) {
-
-		code += 'gl_Position = ' + data.result + ';';
-
-	} else {
-
-		code += 'gl_FragColor = ' + data.result + ';';
-
-	}
-
-	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;
-
-};

+ 205 - 0
examples/js/nodes/THREE.Nodes.js

@@ -0,0 +1,205 @@
+import { 
+
+	// core
+	
+	GLNode,
+	TempNode,
+	InputNode,
+	ConstNode,
+	VarNode,
+	StructNode,
+	AttributeNode,
+	FunctionNode,
+	FunctionCallNode,
+	NodeLib,
+	NodeUtils,
+	NodeFrame,
+	NodeUniform,
+	NodeBuilder,
+	
+	// inputs
+	
+	IntNode,
+	FloatNode,
+	Vector2Node,
+	Vector3Node,
+	Vector4Node,
+	ColorNode,
+	Matrix3Node,
+	Matrix4Node,
+	TextureNode,
+	CubeTextureNode,
+	ScreenNode,
+	ReflectorNode,
+	PropertyNode,
+	
+	// accessors
+	
+	UVNode,
+	ColorsNode,
+	PositionNode,
+	NormalNode,
+	CameraNode,
+	LightNode,
+	ReflectNode,
+	ScreenUVNode,
+	ResolutionNode,
+	
+	// math
+	
+	Math1Node,
+	Math2Node,
+	Math3Node,
+	OperatorNode,
+	
+	// procedural
+	
+	NoiseNode,
+	
+	// bsdfs
+	
+	BlinnShininessExponentNode,
+	BlinnExponentToRoughnessNode,
+	RoughnessToBlinnExponentNode,
+	
+	// misc
+	
+	TextureCubeUVNode,
+	TextureCubeNode,
+	NormalMapNode,
+	BumpMapNode,
+	
+	// utils
+	
+	BypassNode,
+	JoinNode,
+	SwitchNode,
+	TimerNode,
+	VelocityNode,
+	UVTransformNode,
+	MaxMIPLevelNode,
+	
+	// effects
+	
+	BlurNode,
+	ColorAdjustmentNode,
+	LuminanceNode,
+
+	// material nodes
+	
+	RawNode,
+	SpriteNode,
+	PhongNode,
+	StandardNode,
+	MeshStandardNode,
+	
+	// materials
+	
+	NodeMaterial,
+	SpriteNodeMaterial,
+	PhongNodeMaterial,
+	StandardNodeMaterial,
+	MeshStandardNodeMaterial
+	
+} from './Nodes.js';
+
+// core
+
+THREE.GLNode = GLNode;
+THREE.TempNode = TempNode;
+THREE.InputNode = InputNode;
+THREE.ConstNode = ConstNode;
+THREE.VarNode = VarNode;
+THREE.StructNode = StructNode;
+THREE.AttributeNode = AttributeNode;
+THREE.FunctionNode = FunctionNode;
+THREE.FunctionCallNode = FunctionCallNode;
+THREE.NodeLib = NodeLib;
+THREE.NodeUtils = NodeUtils;
+THREE.NodeFrame = NodeFrame;
+THREE.NodeUniform = NodeUniform;
+THREE.NodeBuilder = NodeBuilder;
+
+// inputs
+
+THREE.IntNode = IntNode;
+THREE.FloatNode = FloatNode;
+THREE.Vector2Node = Vector2Node;
+THREE.Vector3Node = Vector3Node;
+THREE.Vector4Node = Vector4Node;
+THREE.ColorNode = ColorNode;
+THREE.Matrix3Node = Matrix3Node;
+THREE.Matrix4Node = Matrix4Node;
+THREE.TextureNode = TextureNode;
+THREE.CubeTextureNode = CubeTextureNode;
+THREE.ScreenNode = ScreenNode;
+THREE.ReflectorNode = ReflectorNode;
+THREE.PropertyNode = PropertyNode;
+
+// accessors
+
+THREE.UVNode = UVNode;
+THREE.ColorsNode = ColorsNode;
+THREE.PositionNode = PositionNode;
+THREE.NormalNode = NormalNode;
+THREE.CameraNode = CameraNode;
+THREE.LightNode = LightNode;
+THREE.ReflectNode = ReflectNode;
+THREE.ScreenUVNode = ScreenUVNode;
+THREE.ResolutionNode = ResolutionNode;
+
+// math
+
+THREE.Math1Node = Math1Node;
+THREE.Math2Node = Math2Node;
+THREE.Math3Node = Math3Node;
+THREE.OperatorNode = OperatorNode;
+
+// procedural
+
+THREE.NoiseNode = NoiseNode;
+
+// bsdfs
+
+THREE.BlinnShininessExponentNode = BlinnShininessExponentNode;
+THREE.BlinnExponentToRoughnessNode = BlinnExponentToRoughnessNode;
+THREE.RoughnessToBlinnExponentNode = RoughnessToBlinnExponentNode;
+
+// misc
+
+THREE.TextureCubeUVNode = TextureCubeUVNode;
+THREE.TextureCubeNode = TextureCubeNode;
+THREE.NormalMapNode = NormalMapNode;
+THREE.BumpMapNode = BumpMapNode;
+
+// utils
+
+THREE.BypassNode = BypassNode;
+THREE.JoinNode = JoinNode;
+THREE.SwitchNode = SwitchNode;
+THREE.TimerNode = TimerNode;
+THREE.VelocityNode = VelocityNode;
+THREE.UVTransformNode = UVTransformNode;
+THREE.MaxMIPLevelNode = MaxMIPLevelNode;
+
+// effects
+
+THREE.BlurNode = BlurNode;
+THREE.ColorAdjustmentNode = ColorAdjustmentNode;
+THREE.LuminanceNode = LuminanceNode;
+
+// material nodes
+
+THREE.RawNode = RawNode;
+THREE.SpriteNode = SpriteNode;
+THREE.PhongNode = PhongNode;
+THREE.StandardNode = StandardNode;
+THREE.MeshStandardNode = MeshStandardNode;
+
+// materials
+
+THREE.NodeMaterial = NodeMaterial;
+THREE.SpriteNodeMaterial = SpriteNodeMaterial;
+THREE.PhongNodeMaterial = PhongNodeMaterial;
+THREE.StandardNodeMaterial = StandardNodeMaterial;
+THREE.MeshStandardNodeMaterial = MeshStandardNodeMaterial;

+ 0 - 134
examples/js/nodes/TempNode.js

@@ -1,134 +0,0 @@
-/**
- * Automatic node cache
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.TempNode = function ( type, params ) {
-
-	THREE.GLNode.call( this, type );
-
-	params = params || {};
-
-	this.shared = params.shared !== undefined ? params.shared : true;
-	this.unique = params.unique !== undefined ? params.unique : false;
-
-};
-
-THREE.TempNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.TempNode.prototype.constructor = THREE.TempNode;
-
-THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
-
-	output = output || this.getType( builder );
-
-	var material = builder.material;
-
-	if ( this.isShared( builder, output ) ) {
-
-		var isUnique = this.isUnique( builder, output );
-
-		if ( isUnique && this.constructor.uuid === undefined ) {
-
-			this.constructor.uuid = THREE.Math.generateUUID();
-
-		}
-
-		uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
-
-		var data = material.getDataNode( uuid );
-
-		if ( builder.parsing ) {
-
-			if ( data.deps || 0 > 0 ) {
-
-				this.appendDepsNode( builder, data, output );
-
-				return this.generate( builder, type, uuid );
-
-			}
-
-			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-		} else if ( isUnique ) {
-
-			data.name = data.name || THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-			return data.name;
-
-		} else if ( ! builder.optimize || data.deps == 1 ) {
-
-			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-		}
-
-		uuid = this.getUuid( false );
-
-		var name = this.getTemp( builder, uuid );
-		var type = data.output || this.getType( builder );
-
-		if ( name ) {
-
-			return builder.format( name, type, output );
-
-		} else {
-
-			name = THREE.TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
-
-			var code = this.generate( builder, type, uuid );
-
-			if ( builder.isShader( 'vertex' ) ) material.addVertexNode( name + '=' + code + ';' );
-			else material.addFragmentNode( name + '=' + code + ';' );
-
-			return builder.format( name, type, output );
-
-		}
-
-	}
-
-	return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-};
-
-THREE.TempNode.prototype.isShared = function ( builder, output ) {
-
-	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
-
-};
-
-THREE.TempNode.prototype.isUnique = function ( builder, output ) {
-
-	return this.unique;
-
-};
-
-THREE.TempNode.prototype.getUuid = function ( unique ) {
-
-	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
-
-	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
-
-	return uuid;
-
-};
-
-THREE.TempNode.prototype.getTemp = function ( builder, uuid ) {
-
-	uuid = uuid || this.uuid;
-
-	var material = builder.material;
-
-	if ( builder.isShader( 'vertex' ) && material.vertexTemps[ uuid ] ) return material.vertexTemps[ uuid ].name;
-	else if ( material.fragmentTemps[ uuid ] ) return material.fragmentTemps[ uuid ].name;
-
-};
-
-THREE.TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
-
-	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
-
-	uuid = uuid || this.uuid;
-
-	if ( builder.isShader( 'vertex' ) ) return builder.material.getVertexTemp( uuid, type || this.getType( builder ), ns ).name;
-	else return builder.material.getFragmentTemp( uuid, type || this.getType( builder ), ns ).name;
-
-};

+ 0 - 43
examples/js/nodes/VarNode.js

@@ -1,43 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.VarNode = function ( type ) {
-
-	THREE.GLNode.call( this, 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 ) {
-
-	return builder.getTypeByFormat( this.type );
-
-};
-
-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;
-
-};

+ 97 - 50
examples/js/nodes/accessors/CameraNode.js

@@ -2,46 +2,66 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.CameraNode = function ( scope, camera ) {
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+ 
+function CameraNode( scope, camera ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.setScope( scope || THREE.CameraNode.POSITION );
+	this.setScope( scope || CameraNode.POSITION );
 	this.setCamera( camera );
 
 };
 
-THREE.CameraNode.fDepthColor = new THREE.FunctionNode( [
-	"float depthColor( float mNear, float mFar ) {",
-	"	#ifdef USE_LOGDEPTHBUF_EXT",
-	"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",
-	"	#else",
-	"		float depth = gl_FragCoord.z / gl_FragCoord.w;",
-	"	#endif",
-	"	return 1.0 - smoothstep( mNear, mFar, depth );",
-	"}"
-].join( "\n" ) );
-
-THREE.CameraNode.POSITION = 'position';
-THREE.CameraNode.DEPTH = 'depth';
-THREE.CameraNode.TO_VERTEX = 'toVertex';
-
-THREE.CameraNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.CameraNode.prototype.constructor = THREE.CameraNode;
-THREE.CameraNode.prototype.nodeType = "Camera";
-
-THREE.CameraNode.prototype.setCamera = function ( camera ) {
+CameraNode.Nodes = (function() {
+	
+	var depthColor = new FunctionNode( [
+		"float depthColor( float mNear, float mFar ) {",
+		
+		"	#ifdef USE_LOGDEPTHBUF_EXT",
+		
+		"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",
+		
+		"	#else",
+		
+		"		float depth = gl_FragCoord.z / gl_FragCoord.w;",
+		
+		"	#endif",
+		
+		"	return 1.0 - smoothstep( mNear, mFar, depth );",
+		
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		depthColor: depthColor
+	};
+	
+})();
+
+CameraNode.POSITION = 'position';
+CameraNode.DEPTH = 'depth';
+CameraNode.TO_VERTEX = 'toVertex';
+
+CameraNode.prototype = Object.create( TempNode.prototype );
+CameraNode.prototype.constructor = CameraNode;
+CameraNode.prototype.nodeType = "Camera";
+
+CameraNode.prototype.setCamera = function ( camera ) {
 
 	this.camera = camera;
 	this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
 
 };
 
-THREE.CameraNode.prototype.setScope = function ( scope ) {
+CameraNode.prototype.setScope = function ( scope ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			delete this.near;
 			delete this.far;
@@ -54,12 +74,12 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
 
 	switch ( scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			var camera = this.camera;
 
-			this.near = new THREE.FloatNode( camera ? camera.near : 1 );
-			this.far = new THREE.FloatNode( camera ? camera.far : 1200 );
+			this.near = new FloatNode( camera ? camera.near : 1 );
+			this.far = new FloatNode( camera ? camera.far : 1200 );
 
 			break;
 
@@ -67,12 +87,13 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
 
 };
 
-THREE.CameraNode.prototype.getType = function ( builder ) {
+CameraNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
-			return 'fv1';
+		case CameraNode.DEPTH:
+		
+			return 'f';
 
 	}
 
@@ -80,12 +101,13 @@ THREE.CameraNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.isUnique = function ( builder ) {
+CameraNode.prototype.isUnique = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
-		case THREE.CameraNode.TO_VERTEX:
+		case CameraNode.DEPTH:
+		case CameraNode.TO_VERTEX:
+		
 			return true;
 
 	}
@@ -94,11 +116,12 @@ THREE.CameraNode.prototype.isUnique = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.isShared = function ( builder ) {
+CameraNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.POSITION:
+		case CameraNode.POSITION:
+		
 			return false;
 
 	}
@@ -107,32 +130,29 @@ THREE.CameraNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.generate = function ( builder, output ) {
+CameraNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.POSITION:
+		case CameraNode.POSITION:
 
 			result = 'cameraPosition';
 
 			break;
 
-		case THREE.CameraNode.DEPTH:
-
-			var func = THREE.CameraNode.fDepthColor;
+		case CameraNode.DEPTH:
 
-			builder.include( func );
+			var depthColor = builder.include( CameraNode.Nodes.depthColor );
 
-			result = func.name + '(' + this.near.build( builder, 'fv1' ) + ',' + this.far.build( builder, 'fv1' ) + ')';
+			result = depthColor + '( ' + this.near.build( builder, 'f' ) + ', ' + this.far.build( builder, 'f' ) + ' )';
 
 			break;
 
-		case THREE.CameraNode.TO_VERTEX:
+		case CameraNode.TO_VERTEX:
 
-			result = 'normalize( ' + new THREE.PositionNode( THREE.PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
+			result = 'normalize( ' + new PositionNode( PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
 
 			break;
 
@@ -142,11 +162,11 @@ THREE.CameraNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
+CameraNode.prototype.onUpdateFrame = function ( frame ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			var camera = this.camera;
 
@@ -159,7 +179,32 @@ THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
 
 };
 
-THREE.CameraNode.prototype.toJSON = function ( meta ) {
+CameraNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.setScope( source.scope );
+
+	if ( source.camera ) {
+		
+		this.setCamera( source.camera );
+		
+	}
+
+	switch ( source.scope ) {
+
+		case CameraNode.DEPTH:
+
+			this.near.number = source.near;
+			this.far.number = source.far;
+
+			break;
+
+	}
+	
+};
+
+CameraNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -173,7 +218,7 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
 
 		switch ( this.scope ) {
 
-			case THREE.CameraNode.DEPTH:
+			case CameraNode.DEPTH:
 
 				data.near = this.near.value;
 				data.far = this.far.value;
@@ -187,3 +232,5 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { CameraNode };

+ 25 - 16
examples/js/nodes/accessors/ColorsNode.js

@@ -1,36 +1,43 @@
 /**
  * @author sunag / http://www.sunag.com.br/
  */
+ 
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+var vertexDict = [ 'color', 'color2' ],
+	fragmentDict = [ 'vColor', 'vColor2' ];
+ 
+function ColorsNode( index ) {
 
-THREE.ColorsNode = function ( index ) {
-
-	THREE.TempNode.call( this, 'v4', { shared: false } );
+	TempNode.call( this, 'v4', { shared: false } );
 
 	this.index = index || 0;
 
 };
 
-THREE.ColorsNode.vertexDict = [ 'color', 'color2' ];
-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 ) {
+ColorsNode.prototype = Object.create( TempNode.prototype );
+ColorsNode.prototype.constructor = ColorsNode;
 
-	var material = builder.material;
-	var result;
+ColorsNode.prototype.generate = function ( builder, output ) {
 
-	material.requires.color[ this.index ] = true;
+	builder.requires.color[ this.index ] = true;
 
-	if ( builder.isShader( 'vertex' ) ) result = THREE.ColorsNode.vertexDict[ this.index ];
-	else result = THREE.ColorsNode.fragmentDict[ this.index ];
+	var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
 
 	return builder.format( result, this.getType( builder ), output );
 
 };
 
-THREE.ColorsNode.prototype.toJSON = function ( meta ) {
+ColorsNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.index = source.index;
+	
+};
+
+ColorsNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -45,3 +52,5 @@ THREE.ColorsNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ColorsNode };

+ 21 - 9
examples/js/nodes/accessors/LightNode.js

@@ -2,21 +2,23 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.LightNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
 
-	THREE.TempNode.call( this, 'v3', { shared: false } );
+function LightNode( scope ) {
 
-	this.scope = scope || THREE.LightNode.TOTAL;
+	TempNode.call( this, 'v3', { shared: false } );
+
+	this.scope = scope || LightNode.TOTAL;
 
 };
 
-THREE.LightNode.TOTAL = 'total';
+LightNode.TOTAL = 'total';
 
-THREE.LightNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.LightNode.prototype.constructor = THREE.LightNode;
-THREE.LightNode.prototype.nodeType = "Light";
+LightNode.prototype = Object.create( TempNode.prototype );
+LightNode.prototype.constructor = LightNode;
+LightNode.prototype.nodeType = "Light";
 
-THREE.LightNode.prototype.generate = function ( builder, output ) {
+LightNode.prototype.generate = function ( builder, output ) {
 
 	if ( builder.isCache( 'light' ) ) {
 
@@ -32,7 +34,15 @@ THREE.LightNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.LightNode.prototype.toJSON = function ( meta ) {
+LightNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+LightNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -47,3 +57,5 @@ THREE.LightNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { LightNode };

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

@@ -2,27 +2,31 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NormalNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+function NormalNode( scope ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.scope = scope || THREE.NormalNode.LOCAL;
+	this.scope = scope || NormalNode.LOCAL;
 
 };
 
-THREE.NormalNode.LOCAL = 'local';
-THREE.NormalNode.WORLD = 'world';
-THREE.NormalNode.VIEW = 'view';
+NormalNode.LOCAL = 'local';
+NormalNode.WORLD = 'world';
+NormalNode.VIEW = 'view';
 
-THREE.NormalNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.NormalNode.prototype.constructor = THREE.NormalNode;
-THREE.NormalNode.prototype.nodeType = "Normal";
+NormalNode.prototype = Object.create( TempNode.prototype );
+NormalNode.prototype.constructor = NormalNode;
+NormalNode.prototype.nodeType = "Normal";
 
-THREE.NormalNode.prototype.isShared = function ( builder ) {
+NormalNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.NormalNode.WORLD:
+		case NormalNode.WORLD:
+
 			return true;
 
 	}
@@ -31,32 +35,29 @@ THREE.NormalNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.NormalNode.prototype.generate = function ( builder, output ) {
+NormalNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.NormalNode.LOCAL:
+		case NormalNode.LOCAL:
 
-			material.requires.normal = true;
+			builder.requires.normal = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'normal';
-			else result = 'vObjectNormal';
+			result = builder.isShader( 'vertex' ) ? 'normal' : 'vObjectNormal';
 
 			break;
 
-		case THREE.NormalNode.WORLD:
-
-			material.requires.worldNormal = true;
+		case NormalNode.WORLD:
 
-			if ( builder.isShader( 'vertex' ) ) result = '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz';
-			else result = 'vWNormal';
+			builder.requires.worldNormal = true;
 
+			result = builder.isShader( 'vertex' ) ? '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz' : 'vWNormal';
+			
 			break;
 
-		case THREE.NormalNode.VIEW:
+		case NormalNode.VIEW:
 
 			result = 'vNormal';
 
@@ -68,7 +69,15 @@ THREE.NormalNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.NormalNode.prototype.toJSON = function ( meta ) {
+NormalNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+NormalNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -83,3 +92,23 @@ THREE.NormalNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'normal', function () {
+
+	return new NormalNode();
+
+} );
+
+NodeLib.addKeyword( 'worldNormal', function () {
+
+	return new NormalNode( NormalNode.WORLD );
+
+} );
+
+NodeLib.addKeyword( 'viewNormal', function () {
+
+	return new NormalNode( NormalNode.VIEW );
+
+} );
+
+export { NormalNode };

+ 60 - 32
examples/js/nodes/accessors/PositionNode.js

@@ -2,28 +2,32 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PositionNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+function PositionNode( scope ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.scope = scope || THREE.PositionNode.LOCAL;
+	this.scope = scope || PositionNode.LOCAL;
 
 };
 
-THREE.PositionNode.LOCAL = 'local';
-THREE.PositionNode.WORLD = 'world';
-THREE.PositionNode.VIEW = 'view';
-THREE.PositionNode.PROJECTION = 'projection';
+PositionNode.LOCAL = 'local';
+PositionNode.WORLD = 'world';
+PositionNode.VIEW = 'view';
+PositionNode.PROJECTION = 'projection';
 
-THREE.PositionNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.PositionNode.prototype.constructor = THREE.PositionNode;
-THREE.PositionNode.prototype.nodeType = "Position";
+PositionNode.prototype = Object.create( TempNode.prototype );
+PositionNode.prototype.constructor = PositionNode;
+PositionNode.prototype.nodeType = "Position";
 
-THREE.PositionNode.prototype.getType = function ( builder ) {
+PositionNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.PROJECTION:
+		case PositionNode.PROJECTION:
+		
 			return 'v4';
 
 	}
@@ -32,12 +36,13 @@ THREE.PositionNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.PositionNode.prototype.isShared = function ( builder ) {
+PositionNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.LOCAL:
-		case THREE.PositionNode.WORLD:
+		case PositionNode.LOCAL:
+		case PositionNode.WORLD:
+		
 			return false;
 
 	}
@@ -46,42 +51,37 @@ THREE.PositionNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.PositionNode.prototype.generate = function ( builder, output ) {
+PositionNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.LOCAL:
+		case PositionNode.LOCAL:
 
-			material.requires.position = true;
+			builder.requires.position = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'transformed';
-			else result = 'vPosition';
+			result = builder.isShader( 'vertex' ) ? 'transformed' : 'vPosition';
 
 			break;
 
-		case THREE.PositionNode.WORLD:
+		case PositionNode.WORLD:
 
-			material.requires.worldPosition = true;
+			builder.requires.worldPosition = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'vWPosition';
-			else result = 'vWPosition';
+			result = 'vWPosition';
 
 			break;
 
-		case THREE.PositionNode.VIEW:
+		case PositionNode.VIEW:
 
-			if ( builder.isShader( 'vertex' ) ) result = '-mvPosition.xyz';
-			else result = 'vViewPosition';
+			result = builder.isShader( 'vertex' ) ? '-mvPosition.xyz' : 'vViewPosition';
 
 			break;
 
-		case THREE.PositionNode.PROJECTION:
+		case PositionNode.PROJECTION:
 
-			if ( builder.isShader( 'vertex' ) ) result = '(projectionMatrix * modelViewMatrix * vec4( position, 1.0 ))';
-			else result = 'vec4( 0.0 )';
+			result = builder.isShader( 'vertex' ) ? '( projectionMatrix * modelViewMatrix * vec4( position, 1.0 ) )' : 'vec4( 0.0 )';
 
 			break;
 
@@ -91,7 +91,15 @@ THREE.PositionNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.PositionNode.prototype.toJSON = function ( meta ) {
+PositionNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+PositionNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -106,3 +114,23 @@ THREE.PositionNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'position', function () {
+
+	return new PositionNode();
+
+} );
+
+NodeLib.addKeyword( 'worldPosition', function () {
+
+	return new PositionNode( PositionNode.WORLD );
+
+} );
+
+NodeLib.addKeyword( 'viewPosition', function () {
+
+	return new PositionNode( NormalNode.VIEW );
+
+} );
+
+export { PositionNode };

+ 46 - 31
examples/js/nodes/accessors/ReflectNode.js

@@ -2,27 +2,30 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ReflectNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
 
-	THREE.TempNode.call( this, 'v3', { unique: true } );
+function ReflectNode( scope ) {
 
-	this.scope = scope || THREE.ReflectNode.CUBE;
+	TempNode.call( this, 'v3', { unique: true } );
+
+	this.scope = scope || ReflectNode.CUBE;
 
 };
 
-THREE.ReflectNode.CUBE = 'cube';
-THREE.ReflectNode.SPHERE = 'sphere';
-THREE.ReflectNode.VECTOR = 'vector';
+ReflectNode.CUBE = 'cube';
+ReflectNode.SPHERE = 'sphere';
+ReflectNode.VECTOR = 'vector';
 
-THREE.ReflectNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ReflectNode.prototype.constructor = THREE.ReflectNode;
-THREE.ReflectNode.prototype.nodeType = "Reflect";
+ReflectNode.prototype = Object.create( TempNode.prototype );
+ReflectNode.prototype.constructor = ReflectNode;
+ReflectNode.prototype.nodeType = "Reflect";
 
-THREE.ReflectNode.prototype.getType = function ( builder ) {
+ReflectNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.ReflectNode.SPHERE:
+		case ReflectNode.SPHERE:
+
 			return 'v2';
 
 	}
@@ -31,47 +34,57 @@ THREE.ReflectNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.ReflectNode.prototype.generate = function ( builder, output ) {
+ReflectNode.prototype.generate = function ( builder, output ) {
 
-	var result;
+	if ( builder.isShader( 'fragment' ) ) {
+		
+		var result;
 
-	switch ( this.scope ) {
+		switch ( this.scope ) {
 
-		case THREE.ReflectNode.VECTOR:
+			case ReflectNode.VECTOR:
 
-			builder.material.addFragmentNode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
+				builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
 
-			result = 'reflectVec';
+				result = 'reflectVec';
 
-			break;
+				break;
 
-		case THREE.ReflectNode.CUBE:
+			case ReflectNode.CUBE:
 
-			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
+				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-			builder.material.addFragmentNode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
+				builder.addNodeCode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
 
-			result = 'reflectCubeVec';
+				result = 'reflectCubeVec';
 
-			break;
+				break;
 
-		case THREE.ReflectNode.SPHERE:
+			case ReflectNode.SPHERE:
 
-			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
+				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-			builder.material.addFragmentNode( 'vec2 reflectSphereVec = normalize((viewMatrix * vec4(' + reflectVec + ', 0.0 )).xyz + vec3(0.0,0.0,1.0)).xy * 0.5 + 0.5;' );
+				builder.addNodeCode( 'vec2 reflectSphereVec = normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5;' );
 
-			result = 'reflectSphereVec';
+				result = 'reflectSphereVec';
 
-			break;
+				break;
 
-	}
+		}
 
-	return builder.format( result, this.getType( this.type ), output );
+		return builder.format( result, this.getType( this.type ), output );
+	
+	} else {
+		
+		console.warn( "THREE.ReflectNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec3( 0.0 )', this.type, output );
+		
+	}
 
 };
 
-THREE.ReflectNode.prototype.toJSON = function ( meta ) {
+ReflectNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -86,3 +99,5 @@ THREE.ReflectNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ReflectNode };

+ 53 - 0
examples/js/nodes/accessors/ResolutionNode.js

@@ -0,0 +1,53 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { Vector2Node } from '../inputs/Vector2Node.js';
+ 
+function ResolutionNode( renderer ) {
+
+	Vector2Node.call( this );
+
+	this.renderer = renderer;
+
+};
+
+ResolutionNode.prototype = Object.create( Vector2Node.prototype );
+ResolutionNode.prototype.constructor = ResolutionNode;
+ResolutionNode.prototype.nodeType = "Resolution";
+
+ResolutionNode.prototype.updateFrame = function ( frame ) {
+
+	var size = this.renderer.getSize(),
+		pixelRatio = this.renderer.getPixelRatio();
+
+	this.x = size.width * pixelRatio;
+	this.y = size.height * pixelRatio;
+
+};
+
+ResolutionNode.prototype.copy = function ( source ) {
+			
+	Vector2Node.prototype.copy.call( this, source );
+	
+	this.renderer = source.renderer;
+	
+};
+
+ResolutionNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.renderer = this.renderer.uuid;
+
+	}
+
+	return data;
+
+};
+
+export { ResolutionNode };

+ 21 - 9
examples/js/nodes/accessors/ScreenUVNode.js

@@ -2,26 +2,27 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ScreenUVNode = function ( resolution ) {
+import { TempNode } from '../core/TempNode.js';
+ 
+function ScreenUVNode( resolution ) {
 
-	THREE.TempNode.call( this, 'v2' );
+	TempNode.call( this, 'v2' );
 
 	this.resolution = resolution;
 
 };
 
-THREE.ScreenUVNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ScreenUVNode.prototype.constructor = THREE.ScreenUVNode;
-THREE.ScreenUVNode.prototype.nodeType = "ScreenUV";
+ScreenUVNode.prototype = Object.create( TempNode.prototype );
+ScreenUVNode.prototype.constructor = ScreenUVNode;
+ScreenUVNode.prototype.nodeType = "ScreenUV";
 
-THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
+ScreenUVNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	if ( builder.isShader( 'fragment' ) ) {
 
-		result = '(gl_FragCoord.xy/' + this.resolution.build( builder, 'v2' ) + ')';
+		result = '( gl_FragCoord.xy / ' + this.resolution.build( builder, 'v2' ) + ')';
 
 	} else {
 
@@ -35,7 +36,15 @@ THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
+ScreenUVNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.resolution = source.resolution;
+	
+};
+
+ScreenUVNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -50,3 +59,6 @@ THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ScreenUVNode };
+

+ 37 - 16
examples/js/nodes/accessors/UVNode.js

@@ -2,36 +2,43 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.UVNode = function ( index ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+var vertexDict = [ 'uv', 'uv2' ],
+	fragmentDict = [ 'vUv', 'vUv2' ];
+ 
+function UVNode( index ) {
 
-	THREE.TempNode.call( this, 'v2', { shared: false } );
+	TempNode.call( this, 'v2', { shared: false } );
 
 	this.index = index || 0;
 
 };
 
-THREE.UVNode.vertexDict = [ 'uv', 'uv2' ];
-THREE.UVNode.fragmentDict = [ 'vUv', 'vUv2' ];
+UVNode.prototype = Object.create( TempNode.prototype );
+UVNode.prototype.constructor = UVNode;
+UVNode.prototype.nodeType = "UV";
 
-THREE.UVNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.UVNode.prototype.constructor = THREE.UVNode;
-THREE.UVNode.prototype.nodeType = "UV";
+UVNode.prototype.generate = function ( builder, output ) {
 
-THREE.UVNode.prototype.generate = function ( builder, output ) {
+	builder.requires.uv[ this.index ] = true;
 
-	var material = builder.material;
-	var result;
-
-	material.requires.uv[ this.index ] = true;
-
-	if ( builder.isShader( 'vertex' ) ) result = THREE.UVNode.vertexDict[ this.index ];
-	else result = THREE.UVNode.fragmentDict[ this.index ];
+	var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
 
 	return builder.format( result, this.getType( builder ), output );
 
 };
 
-THREE.UVNode.prototype.toJSON = function ( meta ) {
+UVNode.prototype.copy = function ( source ) {
+		
+	TempNode.prototype.copy.call( this, source );
+	
+	this.index = source.index;
+	
+};
+
+UVNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -46,3 +53,17 @@ THREE.UVNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'uv', function () {
+
+	return new UVNode();
+
+} );
+
+NodeLib.addKeyword( 'uv2', function () {
+
+	return new UVNode( 1 );
+
+} );
+
+export { UVNode };

+ 50 - 0
examples/js/nodes/bsdfs/BlinnExponentToRoughnessNode.js

@@ -0,0 +1,50 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
+
+function BlinnExponentToRoughnessNode( blinnExponent ) {
+
+	TempNode.call( this, 'f' );
+
+	this.blinnExponent = blinnExponent || new BlinnShininessExponentNode();
+
+};
+
+BlinnExponentToRoughnessNode.prototype = Object.create( TempNode.prototype );
+BlinnExponentToRoughnessNode.prototype.constructor = BlinnExponentToRoughnessNode;
+BlinnExponentToRoughnessNode.prototype.nodeType = "BlinnExponentToRoughness";
+
+BlinnExponentToRoughnessNode.prototype.generate = function ( builder, output ) {
+
+	return builder.format( 'BlinnExponentToGGXRoughness( ' + this.blinnExponent.build( builder, 'f' ) + ' )', this.type, output );
+
+};
+
+BlinnExponentToRoughnessNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.blinnExponent = source.blinnExponent;
+	
+};
+
+BlinnExponentToRoughnessNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.blinnExponent = this.blinnExponent;
+
+	}
+
+	return data;
+
+};
+
+export { BlinnExponentToRoughnessNode };

+ 31 - 0
examples/js/nodes/bsdfs/BlinnShininessExponentNode.js

@@ -0,0 +1,31 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+
+function BlinnShininessExponentNode() {
+
+	TempNode.call( this, 'f' );
+
+};
+
+BlinnShininessExponentNode.prototype = Object.create( TempNode.prototype );
+BlinnShininessExponentNode.prototype.constructor = BlinnShininessExponentNode;
+BlinnShininessExponentNode.prototype.nodeType = "BlinnShininessExponent";
+
+BlinnShininessExponentNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isCache( 'clearCoat' ) ) {
+
+		return builder.format( 'Material_ClearCoat_BlinnShininessExponent( material )', this.type, output );
+
+	} else {
+
+		return builder.format( 'Material_BlinnShininessExponent( material )', this.type, output );
+
+	}
+
+};
+
+export { BlinnShininessExponentNode };

+ 91 - 0
examples/js/nodes/bsdfs/RoughnessToBlinnExponentNode.js

@@ -0,0 +1,91 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { MaxMIPLevelNode } from '../utils/MaxMIPLevelNode.js';
+import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
+ 
+function RoughnessToBlinnExponentNode( texture ) {
+
+	TempNode.call( this, 'f' );
+
+	this.texture = texture;
+
+	this.maxMIPLevel = new MaxMIPLevelNode( texture );
+	this.blinnShininessExponent = new BlinnShininessExponentNode();
+
+};
+
+RoughnessToBlinnExponentNode.Nodes = (function() {
+
+	var getSpecularMIPLevel = new 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 float maxMIPLevelScalar ) {",
+
+		//	float envMapWidth = pow( 2.0, maxMIPLevelScalar );
+		//	float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
+
+		"	float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );",
+
+		// clamp to allowable LOD ranges.
+		"	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		getSpecularMIPLevel: getSpecularMIPLevel
+	};
+	
+})();
+
+RoughnessToBlinnExponentNode.prototype = Object.create( TempNode.prototype );
+RoughnessToBlinnExponentNode.prototype.constructor = RoughnessToBlinnExponentNode;
+RoughnessToBlinnExponentNode.prototype.nodeType = "RoughnessToBlinnExponent";
+
+RoughnessToBlinnExponentNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		this.maxMIPLevel.texture = this.texture;
+	
+		var getSpecularMIPLevel = builder.include( RoughnessToBlinnExponentNode.Nodes.getSpecularMIPLevel );
+
+		return builder.format( getSpecularMIPLevel + '( ' + this.blinnShininessExponent.build( builder, 'f' ) + ', ' + this.maxMIPLevel.build( builder, 'f' ) + ' )', this.type, output );
+
+	} else {
+
+		console.warn( "THREE.RoughnessToBlinnExponentNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( '0.0', this.type, output );
+
+	}
+
+};
+
+RoughnessToBlinnExponentNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.texture = source.texture;
+	
+};
+
+RoughnessToBlinnExponentNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.texture = this.texture;
+
+	}
+
+	return data;
+
+};
+
+export { RoughnessToBlinnExponentNode };

+ 70 - 0
examples/js/nodes/core/AttributeNode.js

@@ -0,0 +1,70 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function AttributeNode( name, type ) {
+
+	GLNode.call( this, type );
+
+	this.name = name;
+
+};
+
+AttributeNode.prototype = Object.create( GLNode.prototype );
+AttributeNode.prototype.constructor = AttributeNode;
+AttributeNode.prototype.nodeType = "Attribute";
+
+AttributeNode.prototype.getAttributeType = function ( builder ) {
+
+	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
+
+};
+
+AttributeNode.prototype.getType = function ( builder ) {
+
+	var type = this.getAttributeType( builder );
+
+	return builder.getTypeByFormat( type );
+
+};
+
+AttributeNode.prototype.generate = function ( builder, output ) {
+
+	var type = this.getAttributeType( builder );
+
+	var attribute = builder.getAttribute( this.name, type ),
+		name = builder.isShader( 'vertex' ) ? this.name : attribute.varying.name;
+
+	console.log( attribute );
+		
+	return builder.format( name, this.getType( builder ), output );
+
+};
+
+AttributeNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	this.type = source.type;
+	
+};
+
+AttributeNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.type = this.type;
+
+	}
+
+	return data;
+
+};
+
+export { AttributeNode };

+ 125 - 0
examples/js/nodes/core/ConstNode.js

@@ -0,0 +1,125 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+
+function ConstNode( src, useDefine ) {
+
+	TempNode.call( this );
+
+	this.eval( src || ConstNode.PI, useDefine );
+
+};
+
+ConstNode.PI = 'PI';
+ConstNode.PI2 = 'PI2';
+ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
+ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
+ConstNode.LOG2 = 'LOG2';
+ConstNode.EPSILON = 'EPSILON';
+
+ConstNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
+
+ConstNode.prototype = Object.create( TempNode.prototype );
+ConstNode.prototype.constructor = ConstNode;
+ConstNode.prototype.nodeType = "Const";
+
+ConstNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.type );
+
+};
+
+ConstNode.prototype.eval = function ( src, useDefine ) {
+
+	this.src = src || '';
+
+	var name, type, value = "";
+
+	var match = this.src.match( ConstNode.rDeclaration );
+
+	this.useDefine = useDefine || this.src.charAt(0) === '#';
+
+	if ( match && match.length > 1 ) {
+
+		type = match[ 1 ];
+		name = match[ 2 ];
+		value = match[ 3 ];
+
+	} else {
+
+		name = this.src;
+		type = 'f';
+
+	}
+
+	this.name = name;
+	this.type = type;
+	this.value = value;
+
+};
+
+ConstNode.prototype.build = function ( builder, output ) {
+
+	if ( output === 'source' ) {
+
+		if ( this.value ) {
+
+			if ( this.useDefine ) {
+
+				return '#define ' + this.name + ' ' + this.value;
+
+			}
+
+			return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
+
+		} else if (this.useDefine) {
+		
+			return this.src;
+			
+		}
+
+	} else {
+
+		builder.include( this );
+
+		return builder.format( this.name, this.getType( builder ), output );
+
+	}
+
+};
+
+ConstNode.prototype.generate = function ( builder, output ) {
+
+	return builder.format( this.name, this.getType( builder ), output );
+
+};
+
+ConstNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	this.eval( source.src, source.useDefine );	
+	
+};
+
+ConstNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.src = this.src;
+
+		if ( data.useDefine === true ) data.useDefine = true;
+
+	}
+
+	return data;
+
+};
+
+export { ConstNode };

+ 108 - 0
examples/js/nodes/core/FunctionCallNode.js

@@ -0,0 +1,108 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+ 
+function FunctionCallNode( func, inputs ) {
+
+	TempNode.call( this );
+
+	this.setFunction( func, inputs );
+
+};
+
+FunctionCallNode.prototype = Object.create( TempNode.prototype );
+FunctionCallNode.prototype.constructor = FunctionCallNode;
+FunctionCallNode.prototype.nodeType = "FunctionCall";
+
+FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
+
+	this.value = func;
+	this.inputs = inputs || [];
+
+};
+
+FunctionCallNode.prototype.getFunction = function () {
+
+	return this.value;
+
+};
+
+FunctionCallNode.prototype.getType = function ( builder ) {
+
+	return this.value.getType( builder );
+
+};
+
+FunctionCallNode.prototype.generate = function ( builder, output ) {
+
+	var type = this.getType( builder ),
+		func = this.value;
+
+	var code = func.build( builder, output ) + '( ',
+		params = [];
+
+	for ( var i = 0; i < func.inputs.length; i ++ ) {
+
+		var inpt = func.inputs[ i ],
+			param = this.inputs[ i ] || this.inputs[ inpt.name ];
+
+		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
+
+	}
+
+	code += params.join( ', ' ) + ' )';
+
+	return builder.format( code, type, output );
+
+};
+
+FunctionCallNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	for ( var prop in source.inputs ) {
+
+		this.inputs[ prop ] = source.inputs[ prop ];
+
+	}
+
+	this.value = source.value;
+	
+};
+
+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 ],
+					node = this.inputs[ i ] || this.inputs[ inpt.name ];
+
+				data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
+
+			}
+
+		}
+
+	}
+
+	return data;
+
+};
+
+export { FunctionCallNode };

+ 56 - 34
examples/js/nodes/FunctionNode.js → examples/js/nodes/core/FunctionNode.js

@@ -3,40 +3,48 @@
  * @thanks bhouston / https://clara.io/
  */
 
-THREE.FunctionNode = function ( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions ) {
+import { TempNode } from './TempNode.js';
+import { NodeLib } from './NodeLib.js';
 
-	src = src || '';
+function FunctionNode( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions, includes ) {
 
 	this.isMethod = typeof includesOrType !== "string";
 	this.useKeywords = true;
 
-	THREE.TempNode.call( this, this.isMethod ? null : includesOrType );
+	TempNode.call( this, this.isMethod ? null : includesOrType );
 
-	if ( this.isMethod ) this.eval( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions );
-	else this.eval( src, extensionsOrIncludes, keywordsOrExtensions );
+	if ( this.isMethod ) {
+		
+		this.eval( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions );
+		
+	} else {
+		
+		this.eval( src, includes, keywordsOrExtensions, extensionsOrKeywords );
+
+	}
 
 };
 
-THREE.FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\((.*?)\)/i;
-THREE.FunctionNode.rProperties = /[a-z_0-9]+/ig;
+FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s*\((.*?)\)/i;
+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";
+FunctionNode.prototype = Object.create( TempNode.prototype );
+FunctionNode.prototype.constructor = FunctionNode;
+FunctionNode.prototype.nodeType = "Function";
 
-THREE.FunctionNode.prototype.isShared = function ( builder, output ) {
+FunctionNode.prototype.isShared = function ( builder, output ) {
 
 	return ! this.isMethod;
 
 };
 
-THREE.FunctionNode.prototype.getType = function ( builder ) {
+FunctionNode.prototype.getType = function ( builder ) {
 
 	return builder.getTypeByFormat( this.type );
 
 };
 
-THREE.FunctionNode.prototype.getInputByName = function ( name ) {
+FunctionNode.prototype.getInputByName = function ( name ) {
 
 	var i = this.inputs.length;
 
@@ -49,7 +57,7 @@ THREE.FunctionNode.prototype.getInputByName = function ( name ) {
 
 };
 
-THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
+FunctionNode.prototype.getIncludeByName = function ( name ) {
 
 	var i = this.includes.length;
 
@@ -62,9 +70,9 @@ THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
 
 };
 
-THREE.FunctionNode.prototype.generate = function ( builder, output ) {
+FunctionNode.prototype.generate = function ( builder, output ) {
 
-	var match, offset = 0, src = this.value;
+	var match, offset = 0, src = this.src;
 
 	for ( var i = 0; i < this.includes.length; i ++ ) {
 
@@ -74,26 +82,27 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 	for ( var ext in this.extensions ) {
 
-		builder.material.extensions[ ext ] = true;
+		builder.extensions[ ext ] = true;
 
 	}
 
-	while ( match = THREE.FunctionNode.rProperties.exec( this.value ) ) {
+	while ( match = FunctionNode.rProperties.exec( this.src ) ) {
 
-		var prop = match[ 0 ], isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true;
-		var reference = prop;
+		var prop = match[ 0 ], 
+			isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true,
+			reference = prop;
 
-		if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && THREE.NodeLib.containsKeyword( prop ) ) ) {
+		if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) {
 
 			var node = this.keywords[ prop ];
 
 			if ( ! node ) {
 
-				var keyword = THREE.NodeLib.getKeywordData( prop );
+				var keyword = NodeLib.getKeywordData( prop );
 
 				if ( keyword.cache ) node = builder.keywords[ prop ];
 
-				node = node || THREE.NodeLib.getKeyword( prop, builder );
+				node = node || NodeLib.getKeyword( prop, builder );
 
 				if ( keyword.cache ) builder.keywords[ prop ] = node;
 
@@ -111,9 +120,9 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 		}
 
-		if ( this.getIncludeByName( reference ) === undefined && THREE.NodeLib.contains( reference ) ) {
+		if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) {
 
-			builder.include( THREE.NodeLib.get( reference ) );
+			builder.include( NodeLib.get( reference ) );
 
 		}
 
@@ -131,15 +140,15 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 	} else {
 
-		return builder.format( "(" + src + ")", this.getType( builder ), output );
+		return builder.format( '( ' + src + ' )', this.getType( builder ), output );
 
 	}
 
 };
 
-THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
+FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
 
-	src = ( src || '' ).trim();
+	this.src = src || '';
 
 	this.includes = includes || [];
 	this.extensions = extensions || {};
@@ -147,7 +156,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 
 	if ( this.isMethod ) {
 
-		var match = src.match( THREE.FunctionNode.rDeclaration );
+		var match = this.src.match( FunctionNode.rDeclaration );
 
 		this.inputs = [];
 
@@ -156,7 +165,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 			this.type = match[ 1 ];
 			this.name = match[ 2 ];
 
-			var inputs = match[ 3 ].match( THREE.FunctionNode.rProperties );
+			var inputs = match[ 3 ].match( FunctionNode.rProperties );
 
 			if ( inputs ) {
 
@@ -199,11 +208,22 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 
 	}
 
-	this.value = src;
+};
 
+FunctionNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.isMethod = source.isMethod;
+	this.useKeywords = source.useKeywords;
+	
+	this.eval( source.src, source.includes, source.extensions, source.keywords );
+
+	if ( source.type !== undefined ) this.type = source.type;
+	
 };
 
-THREE.FunctionNode.prototype.toJSON = function ( meta ) {
+FunctionNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -211,11 +231,11 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
 
 		data = this.createJSONNode( meta );
 
-		data.src = this.value;
+		data.src = this.src;
 		data.isMethod = this.isMethod;
 		data.useKeywords = this.useKeywords;
 
-		if ( ! this.isMethod ) data.out = this.type;
+		if ( ! this.isMethod ) data.type = this.type;
 
 		data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
 		data.keywords = {};
@@ -243,3 +263,5 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { FunctionNode };

+ 176 - 0
examples/js/nodes/core/GLNode.js

@@ -0,0 +1,176 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+function GLNode( type ) {
+
+	this.uuid = THREE.Math.generateUUID();
+
+	this.name = "";
+
+	this.type = type;
+
+	this.userData = {};
+
+};
+
+GLNode.prototype = {
+
+	constructor: GLNode,
+	
+	isNode: true,
+	
+	parse: function ( builder, settings ) {
+
+		settings = settings || {};
+
+		builder.parsing = true;
+
+		this.build( builder.addCache( settings.cache, settings.requires ).addSlot( settings.slot ), 'v4' );
+
+		builder.clearVertexNodeCode()
+		builder.clearFragmentNodeCode();
+
+		builder.removeCache().removeSlot();
+
+		builder.parsing = false;
+
+	},
+	
+	parseAndBuildCode: function ( builder, output, settings ) {
+
+		settings = settings || {};
+
+		this.parse( builder, settings );
+
+		return this.buildCode( builder, output, settings );
+	
+	},
+	
+	buildCode: function ( builder, output, settings ) {
+
+		settings = settings || {};
+
+		var data = { result: this.build( builder.addCache( settings.cache, settings.context ).addSlot( settings.slot ), output ) };
+
+		data.code = builder.clearNodeCode();
+
+		builder.removeCache().removeSlot();
+
+		return data;
+	
+	},
+
+	build: function ( builder, output, uuid ) {
+
+		output = output || this.getType( builder, output );
+
+		var data = builder.getNodeData( uuid || this );
+
+		if ( builder.parsing ) this.appendDepsNode( builder, data, output );
+
+		if ( builder.nodes.indexOf( this ) === - 1 ) {
+
+			builder.nodes.push( this );
+
+		}
+
+		if ( this.updateFrame !== undefined && builder.updaters.indexOf( this ) === - 1 ) {
+
+			builder.updaters.push( this );
+
+		}
+
+		return this.generate( builder, output, uuid );
+	
+	},
+	
+	appendDepsNode: function ( builder, data, output ) {
+
+		data.deps = ( data.deps || 0 ) + 1;
+
+		var outputLen = builder.getTypeLength( output );
+
+		if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
+
+			data.outputMax = outputLen;
+			data.output = output;
+
+		}
+	
+	},
+	
+	setName: function( name ) {
+		
+		this.name = name;
+		
+		return this;
+		
+	},
+	
+	getName: function( builder ) {
+		
+		return this.name;
+		
+	},
+	
+	getType: function ( builder, output ) {
+
+		return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
+	
+	},
+	
+	getJSONNode: function ( meta ) {
+
+		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+		if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
+
+			return meta.nodes[ this.uuid ];
+
+		}
+	
+	},
+	
+	copy: function ( source ) {
+
+		if ( source.name !== undefined ) this.name = source.name;
+	
+		if ( source.userData !== undefined ) this.userData = JSON.parse( JSON.stringify( source.userData ) );
+	
+	},
+	
+	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.nodeType = this.nodeType;
+
+		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;
+	
+	},
+	
+	toJSON: function ( meta ) {
+
+		return this.getJSONNode( meta ) || this.createJSONNode( meta );
+	
+	}
+	
+};
+
+export { GLNode };

+ 85 - 0
examples/js/nodes/core/InputNode.js

@@ -0,0 +1,85 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+
+function InputNode( type, params ) {
+
+	params = params || {};
+	params.shared = params.shared !== undefined ? params.shared : false;
+
+	TempNode.call( this, type, params );
+
+	this.readonly = false;
+
+};
+
+InputNode.prototype = Object.create( TempNode.prototype );
+InputNode.prototype.constructor = InputNode;
+
+InputNode.prototype.isReadonly = function ( builder ) {
+
+	return this.readonly;
+
+};
+
+InputNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	if ( source.readonly !== undefined ) this.readonly = source.readonly;
+	
+};
+
+InputNode.prototype.createJSONNode = function ( meta ) {
+
+	var data = TempNode.prototype.createJSONNode.call( this, meta );
+	
+	if ( this.readonly === true ) data.readonly = this.readonly;
+
+	return data;
+
+};
+
+InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
+
+	uuid = builder.getUuid( uuid || this.getUuid() );
+	type = type || this.getType( builder );
+
+	var data = builder.getNodeData( uuid ),
+		readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
+
+	if ( readonly ) {
+
+		return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
+
+	} else {
+
+		if ( builder.isShader( 'vertex' ) ) {
+
+			if ( ! data.vertex ) {
+
+				data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate );
+
+			}
+
+			return builder.format( data.vertex.name, type, output );
+
+		} else {
+
+			if ( ! data.fragment ) {
+
+				data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate );
+
+			}
+
+			return builder.format( data.fragment.name, type, output );
+
+		}
+
+	}
+
+};
+
+export { InputNode };

+ 1007 - 0
examples/js/nodes/core/NodeBuilder.js

@@ -0,0 +1,1007 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { NodeUniform } from './NodeUniform.js';
+import { NodeUtils } from './NodeUtils.js';
+import { NodeLib } from './NodeLib.js';
+import { FunctionNode } from './FunctionNode.js';
+import { ConstNode } from './ConstNode.js';
+import { StructNode } from './StructNode.js';
+import { Vector2Node } from '../inputs/Vector2Node.js';
+import { Vector3Node } from '../inputs/Vector3Node.js';
+import { Vector4Node } from '../inputs/Vector4Node.js';
+import { TextureNode } from '../inputs/TextureNode.js';
+import { CubeTextureNode } from '../inputs/CubeTextureNode.js';
+
+var elements = NodeUtils.elements,
+	constructors = [ 'float', 'vec2', 'vec3', 'vec4' ],
+	convertFormatToType = {
+		float: 'f',
+		vec2: 'v2',
+		vec3: 'v3',
+		vec4: 'v4',
+		mat4: 'v4',
+		int: 'i'
+	},
+	convertTypeToFormat = {
+		t: 'sampler2D',
+		tc: 'samplerCube',
+		b: 'bool',
+		i: 'int',
+		f: 'float',
+		c: 'vec3',
+		v2: 'vec2',
+		v3: 'vec3',
+		v4: 'vec4',
+		m3: 'mat3',
+		m4: 'mat4'
+	};
+ 
+function NodeBuilder() {
+
+	this.caches = [];
+	this.slots = [];
+
+	this.keywords = {};
+	
+	this.nodeData = {};
+	
+	this.requires = {
+		uv: [],
+		color: [],
+		lights: false,
+		fog: false
+	};
+
+	this.includes = {
+		consts: [],
+		functions: [],
+		structs: []
+	};
+	
+	this.attributes = {};
+	
+	this.prefixCode = [
+		"#ifdef GL_EXT_shader_texture_lod",
+
+		"	#define texCube(a, b) textureCube(a, b)",
+		"	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
+
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
+
+		"#else",
+
+		"	#define texCube(a, b) textureCube(a, b)",
+		"	#define texCubeBias(a, b, c) textureCube(a, b, c)",
+
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2D(a, b, c)",
+
+		"#endif",
+
+		"#include <packing>"
+
+	].join( "\n" );
+	
+	this.parsCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.code = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.nodeCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.resultCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.finalCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.inputs = {
+		uniforms: {
+			list: [],
+			vertex: [],
+			fragment: []
+		},
+		vars: {
+			varying: [],
+			vertex: [],
+			fragment: []
+		}
+	};
+	
+	// send to material
+	
+	this.defines = {};
+	
+	this.uniforms = {};
+	
+	this.extensions = {};
+	
+	this.updaters = [];
+	
+	this.nodes = [];
+	
+	// --
+	
+	this.parsing = false;
+	this.optimize = true;
+
+	this.update();
+
+};
+
+NodeBuilder.prototype = {
+
+	constructor: NodeBuilder,
+
+	build: function( vertex, fragment ) {
+		
+		this.buildShader( 'vertex', vertex );
+		this.buildShader( 'fragment', fragment );
+		
+		if ( this.requires.uv[ 0 ] ) {
+
+			this.addVaryCode( 'varying vec2 vUv;' );
+		
+			this.addVertexFinalCode( 'vUv = uv;' );
+
+		}
+		
+		if ( this.requires.uv[ 1 ] ) {
+
+			this.addVaryCode( 'varying vec2 vUv2;' );
+			this.addVertexParsCode( 'attribute vec2 uv2;' );
+
+			this.addVertexFinalCode( 'vUv2 = uv2;' );
+
+		}
+		
+		if ( this.requires.color[ 0 ] ) {
+
+			this.addVaryCode( 'varying vec4 vColor;' );
+			this.addVertexParsCode( 'attribute vec4 color;' );
+
+			this.addVertexFinalCode( 'vColor = color;' );
+
+		}
+		
+		if ( this.requires.color[ 1 ] ) {
+
+			this.addVaryCode( 'varying vec4 vColor2;' );
+			this.addVertexParsCode( 'attribute vec4 color2;' );
+
+			this.addVertexFinalCode( 'vColor2 = color2;' );
+
+		}
+		
+		if ( this.requires.position ) {
+
+			this.addVaryCode( 'varying vec3 vPosition;' );
+
+			this.addVertexFinalCode( 'vPosition = transformed;' );
+
+		}
+		
+		if ( this.requires.worldPosition ) {
+
+			this.addVaryCode( 'varying vec3 vWPosition;' );
+			
+			this.addVertexFinalCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
+
+		}
+		
+		if ( this.requires.normal ) {
+
+			this.addVaryCode( 'varying vec3 vObjectNormal;' );
+
+			this.addVertexFinalCode( 'vObjectNormal = normal;' );
+
+		}
+		
+		if ( this.requires.worldNormal ) {
+
+			this.addVaryCode( 'varying vec3 vWNormal;' );
+
+			this.addVertexFinalCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
+
+		}
+		
+		return this;
+		
+	},
+	
+	buildShader: function( shader, node ) {
+		
+		this.resultCode[shader] = node.build( this.setShader( shader ), 'v4' );
+		
+	},
+	
+	setMaterial: function( material, renderer ) {
+		
+		this.material = material;
+		this.renderer = renderer;
+		
+		this.requires.lights = material.lights;
+		this.requires.fog = material.fog;
+		
+		return this;
+		
+	},
+	
+	addCache: function ( name, context ) {
+
+		this.caches.push( {
+			name: name || '',
+			context: context || {}
+		} );
+
+		return this.update();
+
+	},
+
+	removeCache: function () {
+
+		this.caches.pop();
+
+		return this.update();
+
+	},
+
+	addSlot: function ( name ) {
+
+		this.slots.push( {
+			name: name || ''
+		} );
+
+		return this.update();
+
+	},
+
+	removeSlot: function () {
+
+		this.slots.pop();
+
+		return this.update();
+
+	},
+
+	
+	addVertexCode: function ( code ) {
+
+		this.addCode( code, 'vertex' );
+
+	},
+
+	addFragmentCode: function ( code ) {
+
+		this.addCode( code, 'fragment' );
+
+	},
+	
+	addCode: function ( code, shader ) {
+
+		this.code[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVertexNodeCode: function ( code ) {
+
+		this.addNodeCode( code, 'vertex' );
+
+	},
+
+	addFragmentNodeCode: function ( code ) {
+
+		this.addNodeCode( code, 'fragment' );
+
+	},
+	
+	addNodeCode: function ( code, shader ) {
+
+		this.nodeCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	clearNodeCode: function ( shader ) {
+
+		shader = shader || this.shader;
+	
+		var code = this.nodeCode[shader];
+		
+		this.nodeCode[shader] = '';
+
+		return code;
+		
+	},
+	
+	clearVertexNodeCode: function (  ) {
+
+		return this.clearNodeCode( 'vertex' );
+
+	},
+	
+	clearFragmentNodeCode: function (  ) {
+
+		return this.clearNodeCode( 'fragment' );
+
+	},
+	
+	addVertexFinalCode: function ( code ) {
+
+		this.addFinalCode( code, 'vertex' );
+
+	},
+
+	addFragmentFinalCode: function ( code ) {
+
+		this.addFinalCode( code, 'fragment' );
+
+	},
+	
+	addFinalCode: function ( code, shader ) {
+
+		this.finalCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVertexParsCode: function ( code ) {
+
+		this.addParsCode( code, 'vertex' );
+
+	},
+	
+	addFragmentParsCode: function ( code ) {
+
+		this.addParsCode( code, 'fragment' );
+
+	},
+	
+	addParsCode: function ( code, shader ) {
+
+		this.parsCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVaryCode: function ( code ) {
+
+		this.addVertexParsCode( code );
+		this.addFragmentParsCode( code );
+
+	},
+	
+	
+	isCache: function ( name ) {
+
+		var i = this.caches.length;
+
+		while ( i -- ) {
+
+			if ( this.caches[ i ].name === name ) return true;
+
+		}
+
+		return false;
+
+	},
+
+	isSlot: function ( name ) {
+
+		var i = this.slots.length;
+
+		while ( i -- ) {
+
+			if ( this.slots[ i ].name === name ) return true;
+
+		}
+
+		return false;
+
+	},
+
+	update: function () {
+
+		var cache = this.caches[ this.caches.length - 1 ];
+		var slot = this.slots[ this.slots.length - 1 ];
+
+		this.slot = slot ? slot.name : '';
+		this.cache = cache ? cache.name : '';
+		this.context = cache ? cache.context : {};
+
+		return this;
+
+	},
+
+	define: function ( name, value ) {
+
+		this.defines[ name ] = value === undefined ? 1 : value;
+
+	},
+	
+	isDefined: function ( name ) {
+
+		return this.defines[ name ] !== undefined;
+
+	},
+
+	getVar: function ( uuid, type, ns, shader ) {
+
+		shader = shader || 'varying';
+	
+		var vars = this.getVars(shader),
+			data = vars[ uuid ];
+
+		if ( ! data ) {
+
+			var index = vars.length,
+				name = ns ? ns : 'nVv' + index;
+
+			data = { name: name, type: type };
+
+			vars.push( data );
+			vars[ uuid ] = data;
+
+		}
+
+		return data;
+
+	},
+	
+	getTempVar: function ( uuid, type, ns ) {
+
+		return this.getVar( uuid, type, ns, this.shader );
+
+	},
+	
+	getAttribute: function ( name, type ) {
+
+		if ( ! this.attributes[ name ] ) {
+
+			var varying = this.getVar( name, type );
+
+			this.addVertexParsCode( 'attribute ' + type + ' ' + name + ';' );
+			this.addVertexFinalCode( varying.name + ' = ' + name + ';' );
+
+			this.attributes[ name ] = { varying: varying, name: name, type: type };
+
+		}
+
+		return this.attributes[ name ];
+
+	},
+	
+	getCode: function( shader ) {
+		
+		return [
+			this.prefixCode,
+			this.parsCode[ shader ],
+			this.getVarListCode( this.getVars('varying'), 'varying' ),
+			this.getVarListCode( this.inputs.uniforms[shader], 'uniform' ),
+			this.getIncludesCode( 'consts', shader ),
+			this.getIncludesCode( 'structs', shader ),
+			this.getIncludesCode( 'functions', shader ),
+			'void main() {',
+				this.getVarListCode( this.getVars(shader) ),
+				this.code[ shader ], 
+				this.resultCode[ shader ],
+				this.finalCode[ shader ],
+			'}'
+		].join( "\n" );
+		
+	},
+	
+	getVarListCode: function ( vars, prefix ) {
+
+		prefix = prefix || '';
+	
+		var code = '';
+
+		for ( var i = 0, l = vars.length; i < l; ++ i ) {
+
+			var nVar = vars[i],
+				type = nVar.type,
+				name = nVar.name;
+			
+			var formatType = this.getFormatByType( type );
+
+			if ( formatType === undefined ) {
+				
+				throw new Error( "Node pars " + formatType + " not found." );
+				
+			}
+
+			code += prefix + ' ' + formatType + ' ' + name + ';\n';
+
+		}
+
+		return code;
+
+	},
+	
+	getVars: function ( shader ) {
+
+		return this.inputs.vars[ shader || this.shader ];
+
+	},
+	
+	getNodeData: function ( node ) {
+
+		var uuid = node.isNode ? node.uuid : node;
+	
+		return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
+
+	},
+	
+	createUniform: function ( shader, type, node, ns, needsUpdate ) {
+
+		var uniforms = this.inputs.uniforms,
+			index = uniforms.list.length;
+
+		var uniform = new NodeUniform( {
+			type: type,
+			name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
+			node: node,
+			needsUpdate: needsUpdate
+		} );
+
+		uniforms.list.push( uniform );
+
+		uniforms[shader].push( uniform );
+		uniforms[shader][ uniform.name ] = uniform;
+		
+		this.uniforms[ uniform.name ] = uniform;
+		
+		return uniform;
+
+	},
+	
+	createVertexUniform: function ( type, node, ns, needsUpdate ) {
+
+		return this.createUniform( 'vertex', type, node, ns, needsUpdate );
+
+	},
+	
+	createFragmentUniform: function ( type, node, ns, needsUpdate ) {
+
+		return this.createUniform( 'fragment', type, node, ns, needsUpdate );
+
+	},
+	
+	include: function ( node, parent, source ) {
+
+		var includesStruct;
+
+		node = typeof node === 'string' ? NodeLib.get( node ) : node;
+
+		if ( node instanceof FunctionNode ) {
+
+			includesStruct = this.includes.functions;
+
+		} else if ( node instanceof ConstNode ) {
+
+			includesStruct = this.includes.consts;
+			
+		} else if ( node instanceof StructNode ) {
+
+			includesStruct = this.includes.structs;
+
+		}
+		
+		var includes = includesStruct[ this.shader ] = includesStruct[ this.shader ] || [];
+
+		if (node) {
+		
+			var included = includes[ node.name ];
+
+			if ( ! included ) {
+
+				included = includes[ node.name ] = {
+					node: node,
+					deps: []
+				};
+
+				includes.push( included );
+
+				included.src = node.build( this, 'source' );
+
+			}
+
+			if ( node instanceof FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
+
+				includes[ parent.name ].deps.push( node );
+
+				if ( node.includes && node.includes.length ) {
+
+					var i = 0;
+
+					do {
+
+						this.include( node.includes[ i ++ ], parent );
+
+					} while ( i < node.includes.length );
+
+				}
+
+			}
+
+			if ( source ) {
+
+				included.src = source;
+
+			}
+			
+			return node.name;
+			
+		} else {
+			
+			throw new Error("Include not found.");
+			
+		}
+
+	},
+
+	colorToVectorProperties: function ( color ) {
+
+		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
+
+	},
+	
+	colorToVector: function ( color ) {
+
+		return color.replace( /c/g, 'v3' );
+
+	},
+
+	getIncludes: function ( type, shader ) {
+
+		return this.includes[type][shader || this.shader];
+
+	},
+	
+	getIncludesCode: function () {
+
+		function sortByPosition( a, b ) {
+
+			return a.deps.length - b.deps.length;
+
+		}
+
+		return function getIncludesCode( type, shader ) {
+
+			var includes = this.getIncludes( type, shader );
+	
+			if ( ! includes ) return '';
+
+			var code = '', 
+				includes = includes.sort( sortByPosition );
+
+			for ( var i = 0; i < includes.length; i ++ ) {
+
+				if ( includes[ i ].src ) code += includes[ i ].src + '\n';
+
+			}
+
+			return code;
+
+		};
+
+	}(),
+	
+	getConstructorFromLength: function ( len ) {
+
+		return constructors[ len - 1 ];
+
+	},
+
+	isTypeMatrix: function ( format ) {
+
+		return /^m/.test( format );
+
+	},
+
+	getTypeLength: function ( type ) {
+
+		if ( type === 'f' ) return 1;
+	
+		return parseInt( this.colorToVector( type ).substr( 1 ) );
+
+	},
+
+	getTypeFromLength: function ( len ) {
+
+		if ( len === 1 ) return 'f';
+
+		return 'v' + len;
+
+	},
+	
+	findNode: function() {
+		
+		for(var i = 0; i < arguments.length; i++) {
+			
+			var nodeCandidate = arguments[i];
+			
+			if (nodeCandidate !== undefined && nodeCandidate.isNode) {
+				
+				return nodeCandidate;
+				
+			}
+			
+		}
+		
+	},
+	
+	resolve: function() {
+		
+		for(var i = 0; i < arguments.length; i++) {
+			
+			var nodeCandidate = arguments[i];
+			
+			if (nodeCandidate !== undefined) {
+				
+				if (nodeCandidate.isNode) {
+				
+					return nodeCandidate;
+					
+				} else if (nodeCandidate.isTexture) {
+					
+					switch( nodeCandidate.mapping ) {
+					
+						case THREE.CubeReflectionMapping:
+						case THREE.CubeRefractionMapping:
+
+							return new CubeTextureNode( nodeCandidate );
+
+							break;
+						
+						case THREE.CubeUVReflectionMapping:
+						case THREE.CubeUVRefractionMapping:
+
+							return new TextureCubeNode( new TextureNode( nodeCandidate ) );
+
+							break;
+							
+						default:
+						
+							return new TextureNode( nodeCandidate );
+						
+					}
+					
+				} else if (nodeCandidate.isVector2) {
+					
+					return new Vector2Node( nodeCandidate );
+					
+				} else if (nodeCandidate.isVector3) {
+					
+					return new Vector3Node( nodeCandidate );
+					
+				} else if (nodeCandidate.isVector4) {
+					
+					return new Vector4Node( nodeCandidate );
+					
+				}
+				
+			}
+			
+		}
+		
+	},
+
+	format: function ( code, from, to ) {
+
+		var typeToType = this.colorToVector( to + ' = ' + from );
+
+		switch ( typeToType ) {
+
+			case 'f = v2': return code + '.x';
+			case 'f = v3': return code + '.x';
+			case 'f = v4': return code + '.x';
+			case 'f = i': return 'float( ' + code + ' )';
+
+			case 'v2 = f': return 'vec2( ' + code + ' )';
+			case 'v2 = v3': return code + '.xy';
+			case 'v2 = v4': return code + '.xy';
+			case 'v2 = i': return 'vec2( float( ' + code + ' ) )';
+
+			case 'v3 = f': return 'vec3( ' + code + ' )';
+			case 'v3 = v2': return 'vec3( ' + code + ', 0.0 )';
+			case 'v3 = v4': return code + '.xyz';
+			case 'v3 = i': return 'vec2( float( ' + code + ' ) )';
+
+			case 'v4 = f': return 'vec4( ' + code + ' )';
+			case 'v4 = v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
+			case 'v4 = v3': return 'vec4( ' + code + ', 1.0 )';
+			case 'v4 = i': return 'vec4( float( ' + code + ' ) )';
+
+			case 'i = f': return 'int( ' + code + ' )';
+			case 'i = v2': return 'int( ' + code + '.x )';
+			case 'i = v3': return 'int( ' + code + '.x )';
+			case 'i = v4': return 'int( ' + code + '.x )';
+
+		}
+
+		return code;
+
+	},
+
+	getTypeByFormat: function ( format ) {
+
+		return convertFormatToType[ format ] || format;
+
+	},
+	
+	getFormatByType: function ( type ) {
+
+		return convertTypeToFormat[ type ] || type;
+
+	},
+
+	getUuid: function ( uuid, useCache ) {
+
+		useCache = useCache !== undefined ? useCache : true;
+
+		if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
+
+		return uuid;
+
+	},
+
+	getElementByIndex: function ( index ) {
+
+		return elements[ index ];
+
+	},
+
+	getIndexByElement: function ( elm ) {
+
+		return elements.indexOf( elm );
+
+	},
+
+	isShader: function ( shader ) {
+
+		return this.shader === shader;
+
+	},
+
+	setShader: function ( shader ) {
+
+		this.shader = shader;
+
+		return this;
+
+	},
+	
+	mergeUniform: function ( uniforms ) {
+
+		for ( var name in uniforms ) {
+
+			this.uniforms[ name ] = uniforms[ name ];
+
+		}
+
+	},
+
+	getTexelDecodingFunctionFromTexture: function( code, texture ) {
+
+		var gammaOverrideLinear = this.getTextureEncodingFromMap( texture, this.context.gamma && ( this.renderer ? this.renderer.gammaInput : false ) )
+
+		return this.getTexelDecodingFunction( code, gammaOverrideLinear );
+
+	},
+
+	getTexelDecodingFunction: function( value, encoding ) {
+
+		var components = this.getEncodingComponents( encoding );
+
+		return components[ 0 ] + 'ToLinear' + components[ 1 ].replace( 'value', value );
+
+	},
+
+	getTexelEncodingFunction: function( value, encoding ) {
+
+		var components = this.getEncodingComponents( encoding );
+
+		return 'LinearTo' + components[ 0 ] + components[ 1 ].replace( 'value', value );
+
+	},
+
+	getEncodingComponents: function( encoding ) {
+
+		switch ( encoding ) {
+
+			case THREE.LinearEncoding:
+				return [ 'Linear', '( value )' ];
+			case THREE.sRGBEncoding:
+				return [ 'sRGB', '( value )' ];
+			case THREE.RGBEEncoding:
+				return [ 'RGBE', '( value )' ];
+			case THREE.RGBM7Encoding:
+				return [ 'RGBM', '( value, 7.0 )' ];
+			case THREE.RGBM16Encoding:
+				return [ 'RGBM', '( value, 16.0 )' ];
+			case THREE.RGBDEncoding:
+				return [ 'RGBD', '( value, 256.0 )' ];
+			case THREE.GammaEncoding:
+				return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
+			default:
+				throw new Error( 'unsupported encoding: ' + encoding );
+
+		}
+
+	},
+
+	getEncodingComponents: function( encoding ) {
+
+		switch ( encoding ) {
+
+			case THREE.LinearEncoding:
+				return [ 'Linear', '( value )' ];
+			case THREE.sRGBEncoding:
+				return [ 'sRGB', '( value )' ];
+			case THREE.RGBEEncoding:
+				return [ 'RGBE', '( value )' ];
+			case THREE.RGBM7Encoding:
+				return [ 'RGBM', '( value, 7.0 )' ];
+			case THREE.RGBM16Encoding:
+				return [ 'RGBM', '( value, 16.0 )' ];
+			case THREE.RGBDEncoding:
+				return [ 'RGBD', '( value, 256.0 )' ];
+			case THREE.GammaEncoding:
+				return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
+			default:
+				throw new Error( 'unsupported encoding: ' + encoding );
+
+		}
+
+	},
+	
+	getTextureEncodingFromMap: function ( map, gammaOverrideLinear ) {
+
+		var encoding;
+
+		if ( ! map ) {
+
+			encoding = THREE.LinearEncoding;
+
+		} else if ( map.isTexture ) {
+
+			encoding = map.encoding;
+
+		} else if ( map.isWebGLRenderTarget ) {
+
+			console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
+			encoding = map.texture.encoding;
+
+		}
+
+		// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
+		if ( encoding === THREE.LinearEncoding && gammaOverrideLinear ) {
+
+			encoding = THREE.GammaEncoding;
+
+		}
+
+		return encoding;
+
+	}
+
+};
+
+export { NodeBuilder };

+ 42 - 0
examples/js/nodes/core/NodeFrame.js

@@ -0,0 +1,42 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+function NodeFrame( time ) {
+
+	this.time = time !== undefined ? time : 0;
+
+	this.frameId = 0;
+
+};
+
+NodeFrame.prototype = {
+
+	constructor: NodeFrame,
+
+	update: function ( delta ) {
+
+		++this.frameId;
+
+		this.time += delta;
+		this.delta = delta;
+
+		return this;
+
+	},
+	
+	updateNode: function ( node ) {
+
+		if ( node.frameId === this.frameId ) return this;
+
+		node.updateFrame( this );
+
+		node.frameId = this.frameId;
+
+		return this;
+
+	}
+	
+};
+
+export { NodeFrame };

+ 68 - 0
examples/js/nodes/core/NodeLib.js

@@ -0,0 +1,68 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+var NodeLib = {
+
+	nodes: {},
+	keywords: {},
+
+	add: function ( node ) {
+
+		this.nodes[ node.name ] = node;
+
+	},
+
+	addKeyword: function ( name, callback, cache ) {
+
+		cache = cache !== undefined ? cache : true;
+
+		this.keywords[ name ] = { callback: callback, cache: cache };
+
+	},
+
+	remove: function ( node ) {
+
+		delete this.nodes[ node.name ];
+
+	},
+
+	removeKeyword: function ( name ) {
+
+		delete this.keywords[ name ];
+
+	},
+
+	get: function ( name ) {
+
+		return this.nodes[ name ];
+
+	},
+
+	getKeyword: function ( name, material ) {
+
+		return this.keywords[ name ].callback.call( this, material );
+
+	},
+
+	getKeywordData: function ( name ) {
+
+		return this.keywords[ name ];
+
+	},
+
+	contains: function ( name ) {
+
+		return this.nodes[ name ] != undefined;
+
+	},
+
+	containsKeyword: function ( name ) {
+
+		return this.keywords[ name ] != undefined;
+
+	}
+
+};
+
+export { NodeLib };

+ 9 - 2
examples/js/nodes/NodeUniform.js → examples/js/nodes/core/NodeUniform.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodeUniform = function ( params ) {
+function NodeUniform( params ) {
 
 	params = params || {};
 
@@ -13,17 +13,24 @@ THREE.NodeUniform = function ( params ) {
 
 };
 
-Object.defineProperties( THREE.NodeUniform.prototype, {
+Object.defineProperties( NodeUniform.prototype, {
+	
 	value: {
+		
 		get: function () {
 
 			return this.node.value;
 
 		},
+		
 		set: function ( val ) {
 
 			this.node.value = val;
 
 		}
+		
 	}
+	
 } );
+
+export { NodeUniform };

+ 75 - 0
examples/js/nodes/core/NodeUtils.js

@@ -0,0 +1,75 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+var NodeUtils = {
+
+	elements: [ 'x', 'y', 'z', 'w' ],
+
+	addShortcuts: function () {
+
+		function applyShortcut( proxy, property, subProperty ) {
+
+			if ( subProperty ) {
+
+				return {
+					
+					get: function () {
+
+						return this[ proxy ][ property ][ subProperty ];
+
+					},
+					
+					set: function ( val ) {
+
+						this[ proxy ][ property ][ subProperty ] = val;
+
+					}
+					
+				};
+
+			} else {
+
+				return {
+					
+					get: function () {
+
+						return this[ proxy ][ property ];
+
+					},
+					
+					set: function ( val ) {
+
+						this[ proxy ][ property ] = val;
+
+					}
+					
+				};
+
+			}
+
+		}
+
+		return function addShortcuts( proto, proxy, list ) {
+
+			var shortcuts = {};
+
+			for ( var i = 0; i < list.length; ++ i ) {
+
+				var data = list[ i ].split( "." ),
+					property = data[0],
+					subProperty = data[1];
+
+				shortcuts[ property ] = applyShortcut( proxy, property, subProperty );
+
+			}
+
+			Object.defineProperties( proto, shortcuts );
+
+		};
+
+	}()
+	
+};
+
+export { NodeUtils };

+ 107 - 0
examples/js/nodes/core/StructNode.js

@@ -0,0 +1,107 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+import { FunctionNode } from './FunctionNode.js';
+
+function StructNode( src ) {
+
+	TempNode.call( this);
+
+	this.eval( src );
+
+};
+
+StructNode.rDeclaration = /^struct\s*([a-z_0-9]+)\s*{\s*((.|\n)*?)}/img;
+StructNode.rProperties = /\s*(\w*?)\s*(\w*?)(\=|\;)/img;
+
+StructNode.prototype = Object.create( TempNode.prototype );
+StructNode.prototype.constructor = StructNode;
+StructNode.prototype.nodeType = "Struct";
+
+StructNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.name );
+
+};
+
+StructNode.prototype.getInputByName = function ( name ) {
+
+	var i = this.inputs.length;
+
+	while ( i -- ) {
+
+		if ( this.inputs[ i ].name === name )
+			return this.inputs[ i ];
+
+	}
+
+};
+
+StructNode.prototype.generate = function ( builder, output ) {
+
+	if ( output === 'source' ) {
+
+		return this.src + ';';
+
+	} else {
+
+		return builder.format( "(" + src + ")", this.getType( builder ), output );
+
+	}
+
+};
+
+StructNode.prototype.eval = function ( src ) {
+
+	this.src = src || '';
+	
+	this.inputs = [];
+	
+	var declaration = StructNode.rDeclaration.exec( this.src );
+	
+	if (declaration) {
+		
+		var properties = declaration[2], matchType, matchName;
+		
+		while ( matchType = FunctionNode.rProperties.exec( properties ) ) {
+			
+			matchName = FunctionNode.rProperties.exec( properties )[0];
+			
+			this.inputs.push( {
+				name: matchName,
+				type: matchType
+			} );
+			
+		}
+		
+		this.name = declaration[1];
+
+	} else {
+		
+		this.name = '';
+		
+	}
+	
+	this.type = this.name;
+
+};
+
+StructNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.src = this.src;
+
+	}
+
+	return data;
+
+};
+
+export { StructNode };

+ 133 - 0
examples/js/nodes/core/TempNode.js

@@ -0,0 +1,133 @@
+/**
+ * Automatic node cache
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function TempNode( type, params ) {
+
+	GLNode.call( this, type );
+
+	params = params || {};
+
+	this.shared = params.shared !== undefined ? params.shared : true;
+	this.unique = params.unique !== undefined ? params.unique : false;
+
+};
+
+TempNode.prototype = Object.create( GLNode.prototype );
+TempNode.prototype.constructor = TempNode;
+
+TempNode.prototype.build = function ( builder, output, uuid, ns ) {
+
+	output = output || this.getType( builder );
+
+	if ( this.isShared( builder, output ) ) {
+
+		var isUnique = this.isUnique( builder, output );
+
+		if ( isUnique && this.constructor.uuid === undefined ) {
+
+			this.constructor.uuid = THREE.Math.generateUUID();
+
+		}
+
+		uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
+
+		var data = builder.getNodeData( uuid );
+
+		if ( builder.parsing ) {
+
+			if ( data.deps || 0 > 0 ) {
+
+				this.appendDepsNode( builder, data, output );
+
+				return this.generate( builder, type, uuid );
+
+			}
+
+			return GLNode.prototype.build.call( this, builder, output, uuid );
+
+		} else if ( isUnique ) {
+
+			data.name = data.name || GLNode.prototype.build.call( this, builder, output, uuid );
+
+			return data.name;
+
+		} else if ( ! builder.optimize || data.deps == 1 ) {
+
+			return GLNode.prototype.build.call( this, builder, output, uuid );
+
+		}
+
+		uuid = this.getUuid( false );
+
+		var name = this.getTemp( builder, uuid ),
+			type = data.output || this.getType( builder );
+
+		if ( name ) {
+
+			return builder.format( name, type, output );
+
+		} else {
+
+			name = TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
+
+			var code = this.generate( builder, type, uuid );
+
+			builder.addNodeCode( name + ' = ' + code + ';' );
+
+			return builder.format( name, type, output );
+
+		}
+
+	}
+
+	return GLNode.prototype.build.call( this, builder, output, uuid );
+
+};
+
+TempNode.prototype.isShared = function ( builder, output ) {
+
+	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
+
+};
+
+TempNode.prototype.isUnique = function ( builder, output ) {
+
+	return this.unique;
+
+};
+
+TempNode.prototype.getUuid = function ( unique ) {
+
+	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
+
+	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
+
+	return uuid;
+
+};
+
+TempNode.prototype.getTemp = function ( builder, uuid ) {
+
+	uuid = uuid || this.uuid;
+
+	var tempVar = builder.getVars()[uuid]
+	
+	return tempVar ? tempVar.name : undefined;
+	
+};
+
+TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
+
+	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
+
+	uuid = uuid || this.uuid;
+
+	return builder.getTempVar( uuid, type || this.getType( builder ), ns ).name;
+
+};
+
+export { TempNode };

+ 66 - 0
examples/js/nodes/core/VarNode.js

@@ -0,0 +1,66 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function VarNode( type, value ) {
+
+	GLNode.call( this, type );
+	
+	this.value = value;
+
+};
+
+VarNode.prototype = Object.create( GLNode.prototype );
+VarNode.prototype.constructor = VarNode;
+VarNode.prototype.nodeType = "Var";
+
+VarNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.type );
+
+};
+
+VarNode.prototype.generate = function ( builder, output ) {
+
+	var varying = builder.getVar( this.uuid, this.type );
+
+	if ( this.value && builder.isShader( 'vertex' ) ) {
+
+		builder.addNodeCode( varying.name + ' = ' + this.value.build( builder, this.getType( builder ) ) + ';' );
+
+	}
+	
+	return builder.format( varying.name, this.getType( builder ), output );
+
+};
+
+VarNode.prototype.copy = function ( source ) {
+	
+	GLNode.prototype.copy.call( this, source );
+	
+	this.type = source.type;
+	this.value = source.value;
+	
+};
+
+VarNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.type = this.type;
+
+		if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { VarNode };

+ 168 - 0
examples/js/nodes/effects/BlurNode.js

@@ -0,0 +1,168 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { Vector2Node } from '../inputs/Vector2Node.js';
+import { UVNode } from '../accessors/UVNode.js';
+
+function BlurNode( value, uv, radius, size ) {
+
+	TempNode.call( this, 'v4' );
+
+	this.value = value;
+	this.uv = uv || new UVNode();
+	this.radius = new Vector2Node( 1, 1 );
+
+	this.size = size;
+
+	this.blurX = true;
+	this.blurY = true;
+
+	this.horizontal = new FloatNode( 1 / 64 );
+	this.vertical = new FloatNode( 1 / 64 );
+
+};
+
+BlurNode.Nodes = (function() {
+	
+	var blurX = new 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;",
+		"}"
+	].join( "\n" ) );
+	
+	var blurY = new 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;",
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		blurX: blurX,
+		blurY: blurY
+	};
+	
+})();
+
+
+BlurNode.prototype = Object.create( TempNode.prototype );
+BlurNode.prototype.constructor = BlurNode;
+BlurNode.prototype.nodeType = "Blur";
+
+BlurNode.prototype.updateFrame = function ( frame ) {
+
+	if ( this.size ) {
+
+		this.horizontal.value = this.radius.x / this.size.x;
+		this.vertical.value = this.radius.y / this.size.y;
+
+	} else if ( this.value.value && this.value.value.image ) {
+
+		var image = this.value.value.image;
+
+		this.horizontal.value = this.radius.x / image.width;
+		this.vertical.value = this.radius.y / image.height;
+
+	}
+
+};
+
+BlurNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		var blurCode = [], code;
+
+		var blurX = builder.include( BlurNode.Nodes.blurX ),
+			blurY = builder.include( BlurNode.Nodes.blurY );
+		
+		if ( this.blurX ) {
+
+			blurCode.push( blurX + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.horizontal.build( builder, 'f' ) + ' )' );
+
+		}
+
+		if ( this.blurY ) {
+
+			blurCode.push( blurY + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.vertical.build( builder, 'f' ) + ' )' );
+
+		}
+
+		if ( blurCode.length == 2 ) code = '( ' + blurCode.join( ' + ' ) + '/ 2.0 )';
+		else if ( blurCode.length ) code = '( ' + blurCode[ 0 ] + ' )';
+		else code = 'vec4( 0.0 )';
+
+		return builder.format( code, this.getType( builder ), output );
+
+	} else {
+
+		console.warn( "THREE.BlurNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+BlurNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	this.uv = source.uv;
+	this.radius = source.radius;
+
+	if ( source.size !== undefined ) this.size = new THREE.Vector2( source.size.x, source.size.y );
+
+	this.blurX = source.blurX;
+	this.blurY = source.blurY;
+					
+};
+
+BlurNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.uv = this.uv.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;
+
+};
+
+export { BlurNode };

+ 136 - 0
examples/js/nodes/effects/ColorAdjustmentNode.js

@@ -0,0 +1,136 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { LuminanceNode } from './LuminanceNode.js';
+
+function ColorAdjustmentNode( rgb, adjustment, method ) {
+
+	TempNode.call( this, 'v3' );
+
+	this.rgb = rgb;
+	this.adjustment = adjustment;
+
+	this.method = method || ColorAdjustmentNode.SATURATION;
+
+};
+
+ColorAdjustmentNode.Nodes = (function() {
+	
+	var hue = new FunctionNode( [
+		"vec3 hue(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" ) );
+	
+	var saturation = new FunctionNode( [
+		// Algorithm from Chapter 16 of OpenGL Shading Language
+		"vec3 saturation(vec3 rgb, float adjustment) {",
+		
+		"	vec3 intensity = vec3( luminance( rgb ) );",
+		
+		"	return mix( intensity, rgb, adjustment );",
+		
+		"}"
+	].join( "\n" ), [ LuminanceNode.Nodes.luminance ] ); // include LuminanceNode function
+	
+	var vibrance = new FunctionNode( [
+		// Shader by Evan Wallace adapted by @lo-th
+		"vec3 vibrance(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" ) );
+	
+	return {
+		hue: hue,
+		saturation: saturation,
+		vibrance: vibrance
+	};
+	
+})();
+
+ColorAdjustmentNode.SATURATION = 'saturation';
+ColorAdjustmentNode.HUE = 'hue';
+ColorAdjustmentNode.VIBRANCE = 'vibrance';
+ColorAdjustmentNode.BRIGHTNESS = 'brightness';
+ColorAdjustmentNode.CONTRAST = 'contrast';
+
+ColorAdjustmentNode.prototype = Object.create( TempNode.prototype );
+ColorAdjustmentNode.prototype.constructor = ColorAdjustmentNode;
+ColorAdjustmentNode.prototype.nodeType = "ColorAdjustment";
+
+ColorAdjustmentNode.prototype.generate = function ( builder, output ) {
+
+	var rgb = this.rgb.build( builder, 'v3' ),
+		adjustment = this.adjustment.build( builder, 'f' );
+
+	switch ( this.method ) {
+
+		case ColorAdjustmentNode.BRIGHTNESS:
+
+			return builder.format( '( ' + rgb + ' + ' + adjustment + ' )', this.getType( builder ), output );
+
+			break;
+
+		case ColorAdjustmentNode.CONTRAST:
+
+			return builder.format( '( ' + rgb + ' * ' + adjustment + ' )', this.getType( builder ), output );
+
+			break;
+
+	}
+
+	var method = builder.include( ColorAdjustmentNode.Nodes[this.method] );
+
+	return builder.format( method + '( ' + rgb + ', ' + adjustment + ' )', this.getType( builder ), output );
+
+};
+
+ColorAdjustmentNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.rgb = source.rgb;
+	this.adjustment = source.adjustment;
+	this.method = source.method;
+
+};
+
+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;
+
+};
+
+export { ColorAdjustmentNode };

+ 73 - 0
examples/js/nodes/effects/LuminanceNode.js

@@ -0,0 +1,73 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { ConstNode } from '../core/ConstNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+
+function LuminanceNode( rgb ) {
+
+	TempNode.call( this, 'f' );
+
+	this.rgb = rgb;
+
+};
+
+LuminanceNode.Nodes = (function() {
+	
+	var LUMA = new ConstNode( "vec3 LUMA vec3( 0.2125, 0.7154, 0.0721 )" );
+
+	var luminance = new FunctionNode( [
+		// Algorithm from Chapter 10 of Graphics Shaders
+		"float luminance( vec3 rgb ) {",
+		
+		"	return dot( rgb, LUMA );",
+		
+		"}"
+	].join( "\n" ), [ LUMA ] );
+
+	return {
+		LUMA: LUMA,
+		luminance: luminance
+	};
+	
+})();
+
+LuminanceNode.prototype = Object.create( TempNode.prototype );
+LuminanceNode.prototype.constructor = LuminanceNode;
+LuminanceNode.prototype.nodeType = "Luminance";
+
+LuminanceNode.prototype.generate = function ( builder, output ) {
+
+	var luminance = builder.include( LuminanceNode.Nodes.luminance );
+
+	return builder.format( luminance + '( ' + this.rgb.build( builder, 'v3' ) + ' )', this.getType( builder ), output );
+
+};
+
+LuminanceNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.rgb = source.rgb;
+	
+};
+
+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;
+
+};
+
+export { LuminanceNode };

+ 22 - 9
examples/js/nodes/inputs/ColorNode.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ColorNode = function ( color ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'c' );
+function ColorNode( color, g, b ) {
 
-	this.value = new THREE.Color( color || 0 );
+	InputNode.call( this, 'c' );
+
+	this.value = color instanceof THREE.Color ? color : new THREE.Color( color || 0, g, b );
 
 };
 
-THREE.ColorNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.ColorNode.prototype.constructor = THREE.ColorNode;
-THREE.ColorNode.prototype.nodeType = "Color";
+ColorNode.prototype = Object.create( InputNode.prototype );
+ColorNode.prototype.constructor = ColorNode;
+ColorNode.prototype.nodeType = "Color";
 
-THREE.NodeMaterial.addShortcuts( THREE.ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
+NodeUtils.addShortcuts( ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
 
-THREE.ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec3( " + this.r + ", " + this.g + ", " + this.b + " )", type, output );
 
 };
 
-THREE.ColorNode.prototype.toJSON = function ( meta ) {
+ColorNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+	
+};
+
+ColorNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -41,3 +52,5 @@ THREE.ColorNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ColorNode };

+ 33 - 28
examples/js/nodes/inputs/CubeTextureNode.js

@@ -2,27 +2,30 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.CubeTextureNode = function ( value, coord, bias ) {
+import { InputNode } from '../core/InputNode.js';
+import { ReflectNode } from '../accessors/ReflectNode.js';
 
-	THREE.InputNode.call( this, 'v4', { shared: true } );
+function CubeTextureNode( value, uv, bias ) {
+
+	InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
-	this.coord = coord || new THREE.ReflectNode();
+	this.uv = uv || new ReflectNode();
 	this.bias = bias;
 
 };
 
-THREE.CubeTextureNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.CubeTextureNode.prototype.constructor = THREE.CubeTextureNode;
-THREE.CubeTextureNode.prototype.nodeType = "CubeTexture";
+CubeTextureNode.prototype = Object.create( InputNode.prototype );
+CubeTextureNode.prototype.constructor = CubeTextureNode;
+CubeTextureNode.prototype.nodeType = "CubeTexture";
 
-THREE.CubeTextureNode.prototype.getTexture = function ( builder, output ) {
+CubeTextureNode.prototype.getTexture = function ( builder, output ) {
 
-	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
+	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 'tc' );
 
 };
 
-THREE.CubeTextureNode.prototype.generate = function ( builder, output ) {
+CubeTextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'samplerCube' ) {
 
@@ -31,39 +34,39 @@ THREE.CubeTextureNode.prototype.generate = function ( builder, output ) {
 	}
 
 	var cubetex = this.getTexture( builder, output );
-	var coord = this.coord.build( builder, 'v3' );
-	var bias = this.bias ? this.bias.build( builder, 'fv1' ) : undefined;
+	var uv = this.uv.build( builder, 'v3' );
+	var bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
-	if ( bias == undefined && builder.requires.bias ) {
+	if ( bias === undefined && builder.context.bias ) {
 
-		bias = builder.requires.bias.build( builder, 'fv1' );
+		bias = new builder.context.bias( this ).build( builder, 'f' );
 
 	}
 
 	var code;
 
-	if ( bias ) code = 'texCubeBias(' + cubetex + ',' + coord + ',' + bias + ')';
-	else code = 'texCube(' + cubetex + ',' + coord + ')';
-
-	if ( builder.isSlot( 'color' ) ) {
-
-		code = 'mapTexelToLinear(' + code + ')';
+	if ( bias ) code = 'texCubeBias( ' + cubetex + ', ' + uv + ', ' + bias + ' )';
+	else code = 'texCube( ' + cubetex + ', ' + uv + ' )';
 
-	} else if ( builder.isSlot( 'emissive' ) ) {
+	code = builder.getTexelDecodingFunctionFromTexture( code, this.value );
 
-		code = 'emissiveMapTexelToLinear(' + code + ')';
-
-	} else if ( builder.isSlot( 'environment' ) ) {
+	return builder.format( code, this.type, output );
 
-		code = 'envMapTexelToLinear(' + code + ')';
+};
 
-	}
+CubeTextureNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	if ( source.value ) this.value = source.value;
 
-	return builder.format( code, this.type, output );
+	this.uv = source.uv;
 
+	if ( source.bias ) this.bias = source.bias;
+	
 };
 
-THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
+CubeTextureNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -72,7 +75,7 @@ THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
 		data = this.createJSONNode( meta );
 
 		data.value = this.value.uuid;
-		data.coord = this.coord.toJSON( meta ).uuid;
+		data.uv = this.uv.toJSON( meta ).uuid;
 
 		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
 
@@ -81,3 +84,5 @@ THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { CubeTextureNode };

+ 19 - 9
examples/js/nodes/inputs/FloatNode.js

@@ -2,27 +2,35 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.FloatNode = function ( value ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'fv1' );
+function FloatNode( value ) {
+
+	InputNode.call( this, 'f' );
 
 	this.value = value || 0;
 
 };
 
-THREE.FloatNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.FloatNode.prototype.constructor = THREE.FloatNode;
-THREE.FloatNode.prototype.nodeType = "Float";
+FloatNode.prototype = Object.create( InputNode.prototype );
+FloatNode.prototype.constructor = FloatNode;
+FloatNode.prototype.nodeType = "Float";
 
-THREE.FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
-	var val = this.value;
+	return builder.format( this.value + ( this.value % 1 ? '' : '.0' ), type, output );
 
-	return builder.format( Math.floor( val ) !== val ? val : val + ".0", type, output );
+};
 
+FloatNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
 };
 
-THREE.FloatNode.prototype.toJSON = function ( meta ) {
+FloatNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -39,3 +47,5 @@ THREE.FloatNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { FloatNode };

+ 19 - 7
examples/js/nodes/inputs/IntNode.js

@@ -2,25 +2,35 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.IntNode = function ( value ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'iv1' );
+function IntNode( value ) {
+
+	InputNode.call( this, 'i' );
 
 	this.value = Math.floor( value || 0 );
 
 };
 
-THREE.IntNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.IntNode.prototype.constructor = THREE.IntNode;
-THREE.IntNode.prototype.nodeType = "Int";
+IntNode.prototype = Object.create( InputNode.prototype );
+IntNode.prototype.constructor = IntNode;
+IntNode.prototype.nodeType = "Int";
 
-THREE.IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( this.value, type, output );
 
 };
 
-THREE.IntNode.prototype.toJSON = function ( meta ) {
+IntNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
+};
+
+IntNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -37,3 +47,5 @@ THREE.IntNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { IntNode };

+ 40 - 9
examples/js/nodes/inputs/Matrix3Node.js

@@ -2,25 +2,56 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Matrix3Node = function ( matrix ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'm3' );
+function Matrix3Node( matrix ) {
+
+	InputNode.call( this, 'm3' );
 
 	this.value = matrix || new THREE.Matrix3();
 
 };
 
-THREE.Matrix3Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Matrix3Node.prototype.constructor = THREE.Matrix3Node;
-THREE.Matrix3Node.prototype.nodeType = "Matrix3";
+Matrix3Node.prototype = Object.create( InputNode.prototype );
+Matrix3Node.prototype.constructor = Matrix3Node;
+Matrix3Node.prototype.nodeType = "Matrix3";
+
+Object.defineProperties( Matrix3Node.prototype, {
+
+	elements: {
+		
+		set: function (val) {
+
+			this.value.elements = val;
+
+		},
+		
+		get: function () {
+
+			return this.value.elements;
+
+		}
+		
+	}
+
+} );
 
-THREE.Matrix3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Matrix3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "mat3( " + this.value.elements.join( ", " ) + " )", type, output );
 
 };
 
-THREE.Matrix3Node.prototype.toJSON = function ( meta ) {
+
+Matrix3Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.fromArray( source.elements );
+	
+};
+
+Matrix3Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -30,10 +61,10 @@ THREE.Matrix3Node.prototype.toJSON = function ( meta ) {
 
 		data.elements = this.value.elements.concat();
 
-		if ( this.readonly === true ) data.readonly = true;
-
 	}
 
 	return data;
 
 };
+
+export { Matrix3Node };

+ 39 - 9
examples/js/nodes/inputs/Matrix4Node.js

@@ -2,25 +2,55 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Matrix4Node = function ( matrix ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'm4' );
+function Matrix4Node( matrix ) {
+
+	InputNode.call( this, 'm4' );
 
 	this.value = matrix || new THREE.Matrix4();
 
 };
 
-THREE.Matrix4Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Matrix4Node.prototype.constructor = THREE.Matrix4Node;
-THREE.Matrix4Node.prototype.nodeType = "Matrix4";
+Matrix4Node.prototype = Object.create( InputNode.prototype );
+Matrix4Node.prototype.constructor = Matrix4Node;
+Matrix4Node.prototype.nodeType = "Matrix4";
+
+Object.defineProperties( Matrix4Node.prototype, {
+
+	elements: {
+		
+		set: function (val) {
+
+			this.value.elements = val;
 
-THREE.Matrix4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+		},
+		
+		get: function () {
+
+			return this.value.elements;
+
+		}
+		
+	}
+
+} );
+
+Matrix4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "mat4( " + this.value.elements.join( ", " ) + " )", type, output );
 
 };
 
-THREE.Matrix4Node.prototype.toJSON = function ( meta ) {
+Matrix4Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.scope.value.fromArray( source.elements );
+	
+};
+
+Matrix4Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -30,10 +60,10 @@ THREE.Matrix4Node.prototype.toJSON = function ( meta ) {
 
 		data.elements = this.value.elements.concat();
 
-		if ( this.readonly === true ) data.readonly = true;
-
 	}
 
 	return data;
 
 };
+
+export { Matrix4Node };

+ 57 - 0
examples/js/nodes/inputs/PropertyNode.js

@@ -0,0 +1,57 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { InputNode } from '../core/InputNode.js';
+ 
+function PropertyNode( object, property, type ) {
+
+	InputNode.call( this, type );
+	
+	this.object = object;
+	this.property = property;
+
+};
+
+PropertyNode.prototype = Object.create( InputNode.prototype );
+PropertyNode.prototype.constructor = PropertyNode;
+PropertyNode.prototype.nodeType = "Property";
+
+Object.defineProperties( PropertyNode.prototype, {
+
+	value: {
+		
+		get: function () {
+
+			return this.object[ this.property ];
+
+		},
+		
+		set: function ( val ) { 
+		
+			this.object[ this.property ] = val;
+		
+		}
+		
+	}
+
+} );
+
+PropertyNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value;
+		data.property = this.property;
+
+	}
+
+	return data;
+
+};
+
+export { PropertyNode };

+ 37 - 19
examples/js/nodes/inputs/ReflectorNode.js

@@ -1,38 +1,46 @@
-THREE.ReflectorNode = function ( mirror ) {
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
 
-	THREE.TempNode.call( this, 'v4' );
+import { TempNode } from '../core/TempNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+import { OperatorNode } from '../math/OperatorNode.js';
+import { TextureNode } from './TextureNode.js';
+import { Matrix4Node } from './Matrix4Node.js';
+
+function ReflectorNode( mirror ) {
+
+	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";
+ReflectorNode.prototype = Object.create( TempNode.prototype );
+ReflectorNode.prototype.constructor = ReflectorNode;
+ReflectorNode.prototype.nodeType = "Reflector";
 
-THREE.ReflectorNode.prototype.setMirror = function ( mirror ) {
+ReflectorNode.prototype.setMirror = function ( mirror ) {
 
 	this.mirror = mirror;
 
-	this.textureMatrix = new THREE.Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
+	this.textureMatrix = new Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
 
-	this.localPosition = new THREE.PositionNode( THREE.PositionNode.LOCAL );
+	this.localPosition = new PositionNode( PositionNode.LOCAL );
 
-	this.coord = new THREE.OperatorNode( this.textureMatrix, this.localPosition, THREE.OperatorNode.MUL );
-	this.coordResult = new THREE.OperatorNode( null, this.coord, THREE.OperatorNode.ADD );
+	this.uv = new OperatorNode( this.textureMatrix, this.localPosition, OperatorNode.MUL );
+	this.uvResult = new OperatorNode( null, this.uv, OperatorNode.ADD );
 
-	this.texture = new THREE.TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.coord, null, true );
+	this.texture = new TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.uv, null, true );
 
 };
 
-THREE.ReflectorNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
+ReflectorNode.prototype.generate = function ( builder, output ) {
+	
 	if ( builder.isShader( 'fragment' ) ) {
 
-		this.coordResult.a = this.offset;
-		this.texture.coord = this.offset ? this.coordResult : this.coord;
+		this.uvResult.a = this.offset;
+		this.texture.uv = this.offset ? this.uvResult : this.uv;
 
 		if ( output === 'sampler2D' ) {
 
@@ -46,13 +54,21 @@ THREE.ReflectorNode.prototype.generate = function ( builder, output ) {
 
 		console.warn( "THREE.ReflectorNode is not compatible with " + builder.shader + " shader." );
 
-		return builder.format( 'vec4(0.0)', this.type, output );
+		return builder.format( 'vec4( 0.0 )', this.type, output );
 
 	}
 
 };
 
-THREE.ReflectorNode.prototype.toJSON = function ( meta ) {
+ReflectorNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.scope.mirror = source.mirror;
+
+};
+
+ReflectorNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -69,3 +85,5 @@ THREE.ReflectorNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ReflectorNode };

+ 13 - 8
examples/js/nodes/inputs/ScreenNode.js

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

+ 36 - 29
examples/js/nodes/inputs/TextureNode.js

@@ -2,28 +2,32 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TextureNode = function ( value, coord, bias, project ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeBuilder } from '../core/NodeBuilder.js';
+import { UVNode } from '../accessors/UVNode.js';
 
-	THREE.InputNode.call( this, 'v4', { shared: true } );
+function TextureNode( value, uv, bias, project ) {
+
+	InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
-	this.coord = coord || new THREE.UVNode();
+	this.uv = uv || new UVNode();
 	this.bias = bias;
 	this.project = project !== undefined ? project : false;
 
 };
 
-THREE.TextureNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.TextureNode.prototype.constructor = THREE.TextureNode;
-THREE.TextureNode.prototype.nodeType = "Texture";
+TextureNode.prototype = Object.create( InputNode.prototype );
+TextureNode.prototype.constructor = TextureNode;
+TextureNode.prototype.nodeType = "Texture";
 
-THREE.TextureNode.prototype.getTexture = function ( builder, output ) {
+TextureNode.prototype.getTexture = function ( builder, output ) {
 
-	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
+	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
 
 };
 
-THREE.TextureNode.prototype.generate = function ( builder, output ) {
+TextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'sampler2D' ) {
 
@@ -31,13 +35,13 @@ THREE.TextureNode.prototype.generate = function ( builder, output ) {
 
 	}
 
-	var tex = this.getTexture( builder, output );
-	var coord = this.coord.build( builder, this.project ? 'v4' : 'v2' );
-	var bias = this.bias ? this.bias.build( builder, 'fv1' ) : undefined;
+	var tex = this.getTexture( builder, output ),
+		uv = this.uv.build( builder, this.project ? 'v4' : 'v2' ),
+		bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
-	if ( bias == undefined && builder.requires.bias ) {
+	if ( bias == undefined && builder.context.bias ) {
 
-		bias = builder.requires.bias.build( builder, 'fv1' );
+		bias = new builder.context.bias( this ).build( builder, 'f' );
 
 	}
 
@@ -46,28 +50,29 @@ THREE.TextureNode.prototype.generate = function ( builder, output ) {
 	if ( this.project ) method = 'texture2DProj';
 	else method = bias ? 'tex2DBias' : 'tex2D';
 
-	if ( bias ) code = method + '(' + tex + ',' + coord + ',' + bias + ')';
-	else code = method + '(' + tex + ',' + coord + ')';
-
-	if ( builder.isSlot( 'color' ) ) {
-
-		code = 'mapTexelToLinear(' + code + ')';
+	if ( bias ) code = method + '( ' + tex + ', ' + uv + ', ' + bias + ' )';
+	else code = method + '( ' + tex + ', ' + uv + ' )';
 
-	} else if ( builder.isSlot( 'emissive' ) ) {
+	code = builder.getTexelDecodingFunctionFromTexture( code, this.value );
 
-		code = 'emissiveMapTexelToLinear(' + code + ')';
-
-	} else if ( builder.isSlot( 'environment' ) ) {
+	return builder.format( code, this.type, output );
 
-		code = 'envMapTexelToLinear(' + code + ')';
+};
 
-	}
+TextureNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	if ( source.value ) this.value = source.value;
 
-	return builder.format( code, this.type, output );
+	this.uv = source.uv;
 
+	if ( source.bias ) this.bias = source.bias;
+	if ( source.project !== undefined ) this.project = source.project;
+	
 };
 
-THREE.TextureNode.prototype.toJSON = function ( meta ) {
+TextureNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -77,7 +82,7 @@ THREE.TextureNode.prototype.toJSON = function ( meta ) {
 
 		if ( this.value ) data.value = this.value.uuid;
 
-		data.coord = this.coord.toJSON( meta ).uuid;
+		data.uv = this.uv.toJSON( meta ).uuid;
 		data.project = this.project;
 
 		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
@@ -87,3 +92,5 @@ THREE.TextureNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { TextureNode };

+ 22 - 9
examples/js/nodes/inputs/Vector2Node.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector2Node = function ( x, y ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v2' );
+function Vector2Node( x, y ) {
 
-	this.value = new THREE.Vector2( x, y );
+	InputNode.call( this, 'v2' );
+
+	this.value = x instanceof THREE.Vector2 ? x : new THREE.Vector2( x, y );
 
 };
 
-THREE.Vector2Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector2Node.prototype.constructor = THREE.Vector2Node;
-THREE.Vector2Node.prototype.nodeType = "Vector2";
+Vector2Node.prototype = Object.create( InputNode.prototype );
+Vector2Node.prototype.constructor = Vector2Node;
+Vector2Node.prototype.nodeType = "Vector2";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector2Node.prototype, 'value', [ 'x', 'y' ] );
+NodeUtils.addShortcuts( Vector2Node.prototype, 'value', [ 'x', 'y' ] );
 
-THREE.Vector2Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector2Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec2( " + this.x + ", " + this.y + " )", type, output );
 
 };
 
-THREE.Vector2Node.prototype.toJSON = function ( meta ) {
+Vector2Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+
+};
+
+Vector2Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -40,3 +51,5 @@ THREE.Vector2Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector2Node };

+ 22 - 10
examples/js/nodes/inputs/Vector3Node.js

@@ -2,28 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector3Node = function ( x, y, z ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v3' );
+function Vector3Node( x, y, z ) {
 
-	this.type = 'v3';
-	this.value = new THREE.Vector3( x, y, z );
+	InputNode.call( this, 'v3' );
+
+	this.value = x instanceof THREE.Vector3 ? x : new THREE.Vector3( x, y, z );
 
 };
 
-THREE.Vector3Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector3Node.prototype.constructor = THREE.Vector3Node;
-THREE.Vector3Node.prototype.nodeType = "Vector3";
+Vector3Node.prototype = Object.create( InputNode.prototype );
+Vector3Node.prototype.constructor = Vector3Node;
+Vector3Node.prototype.nodeType = "Vector3";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
+NodeUtils.addShortcuts( Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
 
-THREE.Vector3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec3( " + this.x + ", " + this.y + ", " + this.z + " )", type, output );
 
 };
 
-THREE.Vector3Node.prototype.toJSON = function ( meta ) {
+Vector3Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+	
+};
+
+Vector3Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -42,3 +52,5 @@ THREE.Vector3Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector3Node };

+ 22 - 9
examples/js/nodes/inputs/Vector4Node.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector4Node = function ( x, y, z, w ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v4' );
+function Vector4Node( x, y, z, w ) {
 
-	this.value = new THREE.Vector4( x, y, z, w );
+	InputNode.call( this, 'v4' );
+
+	this.value = x instanceof THREE.Vector4 ? x : new THREE.Vector4( x, y, z, w );
 
 };
 
-THREE.Vector4Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector4Node.prototype.constructor = THREE.Vector4Node;
-THREE.Vector4Node.prototype.nodeType = "Vector4";
+Vector4Node.prototype = Object.create( InputNode.prototype );
+Vector4Node.prototype.constructor = Vector4Node;
+Vector4Node.prototype.nodeType = "Vector4";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
+NodeUtils.addShortcuts( Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
 
-THREE.Vector4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec4( " + this.x + ", " + this.y + ", " + this.z + ", " + this.w + " )", type, output );
 
 };
 
-THREE.Vector4Node.prototype.toJSON = function ( meta ) {
+Vector4Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+
+};
+
+Vector4Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -42,3 +53,5 @@ THREE.Vector4Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector4Node };

+ 34 - 0
examples/js/nodes/materials/MeshStandardNodeMaterial.js

@@ -0,0 +1,34 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { MeshStandardNode } from './nodes/MeshStandardNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
+
+function MeshStandardNodeMaterial() {
+
+	var node = new MeshStandardNode();
+
+	NodeMaterial.call( this, node, node );
+
+	this.type = "MeshStandardNodeMaterial";
+
+};
+
+MeshStandardNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+MeshStandardNodeMaterial.prototype.constructor = MeshStandardNodeMaterial;
+
+NodeUtils.addShortcuts( MeshStandardNodeMaterial.prototype, 'properties', [
+	"color",
+	"roughness",
+	"metalness",
+	"map",
+	"normalMap",
+	"normalScale",
+	"metalnessMap",
+	"roughnessMap",
+	"envMap"
+] );
+
+export { MeshStandardNodeMaterial };

+ 189 - 0
examples/js/nodes/materials/NodeMaterial.js

@@ -0,0 +1,189 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { NodeBuilder } from '../core/NodeBuilder.js';
+import { ColorNode } from '../inputs/ColorNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+import { RawNode } from './nodes/RawNode.js';
+ 
+function NodeMaterial( vertex, fragment ) {
+
+	THREE.ShaderMaterial.call( this );
+
+	// prevent code share conflict, remove in future
+	
+	this.defines.UUID = this.uuid;
+
+	this.vertex = vertex || new RawNode( new PositionNode( PositionNode.PROJECTION ) );
+	this.fragment = fragment || new RawNode( new ColorNode( 0xFF0000 ) );
+
+	this.updaters = [];
+
+};
+
+NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
+NodeMaterial.prototype.constructor = NodeMaterial;
+NodeMaterial.prototype.type = "NodeMaterial";
+
+NodeMaterial.prototype.isNodeMaterial = true;
+
+Object.defineProperties( NodeMaterial.prototype, {
+
+	properties: {
+		
+		get: function () {
+
+			return this.fragment.properties;
+
+		}
+		
+	}
+
+} );
+
+NodeMaterial.prototype.updateFrame = function ( frame ) {
+
+	for ( var i = 0; i < this.updaters.length; ++ i ) {
+
+		frame.updateNode( this.updaters[ i ] );
+
+	}
+
+};
+
+NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
+
+	if ( this.needsUpdate ) {
+
+		this.build( { renderer: renderer } );
+
+		shader.uniforms = this.uniforms;
+		shader.vertexShader = this.vertexShader;
+		shader.fragmentShader = this.fragmentShader;
+
+	}
+
+};
+
+NodeMaterial.prototype.build = function ( params ) {
+
+	params = params || {};
+
+	var builder = params.builder || new NodeBuilder();
+	
+	builder.setMaterial( this, params.renderer );
+	builder.build( this.vertex, this.fragment );
+	
+	this.vertexShader = builder.getCode('vertex');
+	this.fragmentShader = builder.getCode('fragment');
+	
+	this.defines = builder.defines;
+	this.uniforms = builder.uniforms;
+	this.extensions = builder.extensions;
+	this.updaters = builder.updaters;
+	
+	this.fog = builder.requires.fog;
+	this.lights = builder.requires.lights;
+
+	this.transparent = builder.requires.transparent || this.blending > THREE.NormalBlending;
+
+	this.needsUpdate = false;
+	
+	return this;
+
+};
+
+NodeMaterial.prototype.copy = function ( source ) {
+	
+	var uuid = this.uuid;
+	
+	for (var name in source) {
+		
+		this[name] = source[name];
+		
+	}
+	
+	this.uuid = uuid;
+	
+	if ( source.userData !== undefined) {
+		
+		this.userData = JSON.parse( JSON.stringify( source.userData ) );
+		
+	}
+	
+};
+
+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.size !== undefined ) data.size = this.size;
+		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
+
+		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.vertexColors !== THREE.NoColors ) data.vertexColors = this.vertexColors;
+
+		if ( this.depthFunc !== THREE.LessEqualDepth ) data.depthFunc = this.depthFunc;
+		if ( this.depthTest === false ) data.depthTest = this.depthTest;
+		if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
+
+		if ( this.linewidth !== 1 ) data.linewidth = this.linewidth;
+		if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
+		if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
+		if ( this.scale !== undefined ) data.scale = this.scale;
+
+		if ( this.dithering === true ) data.dithering = true;
+		
+		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.alphaTest > 0 ) data.alphaTest = this.alphaTest;
+		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
+		
+		if ( this.morphTargets === true ) data.morphTargets = true;
+		if ( this.skinning === true ) data.skinning = true;
+
+		if ( this.visible === false ) data.visible = false;
+		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+		data.fog = this.fog;
+		data.lights = this.lights;
+		
+		data.vertex = this.vertex.toJSON( meta ).uuid;
+		data.fragment = this.fragment.toJSON( meta ).uuid;
+
+	}
+
+	meta.material = this.uuid;
+
+	return meta;
+
+};
+
+export { NodeMaterial };

+ 26 - 7
examples/js/nodes/materials/PhongNodeMaterial.js

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

+ 17 - 7
examples/js/nodes/materials/SpriteNodeMaterial.js

@@ -2,18 +2,28 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SpriteNodeMaterial = function () {
+import { SpriteNode } from './nodes/SpriteNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	this.node = new THREE.SpriteNode();
+function SpriteNodeMaterial() {
 
-	THREE.NodeMaterial.call( this, this.node, this.node );
+	var node = new SpriteNode();
+
+	NodeMaterial.call( this, node, node );
 
 	this.type = "SpriteNodeMaterial";
 
 };
 
-THREE.SpriteNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
-THREE.SpriteNodeMaterial.prototype.constructor = THREE.SpriteNodeMaterial;
+SpriteNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+SpriteNodeMaterial.prototype.constructor = SpriteNodeMaterial;
+
+NodeUtils.addShortcuts( SpriteNodeMaterial.prototype, 'fragment', [ 
+	'color', 
+	'alpha', 
+	'transform', 
+	'spherical' 
+] );
 
-THREE.NodeMaterial.addShortcuts( THREE.SpriteNodeMaterial.prototype, 'node',
-	[ 'color', 'alpha', 'transform', 'spherical' ] );
+export { SpriteNodeMaterial };

+ 28 - 7
examples/js/nodes/materials/StandardNodeMaterial.js

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

+ 109 - 0
examples/js/nodes/materials/nodes/MeshStandardNode.js

@@ -0,0 +1,109 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { StandardNode } from './StandardNode.js';
+import { PropertyNode } from '../../inputs/PropertyNode.js';
+import { OperatorNode } from '../../math/OperatorNode.js';
+import { SwitchNode } from '../../utils/SwitchNode.js';
+import { NormalMapNode } from '../../misc/NormalMapNode.js';
+
+function MeshStandardNode() {
+
+	StandardNode.call( this );
+
+	this.properties = {
+		color: new THREE.Color( 0xffffff ),
+		roughness: 0.5,
+		metalness: 0.5,
+		normalScale: new THREE.Vector2( 1, 1 )
+	};
+	
+	this.inputs = {
+		color: new PropertyNode( this.properties, 'color', 'c' ),
+		roughness: new PropertyNode( this.properties, 'roughness', 'f' ),
+		metalness: new PropertyNode( this.properties, 'metalness', 'f' ),
+		normalScale: new PropertyNode( this.properties, 'normalScale', 'v2' )
+	};
+
+};
+
+MeshStandardNode.prototype = Object.create( StandardNode.prototype );
+MeshStandardNode.prototype.constructor = MeshStandardNode;
+MeshStandardNode.prototype.nodeType = "MeshStandard";
+
+MeshStandardNode.prototype.build = function ( builder ) {
+
+	var props = this.properties,
+		inputs = this.inputs;
+
+	if ( builder.isShader('fragment') ) {
+		
+		// slots
+		// * color
+		// * map
+		
+		var color = builder.findNode( props.color, inputs.color ),
+			map = builder.resolve( props.map );
+		
+		this.color = map ? new OperatorNode( color, map, OperatorNode.MUL ) : color;
+		
+		// slots
+		// * roughness
+		// * roughnessMap
+		
+		var roughness = builder.findNode( props.roughness, inputs.roughness ),
+			roughnessMap = builder.resolve( props.roughnessMap );
+		
+		this.roughness = roughnessMap ? new OperatorNode( roughness, new SwitchNode( roughnessMap, "g" ), OperatorNode.MUL ) : roughness;
+		
+		// slots
+		// * metalness
+		// * metalnessMap
+		
+		var metalness = builder.findNode( props.metalness, inputs.metalness ),
+			metalnessMap = builder.resolve( props.metalnessMap );
+		
+		this.metalness = metalnessMap ? new OperatorNode( metalness, new SwitchNode( metalnessMap, "b" ), OperatorNode.MUL ) : metalness;
+
+		// slots
+		// * normalMap
+		// * normalScale
+		
+		if ( props.normalMap ) {
+			
+			this.normal = new NormalMapNode( builder.resolve( props.normalMap ) );
+			this.normal.scale = builder.findNode( props.normalScale, inputs.normalScale )
+
+		}
+
+		// slots
+		// * envMap
+		
+		this.environment = builder.resolve( props.envMap );
+		
+	}
+	
+	// build code
+
+	return StandardNode.prototype.build.call( this, builder );
+
+};
+
+MeshStandardNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+		
+		console.warn(".toJSON not implemented in", this);
+		
+	}
+
+	return data;
+
+};
+
+export { MeshStandardNode };

+ 76 - 37
examples/js/nodes/materials/PhongNode.js → examples/js/nodes/materials/nodes/PhongNode.js

@@ -2,42 +2,45 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
+import { FloatNode } from '../../inputs/FloatNode.js';
+ 
+function PhongNode() {
 
-	THREE.GLNode.call( this );
+	GLNode.call( this );
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
-	this.specular = new THREE.ColorNode( 0x111111 );
-	this.shininess = new THREE.FloatNode( 30 );
+	this.color = new ColorNode( 0xEEEEEE );
+	this.specular = new ColorNode( 0x111111 );
+	this.shininess = new FloatNode( 30 );
 
 };
 
-THREE.PhongNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.PhongNode.prototype.constructor = THREE.PhongNode;
-THREE.PhongNode.prototype.nodeType = "Phong";
+PhongNode.prototype = Object.create( GLNode.prototype );
+PhongNode.prototype.constructor = PhongNode;
+PhongNode.prototype.nodeType = "Phong";
 
-THREE.PhongNode.prototype.build = function ( builder ) {
+PhongNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var code;
 
-	material.define( 'PHONG' );
-	material.define( 'ALPHATEST', '0.0' );
+	builder.define( 'PHONG' );
+	builder.define( 'ALPHATEST', '0.0' );
 
-	material.requires.lights = true;
+	builder.requires.lights = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"varying vec3 vViewPosition;",
 
 			"#ifndef FLAT_SHADED",
@@ -47,6 +50,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			"#endif",
 
 			"#include <common>",
+			"#include <encodings_pars_fragment>", // encoding functions
 			"#include <fog_pars_vertex>",
 			"#include <morphtarget_pars_vertex>",
 			"#include <skinning_pars_vertex>",
@@ -74,7 +78,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -121,26 +125,26 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var specular = this.specular.buildCode( builder, 'c' );
-		var shininess = this.shininess.buildCode( builder, 'fv1' );
+		var shininess = this.shininess.buildCode( builder, 'f' );
 
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
 
 		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
-		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
+		var ao = this.ao ? this.ao.buildCode( builder, 'f' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
 		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
 		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot: 'environment' } ) : undefined;
-		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'fv1' ) : undefined;
+		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'f' ) : undefined;
 
-		material.requires.transparent = alpha != undefined;
+		builder.requires.transparent = alpha != undefined;
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 			"#include <common>",
 			"#include <fog_pars_fragment>",
 			"#include <bsdfs>",
@@ -167,7 +171,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			"	vec3 specular = " + specular.result + ";",
 
 			shininess.code,
-			"	float shininess = max(0.0001," + shininess.result + ");",
+			"	float shininess = max( 0.0001, " + shininess.result + " );",
 
 			"	float specularStrength = 1.0;" // Ignored in MaterialNode ( replace to specular )
 		];
@@ -183,19 +187,11 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 		if ( normal ) {
 
-			builder.include( 'perturbNormal2Arb' );
-
-			output.push( normal.code );
-
-			if ( normalScale ) output.push( normalScale.code );
-
 			output.push(
-				'normal = perturbNormal2Arb(-vViewPosition,normal,' +
-				normal.result + ',' +
-				new THREE.UVNode().build( builder, 'v2' ) + ',' +
-				( normalScale ? normalScale.result : 'vec2( 1.0 )' ) + ');'
+				normal.code,
+				'normal = ' + normal.result + ';'
 			);
-
+		
 		}
 
 		// optimization for now
@@ -285,7 +281,19 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			}
 
 		}
-
+/*
+		switch( builder.material.combine ) {
+
+			case THREE.ENVMAP_BLENDING_MULTIPLY:
+				
+				//output.push( "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;" );
+				//outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );
+				
+				break;
+			
+			
+		}
+	*/	
 		if ( alpha ) {
 
 			output.push( "gl_FragColor = vec4( outgoingLight, " + alpha.result + " );" );
@@ -311,8 +319,38 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 };
 
+PhongNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+
+	if ( source.transform ) this.transform = source.transform;
+
+	// fragment
+
+	this.color = source.color;
+	this.specular = source.specular;
+	this.shininess = source.shininess;
 
-THREE.PhongNode.prototype.toJSON = function ( meta ) {
+	if ( source.alpha ) this.alpha = source.alpha;
+
+	if ( source.normal ) this.normal = source.normal;
+
+	if ( source.light ) this.light = source.light;
+	if ( source.shadow ) this.shadow = source.shadow;
+
+	if ( source.ao ) this.ao = source.ao;
+	
+	if ( source.emissive ) this.emissive = source.emissive;
+	if ( source.ambient ) this.ambient = source.ambient;
+
+	if ( source.environment ) this.environment = source.environment;
+	if ( source.environmentAlpha ) this.environmentAlpha = source.environmentAlpha;
+
+};
+
+PhongNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -333,7 +371,6 @@ THREE.PhongNode.prototype.toJSON = function ( meta ) {
 		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;
 
@@ -350,3 +387,5 @@ THREE.PhongNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { PhongNode };

+ 62 - 0
examples/js/nodes/materials/nodes/RawNode.js

@@ -0,0 +1,62 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from '../../core/GLNode.js';
+
+function RawNode( value ) {
+
+	GLNode.call( this, 'v4' );
+
+	this.value = value;
+
+};
+
+RawNode.prototype = Object.create( GLNode.prototype );
+RawNode.prototype.constructor = RawNode;
+RawNode.prototype.nodeType = "Raw";
+
+RawNode.prototype.generate = function ( builder ) {
+
+	var data = this.value.parseAndBuildCode( builder, this.type ),
+		code = data.code + '\n';
+
+	if ( builder.isShader( 'vertex' ) ) {
+
+		code += 'gl_Position = ' + data.result + ';';
+
+	} else {
+
+		code += 'gl_FragColor = ' + data.result + ';';
+
+	}
+
+	return code;
+
+};
+
+RawNode.prototype.copy = function ( source ) {
+	
+	GLNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
+};
+
+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;
+
+};
+
+export { RawNode };

+ 41 - 17
examples/js/nodes/materials/SpriteNode.js → examples/js/nodes/materials/nodes/SpriteNode.js

@@ -2,38 +2,40 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SpriteNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
 
-	THREE.GLNode.call( this );
+function SpriteNode() {
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
+	GLNode.call( this );
+
+	this.color = new ColorNode( 0xEEEEEE );
 	this.spherical = true;
 
 };
 
-THREE.SpriteNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.SpriteNode.prototype.constructor = THREE.SpriteNode;
-THREE.SpriteNode.prototype.nodeType = "Sprite";
+SpriteNode.prototype = Object.create( GLNode.prototype );
+SpriteNode.prototype.constructor = SpriteNode;
+SpriteNode.prototype.nodeType = "Sprite";
 
-THREE.SpriteNode.prototype.build = function ( builder ) {
+SpriteNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var output, code;
 
-	material.define( 'SPRITE' );
+	builder.define( 'SPRITE' );
 
-	material.requires.lights = false;
-	material.requires.transparent = this.alpha != undefined;
+	builder.requires.lights = false;
+	builder.requires.transparent = this.alpha != undefined;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 			THREE.UniformsLib[ "fog" ]
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"#include <fog_pars_vertex>"
 		].join( "\n" ) );
 
@@ -45,7 +47,7 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -102,19 +104,20 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 	} else {
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 			"#include <fog_pars_fragment>",
 		].join( "\n" ) );
 
 		// parse all nodes to reuse generate codes
 
 		this.color.parse( builder, { slot: 'color' } );
+
 		if ( this.alpha ) this.alpha.parse( builder );
 
 		// build code
 
 		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		output = [ color.code ];
 
@@ -139,7 +142,25 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 };
 
-THREE.SpriteNode.prototype.toJSON = function ( meta ) {
+SpriteNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+	
+	if ( source.transform ) this.transform = source.transform;
+	
+	// fragment
+	
+	this.color = source.color;
+	
+	if ( source.spherical !== undefined ) this.spherical = source.transform;
+	
+	if ( source.alpha ) this.alpha = source.alpha;
+
+};
+
+SpriteNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -154,6 +175,7 @@ THREE.SpriteNode.prototype.toJSON = function ( meta ) {
 		// 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;
@@ -163,3 +185,5 @@ THREE.SpriteNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { SpriteNode };

+ 99 - 64
examples/js/nodes/materials/StandardNode.js → examples/js/nodes/materials/nodes/StandardNode.js

@@ -2,47 +2,48 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
+import { FloatNode } from '../../inputs/FloatNode.js';
+import { RoughnessToBlinnExponentNode } from '../../bsdfs/RoughnessToBlinnExponentNode.js';
+ 
+function StandardNode() {
 
-	THREE.GLNode.call( this );
+	GLNode.call( this );
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
-	this.roughness = new THREE.FloatNode( 0.5 );
-	this.metalness = new THREE.FloatNode( 0.5 );
+	this.color = new ColorNode( 0xEEEEEE );
+	this.roughness = new FloatNode( 0.5 );
+	this.metalness = new FloatNode( 0.5 );
 
 };
 
-THREE.StandardNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.StandardNode.prototype.constructor = THREE.StandardNode;
-THREE.StandardNode.prototype.nodeType = "Standard";
+StandardNode.prototype = Object.create( GLNode.prototype );
+StandardNode.prototype.constructor = StandardNode;
+StandardNode.prototype.nodeType = "Standard";
 
-THREE.StandardNode.prototype.build = function ( builder ) {
+StandardNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var code;
 
-	material.define( 'PHYSICAL' );
+	builder.define( this.clearCoat || this.clearCoatRoughness ? 'PHYSICAL' : 'STANDARD' );
+	builder.define( 'ALPHATEST', '0.0' );
 
-	if ( ! this.clearCoat && ! this.clearCoatRoughness ) material.define( 'STANDARD' );
+	builder.requires.lights = true;
 
-	material.define( 'ALPHATEST', '0.0' );
-
-	material.requires.lights = true;
-
-	material.extensions.shaderTextureLOD = true;
+	builder.extensions.shaderTextureLOD = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"varying vec3 vViewPosition;",
 
 			"#ifndef FLAT_SHADED",
@@ -52,6 +53,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 			"#endif",
 
 			"#include <common>",
+			"#include <encodings_pars_fragment>", // encoding functions
 			"#include <fog_pars_vertex>",
 			"#include <morphtarget_pars_vertex>",
 			"#include <skinning_pars_vertex>",
@@ -83,7 +85,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -105,19 +107,20 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 	} else {
 
-		// blur textures for PBR effect
+		var contextEnvironment = {
+			bias: RoughnessToBlinnExponentNode,
+			gamma: true
+		};
 
-		var requires = {
-			bias: new THREE.RoughnessToBlinnExponentNode(),
-			offsetU: 0,
-			offsetV: 0
+		var contextGammaOnly = {
+			gamma: true
 		};
 
-		var useClearCoat = ! material.isDefined( 'STANDARD' );
+		var useClearCoat = ! builder.isDefined( 'STANDARD' );
 
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot: 'color' } );
+		this.color.parse( builder, { slot: 'color', context: contextGammaOnly } );
 		this.roughness.parse( builder );
 		this.metalness.parse( builder );
 
@@ -138,38 +141,38 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 		if ( this.shadow ) this.shadow.parse( builder );
 		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { cache: 'env', requires: requires, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+		if ( this.environment ) this.environment.parse( builder, { cache: 'env', context: contextEnvironment, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
-		var roughness = this.roughness.buildCode( builder, 'fv1' );
-		var metalness = this.metalness.buildCode( builder, 'fv1' );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color', context: contextGammaOnly } );
+		var roughness = this.roughness.buildCode( builder, 'f' );
+		var metalness = this.metalness.buildCode( builder, 'f' );
 
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
 
-		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'fv1' ) : undefined;
-		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'fv1' ) : undefined;
+		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'f' ) : undefined;
+		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'f' ) : undefined;
 
-		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'fv1' ) : undefined;
+		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'f' ) : undefined;
 
 		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
-		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
+		var ao = this.ao ? this.ao.buildCode( builder, 'f' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
 		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', requires: requires, slot: 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', context: contextEnvironment, slot: 'environment' } ) : undefined;
 
-		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', requires: requires, slot: 'environment' } ) : undefined;
+		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined;
 
-		material.requires.transparent = alpha != undefined;
+		builder.requires.transparent = alpha !== undefined;
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 
 			"varying vec3 vViewPosition;",
 
@@ -221,28 +224,18 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 		if ( normal ) {
 
-			builder.include( 'perturbNormal2Arb' );
-
-			output.push( normal.code );
-
-			if ( normalScale ) output.push( normalScale.code );
-
 			output.push(
-				'normal = perturbNormal2Arb(-vViewPosition,normal,' +
-				normal.result + ',' +
-				new THREE.UVNode().build( builder, 'v2' ) + ',' +
-				( normalScale ? normalScale.result : 'vec2( 1.0 )' ) + ');'
+				normal.code,
+				'normal = ' + normal.result + ';'
 			);
-
+		
 		}
 
 		// optimization for now
 
-		output.push( 'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * (1.0 - metalnessFactor)' ) + ';' );
-
 		output.push(
-			// accumulation
-			'material.specularRoughness = clamp( roughnessFactor, DEFAULT_SPECULAR_COEFFICIENT, 1.0 );' // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
+			'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * (1.0 - metalnessFactor)' ) + ';',
+			'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );'
 		);
 
 		if ( clearCoat ) {
@@ -262,7 +255,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			output.push(
 				clearCoatRoughness.code,
-				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', DEFAULT_SPECULAR_COEFFICIENT, 1.0 );'
+				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', 0.04, 1.0 );'
 			);
 
 		} else if ( useClearCoat ) {
@@ -287,8 +280,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 		}
 
 		output.push(
-			"#include <lights_fragment_begin>",
-			"#include <lights_fragment_end>"
+			"#include <lights_fragment_begin>"
 		);
 
 		if ( light ) {
@@ -361,9 +353,13 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			}
 
-			output.push( "RE_IndirectSpecular(" + environment.result + ", clearCoatRadiance, geometry, material, reflectedLight );" );
+			output.push( "radiance += " + environment.result + ";" );
 
 		}
+		
+		output.push(
+			"#include <lights_fragment_end>"
+		);
 
 		output.push( "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;" );
 
@@ -381,7 +377,9 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 			"#include <premultiplied_alpha_fragment>",
 			"#include <tonemapping_fragment>",
 			"#include <encodings_fragment>",
-			"#include <fog_fragment>"
+			"#include <fog_fragment>",
+			"#include <premultiplied_alpha_fragment>",
+			"#include <dithering_fragment>"
 		);
 
 		code = output.join( "\n" );
@@ -392,7 +390,42 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 };
 
-THREE.StandardNode.prototype.toJSON = function ( meta ) {
+StandardNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+
+	if ( source.transform ) this.transform = source.transform;
+
+	// fragment
+
+	this.color = source.color;
+	this.roughness = source.roughness;
+	this.metalness = source.metalness;
+
+	if ( source.alpha ) this.alpha = source.alpha;
+
+	if ( source.normal ) this.normal = source.normal;
+
+	if ( source.clearCoat ) this.clearCoat = source.clearCoat;
+	if ( source.clearCoatRoughness ) this.clearCoatRoughness = source.clearCoatRoughness;
+
+	if ( source.reflectivity ) this.reflectivity = source.reflectivity;
+
+	if ( source.light ) this.light = source.light;
+	if ( source.shadow ) this.shadow = source.shadow;
+
+	if ( source.ao ) this.ao = source.ao;
+	
+	if ( source.emissive ) this.emissive = source.emissive;
+	if ( source.ambient ) this.ambient = source.ambient;
+
+	if ( source.environment ) this.environment = source.environment;
+
+};
+
+StandardNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -413,7 +446,6 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 		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;
@@ -421,11 +453,12 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 		if ( this.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
 
 		if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
+		if ( this.shadow ) data.shadow = this.shadow.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.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
 
 		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
 
@@ -434,3 +467,5 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { StandardNode };

+ 64 - 47
examples/js/nodes/math/Math1Node.js

@@ -2,51 +2,54 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Math1Node = function ( a, method ) {
+import { TempNode } from '../core/TempNode.js';
 
-	THREE.TempNode.call( this );
+function Math1Node( a, method ) {
+
+	TempNode.call( this );
 
 	this.a = a;
 
-	this.method = method || THREE.Math1Node.SIN;
+	this.method = method || Math1Node.SIN;
 
 };
 
-THREE.Math1Node.RAD = 'radians';
-THREE.Math1Node.DEG = 'degrees';
-THREE.Math1Node.EXP = 'exp';
-THREE.Math1Node.EXP2 = 'exp2';
-THREE.Math1Node.LOG = 'log';
-THREE.Math1Node.LOG2 = 'log2';
-THREE.Math1Node.SQRT = 'sqrt';
-THREE.Math1Node.INV_SQRT = 'inversesqrt';
-THREE.Math1Node.FLOOR = 'floor';
-THREE.Math1Node.CEIL = 'ceil';
-THREE.Math1Node.NORMALIZE = 'normalize';
-THREE.Math1Node.FRACT = 'fract';
-THREE.Math1Node.SAT = 'saturate';
-THREE.Math1Node.SIN = 'sin';
-THREE.Math1Node.COS = 'cos';
-THREE.Math1Node.TAN = 'tan';
-THREE.Math1Node.ASIN = 'asin';
-THREE.Math1Node.ACOS = 'acos';
-THREE.Math1Node.ARCTAN = 'atan';
-THREE.Math1Node.ABS = 'abs';
-THREE.Math1Node.SIGN = 'sign';
-THREE.Math1Node.LENGTH = 'length';
-THREE.Math1Node.NEGATE = 'negate';
-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 ) {
+Math1Node.RAD = 'radians';
+Math1Node.DEG = 'degrees';
+Math1Node.EXP = 'exp';
+Math1Node.EXP2 = 'exp2';
+Math1Node.LOG = 'log';
+Math1Node.LOG2 = 'log2';
+Math1Node.SQRT = 'sqrt';
+Math1Node.INV_SQRT = 'inversesqrt';
+Math1Node.FLOOR = 'floor';
+Math1Node.CEIL = 'ceil';
+Math1Node.NORMALIZE = 'normalize';
+Math1Node.FRACT = 'fract';
+Math1Node.SAT = 'saturate';
+Math1Node.SIN = 'sin';
+Math1Node.COS = 'cos';
+Math1Node.TAN = 'tan';
+Math1Node.ASIN = 'asin';
+Math1Node.ACOS = 'acos';
+Math1Node.ARCTAN = 'atan';
+Math1Node.ABS = 'abs';
+Math1Node.SIGN = 'sign';
+Math1Node.LENGTH = 'length';
+Math1Node.NEGATE = 'negate';
+Math1Node.INVERT = 'invert';
+
+Math1Node.prototype = Object.create( TempNode.prototype );
+Math1Node.prototype.constructor = Math1Node;
+Math1Node.prototype.nodeType = "Math1";
+
+Math1Node.prototype.getType = function ( builder ) {
 
 	switch ( this.method ) {
 
-		case THREE.Math1Node.LENGTH:
-			return 'fv1';
+		case Math1Node.LENGTH:
+		
+			return 'f';
 
 	}
 
@@ -54,26 +57,29 @@ THREE.Math1Node.prototype.getType = function ( builder ) {
 
 };
 
-THREE.Math1Node.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getType( builder );
+Math1Node.prototype.generate = function ( builder, output ) {
 
-	var result = this.a.build( builder, type );
+	var type = this.getType( builder ),
+		result = this.a.build( builder, type );
 
 	switch ( this.method ) {
 
-		case THREE.Math1Node.NEGATE:
-			result = '(-' + result + ')';
+		case Math1Node.NEGATE:
+		
+			result = '( -' + result + ' )';
+			
 			break;
 
-		case THREE.Math1Node.INVERT:
-			result = '(1.0-' + result + ')';
+		case Math1Node.INVERT:
+		
+			result = '( 1.0 - ' + result + ' )';
+			
 			break;
 
 		default:
-			result = this.method + '(' + result + ')';
+		
+			result = this.method + '( ' + result + ' )';
+			
 			break;
 
 	}
@@ -82,7 +88,16 @@ THREE.Math1Node.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.Math1Node.prototype.toJSON = function ( meta ) {
+Math1Node.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.a = source.a;
+	this.method = source.method;
+	
+};
+
+Math1Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -98,3 +113,5 @@ THREE.Math1Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Math1Node };

+ 62 - 40
examples/js/nodes/math/Math2Node.js

@@ -1,36 +1,39 @@
 /**
  * @author sunag / http://www.sunag.com.br/
  */
+ 
+import { TempNode } from '../core/TempNode.js';
 
-THREE.Math2Node = function ( a, b, method ) {
+function Math2Node( a, b, method ) {
 
-	THREE.TempNode.call( this );
+	TempNode.call( this );
 
 	this.a = a;
 	this.b = b;
 
-	this.method = method || THREE.Math2Node.DISTANCE;
+	this.method = method || Math2Node.DISTANCE;
 
 };
 
-THREE.Math2Node.MIN = 'min';
-THREE.Math2Node.MAX = 'max';
-THREE.Math2Node.MOD = 'mod';
-THREE.Math2Node.STEP = 'step';
-THREE.Math2Node.REFLECT = 'reflect';
-THREE.Math2Node.DISTANCE = 'distance';
-THREE.Math2Node.DOT = 'dot';
-THREE.Math2Node.CROSS = 'cross';
-THREE.Math2Node.POW = 'pow';
+Math2Node.MIN = 'min';
+Math2Node.MAX = 'max';
+Math2Node.MOD = 'mod';
+Math2Node.STEP = 'step';
+Math2Node.REFLECT = 'reflect';
+Math2Node.DISTANCE = 'distance';
+Math2Node.DOT = 'dot';
+Math2Node.CROSS = 'cross';
+Math2Node.POW = 'pow';
 
-THREE.Math2Node.prototype = Object.create( THREE.TempNode.prototype );
-THREE.Math2Node.prototype.constructor = THREE.Math2Node;
-THREE.Math2Node.prototype.nodeType = "Math2";
+Math2Node.prototype = Object.create( TempNode.prototype );
+Math2Node.prototype.constructor = Math2Node;
+Math2Node.prototype.nodeType = "Math2";
 
-THREE.Math2Node.prototype.getInputType = function ( builder ) {
+Math2Node.prototype.getInputType = function ( builder ) {
 
 	// use the greater length vector
-	if ( builder.getFormatLength( this.b.getType( builder ) ) > builder.getFormatLength( this.a.getType( builder ) ) ) {
+	
+	if ( builder.getTypeLength( this.b.getType( builder ) ) > builder.getTypeLength( this.a.getType( builder ) ) ) {
 
 		return this.b.getType( builder );
 
@@ -40,15 +43,17 @@ THREE.Math2Node.prototype.getInputType = function ( builder ) {
 
 };
 
-THREE.Math2Node.prototype.getType = function ( builder ) {
+Math2Node.prototype.getType = function ( builder ) {
 
 	switch ( this.method ) {
 
-		case THREE.Math2Node.DISTANCE:
-		case THREE.Math2Node.DOT:
-			return 'fv1';
+		case Math2Node.DISTANCE:
+		case Math2Node.DOT:
+		
+			return 'f';
 
-		case THREE.Math2Node.CROSS:
+		case Math2Node.CROSS:
+		
 			return 'v3';
 
 	}
@@ -57,49 +62,64 @@ THREE.Math2Node.prototype.getType = function ( builder ) {
 
 };
 
-THREE.Math2Node.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getInputType( builder );
-
-	var a, b,
-		al = builder.getFormatLength( this.a.getType( builder ) ),
-		bl = builder.getFormatLength( this.b.getType( builder ) );
+Math2Node.prototype.generate = function ( builder, output ) {
 
+	var a, b, 
+		type = this.getInputType( builder ),
+		al = builder.getTypeLength( this.a.getType( builder ) ),
+		bl = builder.getTypeLength( this.b.getType( builder ) );
+		
 	// optimzer
 
 	switch ( this.method ) {
 
-		case THREE.Math2Node.CROSS:
+		case Math2Node.CROSS:
+		
 			a = this.a.build( builder, 'v3' );
 			b = this.b.build( builder, 'v3' );
+			
 			break;
 
-		case THREE.Math2Node.STEP:
-			a = this.a.build( builder, al == 1 ? 'fv1' : type );
+		case Math2Node.STEP:
+		
+			a = this.a.build( builder, al === 1 ? 'f' : type );
 			b = this.b.build( builder, type );
+			
 			break;
 
-		case THREE.Math2Node.MIN:
-		case THREE.Math2Node.MAX:
-		case THREE.Math2Node.MOD:
+		case Math2Node.MIN:
+		case Math2Node.MAX:
+		case Math2Node.MOD:
+		
 			a = this.a.build( builder, type );
-			b = this.b.build( builder, bl == 1 ? 'fv1' : type );
+			b = this.b.build( builder, bl === 1 ? 'f' : type );
+			
 			break;
 
 		default:
+		
 			a = this.a.build( builder, type );
 			b = this.b.build( builder, type );
+			
 			break;
 
 	}
 
-	return builder.format( this.method + '(' + a + ',' + b + ')', this.getType( builder ), output );
+	return builder.format( this.method + '( ' + a + ', ' + b + ' )', this.getType( builder ), output );
 
 };
 
-THREE.Math2Node.prototype.toJSON = function ( meta ) {
+Math2Node.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.a = source.a;
+	this.b = source.b;
+	this.method = source.method;
+	
+};
+
+Math2Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -116,3 +136,5 @@ THREE.Math2Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Math2Node };

+ 59 - 34
examples/js/nodes/math/Math3Node.js

@@ -1,81 +1,104 @@
 /**
  * @author sunag / http://www.sunag.com.br/
  */
+ 
+import { TempNode } from '../core/TempNode.js';
 
-THREE.Math3Node = function ( a, b, c, method ) {
+function Math3Node( a, b, c, method ) {
 
-	THREE.TempNode.call( this );
+	TempNode.call( this );
 
 	this.a = a;
 	this.b = b;
 	this.c = c;
 
-	this.method = method || THREE.Math3Node.MIX;
+	this.method = method || Math3Node.MIX;
 
 };
 
-THREE.Math3Node.MIX = 'mix';
-THREE.Math3Node.REFRACT = 'refract';
-THREE.Math3Node.SMOOTHSTEP = 'smoothstep';
-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 ) {
-
-	var a = builder.getFormatLength( this.a.getType( builder ) );
-	var b = builder.getFormatLength( this.b.getType( builder ) );
-	var c = builder.getFormatLength( this.c.getType( builder ) );
-
-	if ( a > b && a > c ) return this.a.getType( builder );
-	else if ( b > c ) return this.b.getType( builder );
+Math3Node.MIX = 'mix';
+Math3Node.REFRACT = 'refract';
+Math3Node.SMOOTHSTEP = 'smoothstep';
+Math3Node.FACEFORWARD = 'faceforward';
+
+Math3Node.prototype = Object.create( TempNode.prototype );
+Math3Node.prototype.constructor = Math3Node;
+Math3Node.prototype.nodeType = "Math3";
+
+Math3Node.prototype.getType = function ( builder ) {
+
+	var a = builder.getTypeLength( this.a.getType( builder ) );
+	var b = builder.getTypeLength( this.b.getType( builder ) );
+	var c = builder.getTypeLength( this.c.getType( builder ) );
+
+	if ( a > b && a > c ) {
+		
+		return this.a.getType( builder );
+		
+	} else if ( b > c ) {
+		
+		return this.b.getType( builder );
+		
+	}
 
 	return this.c.getType( builder );
 
 };
 
-THREE.Math3Node.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getType( builder );
+Math3Node.prototype.generate = function ( builder, output ) {
 
 	var a, b, c,
-		al = builder.getFormatLength( this.a.getType( builder ) ),
-		bl = builder.getFormatLength( this.b.getType( builder ) ),
-		cl = builder.getFormatLength( this.c.getType( builder ) );
+		al = builder.getTypeLength( this.a.getType( builder ) ),
+		bl = builder.getTypeLength( this.b.getType( builder ) ),
+		cl = builder.getTypeLength( this.c.getType( builder ) ),
+		type = this.getType( builder );
 
 	// optimzer
 
 	switch ( this.method ) {
 
-		case THREE.Math3Node.REFRACT:
+		case Math3Node.REFRACT:
+		
 			a = this.a.build( builder, type );
 			b = this.b.build( builder, type );
-			c = this.c.build( builder, 'fv1' );
+			c = this.c.build( builder, 'f' );
+			
 			break;
 
-		case THREE.Math3Node.MIX:
+		case Math3Node.MIX:
+		
 			a = this.a.build( builder, type );
 			b = this.b.build( builder, type );
-			c = this.c.build( builder, cl == 1 ? 'fv1' : type );
+			c = this.c.build( builder, cl === 1 ? 'f' : type );
+			
 			break;
 
 		default:
+		
 			a = this.a.build( builder, type );
 			b = this.b.build( builder, type );
 			c = this.c.build( builder, type );
+			
 			break;
 
 	}
 
-	return builder.format( this.method + '(' + a + ',' + b + ',' + c + ')', type, output );
+	return builder.format( this.method + '( ' + a + ', ' + b + ', ' + c + ' )', type, output );
 
 };
 
-THREE.Math3Node.prototype.toJSON = function ( meta ) {
+Math3Node.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.a = source.a;
+	this.b = source.b;
+	this.c = source.c;
+	this.method = source.method;
+	
+};
+
+Math3Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -93,3 +116,5 @@ THREE.Math3Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Math3Node };

+ 35 - 23
examples/js/nodes/math/OperatorNode.js

@@ -2,35 +2,37 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.OperatorNode = function ( a, b, op ) {
+import { TempNode } from '../core/TempNode.js';
+ 
+function OperatorNode( a, b, op ) {
 
-	THREE.TempNode.call( this );
+	TempNode.call( this );
 
 	this.a = a;
 	this.b = b;
-	this.op = op || THREE.OperatorNode.ADD;
+	this.op = op || OperatorNode.ADD;
 
 };
 
-THREE.OperatorNode.ADD = '+';
-THREE.OperatorNode.SUB = '-';
-THREE.OperatorNode.MUL = '*';
-THREE.OperatorNode.DIV = '/';
+OperatorNode.ADD = '+';
+OperatorNode.SUB = '-';
+OperatorNode.MUL = '*';
+OperatorNode.DIV = '/';
 
-THREE.OperatorNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.OperatorNode.prototype.constructor = THREE.OperatorNode;
-THREE.OperatorNode.prototype.nodeType = "Operator";
+OperatorNode.prototype = Object.create( TempNode.prototype );
+OperatorNode.prototype.constructor = OperatorNode;
+OperatorNode.prototype.nodeType = "Operator";
 
-THREE.OperatorNode.prototype.getType = function ( builder ) {
+OperatorNode.prototype.getType = function ( builder ) {
 
-	var a = this.a.getType( builder );
-	var b = this.b.getType( builder );
+	var a = this.a.getType( builder ),
+		b = this.b.getType( builder );
 
-	if ( builder.isFormatMatrix( a ) ) {
+	if ( builder.isTypeMatrix( a ) ) {
 
 		return 'v4';
 
-	} else if ( builder.getFormatLength( b ) > builder.getFormatLength( a ) ) {
+	} else if ( builder.getTypeLength( b ) > builder.getTypeLength( a ) ) {
 
 		// use the greater length vector
 
@@ -42,21 +44,29 @@ THREE.OperatorNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.OperatorNode.prototype.generate = function ( builder, output ) {
+OperatorNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material,
-		data = material.getDataNode( this.uuid );
+	var data = builder.getNodeData( this ),
+		type = this.getType( builder );
 
-	var type = this.getType( builder );
+	var a = this.a.build( builder, type ),
+		b = this.b.build( builder, type );
 
-	var a = this.a.build( builder, type );
-	var b = this.b.build( builder, type );
+	return builder.format( '( ' + a + ' ' +  this.op + ' '+ b + ' )', type, output );
 
-	return builder.format( '(' + a + this.op + b + ')', type, output );
+};
 
+OperatorNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.a = source.a;
+	this.b = source.b;
+	this.op = source.op;
+	
 };
 
-THREE.OperatorNode.prototype.toJSON = function ( meta ) {
+OperatorNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -73,3 +83,5 @@ THREE.OperatorNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { OperatorNode };

+ 166 - 0
examples/js/nodes/misc/BumpMapNode.js

@@ -0,0 +1,166 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { NormalNode } from '../accessors/NormalNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+
+function BumpMapNode( value, scale ) {
+
+	TempNode.call( this, 'v3' );
+
+	this.value = value;
+	this.scale = scale || new FloatNode( 1 );
+
+	this.toNormalMap = false;
+	
+};
+
+BumpMapNode.Nodes = (function() {
+	
+	var dHdxy_fwd = new FunctionNode( [
+
+		// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
+		// http://api.unrealengine.com/attachments/Engine/Rendering/LightingAndShadows/BumpMappingWithoutTangentSpace/mm_sfgrad_bump.pdf
+		
+		// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
+
+		"vec2 dHdxy_fwd( sampler2D bumpMap, vec2 vUv, float bumpScale ) {",
+
+		// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
+		
+		"	vec2 dSTdx = dFdx( vUv );",
+		"	vec2 dSTdy = dFdy( vUv );",
+		
+		"	float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
+		"	float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
+		"	float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
+		
+		"	return vec2( dBx, dBy );",
+		
+		"}"
+
+	].join( "\n" ), null, { derivatives: true } );
+
+	var perturbNormalArb = new FunctionNode( [
+
+		"vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
+
+		// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
+		
+		"	vec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );",
+		"	vec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );",
+		"	vec3 vN = surf_norm;", // normalized
+		
+		"	vec3 R1 = cross( vSigmaY, vN );",
+		"	vec3 R2 = cross( vN, vSigmaX );",
+
+		"	float fDet = dot( vSigmaX, R1 );",
+		
+		"	fDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );",
+		
+		"	vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
+		
+		"	return normalize( abs( fDet ) * surf_norm - vGrad );",
+
+		"}"
+
+	].join( "\n" ), [ dHdxy_fwd ], { derivatives: true } );
+
+	var bumpToNormal = new FunctionNode( [
+		"vec3 bumpToNormal( sampler2D bumpMap, vec2 uv, float 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 ), .5 - ( dBy * scale ), 1.0 );",
+		
+		"}"
+	].join( "\n" ), null, { derivatives: true } );
+	
+	return {
+		dHdxy_fwd: dHdxy_fwd,
+		perturbNormalArb: perturbNormalArb,
+		bumpToNormal: bumpToNormal
+	};
+	
+})();
+
+BumpMapNode.prototype = Object.create( TempNode.prototype );
+BumpMapNode.prototype.constructor = BumpMapNode;
+BumpMapNode.prototype.nodeType = "BumpMap";
+
+BumpMapNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		if ( this.toNormalMap ) {
+	
+			var bumpToNormal = builder.include( BumpMapNode.Nodes.bumpToNormal );
+		
+			return builder.format( bumpToNormal + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' +
+				this.value.uv.build( builder, 'v2' ) + ', ' +
+				this.scale.build( builder, 'f' ) + ' )', this.getType( builder ), output );
+				
+		} else {
+			
+			var derivativeHeight = builder.include( BumpMapNode.Nodes.dHdxy_fwd ),
+				perturbNormalArb = builder.include( BumpMapNode.Nodes.perturbNormalArb );
+		
+			this.normal = this.normal || new NormalNode( NormalNode.VIEW );
+			this.position = this.position || new PositionNode( PositionNode.VIEW );
+		
+			var derivativeHeightCode = derivativeHeight + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' +
+				this.value.uv.build( builder, 'v2' ) + ', ' +
+				this.scale.build( builder, 'f' ) + ' )';
+
+			return builder.format( perturbNormalArb + '( -' + this.position.build( builder, 'v3' ) + ', ' +
+				this.normal.build( builder, 'v3' ) + ', ' +
+				derivativeHeightCode + ' )', this.getType( builder ), output );
+			
+		}
+
+	} else {
+
+		console.warn( "THREE.BumpMapNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec3( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+BumpMapNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	this.scale = source.scale;
+					
+};
+
+BumpMapNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.scale = this.scale.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { BumpMapNode };

+ 117 - 0
examples/js/nodes/misc/NormalMapNode.js

@@ -0,0 +1,117 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { Vector2Node } from '../inputs/Vector2Node.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { UVNode } from '../accessors/UVNode.js';
+import { NormalNode } from '../accessors/NormalNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+
+function NormalMapNode( value, scale ) {
+
+	TempNode.call( this, 'v3' );
+
+	this.value = value;
+	this.scale = scale || new Vector2Node( 1, 1 );
+
+};
+
+NormalMapNode.Nodes = (function() {
+	
+	var perturbNormal2Arb = new 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 normalScale ) {",
+
+		// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
+		
+		"	vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );",
+		"	vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );",
+		"	vec2 st0 = dFdx( mUv.st );",
+		"	vec2 st1 = dFdy( mUv.st );",
+		
+		"	float scale = sign( st1.t * st0.s - st0.t * st1.s );", // we do not care about the magnitude
+		
+		"	vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );",
+		"	vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );",
+		"	vec3 N = normalize( surf_norm );",
+		"	mat3 tsn = mat3( S, T, N );",
+		
+		"	vec3 mapN = map * 2.0 - 1.0;",
+		
+		"	mapN.xy *= normalScale;",
+		"	mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );",
+		
+		"	return normalize( tsn * mapN );",
+
+		"}"
+
+	].join( "\n" ), null, { derivatives: true } );
+
+	return {
+		perturbNormal2Arb: perturbNormal2Arb
+	};
+	
+})();
+
+NormalMapNode.prototype = Object.create( TempNode.prototype );
+NormalMapNode.prototype.constructor = NormalMapNode;
+NormalMapNode.prototype.nodeType = "NormalMap";
+
+NormalMapNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		var perturbNormal2Arb = builder.include( NormalMapNode.Nodes.perturbNormal2Arb );
+
+		this.normal = this.normal || new NormalNode( NormalNode.VIEW );
+		this.position = this.position || new PositionNode( PositionNode.VIEW );
+		this.uv = this.uv || new UVNode();
+
+		return builder.format( perturbNormal2Arb + '( -' + this.position.build( builder, 'v3' ) + ', ' +
+			this.normal.build( builder, 'v3' ) + ', ' +
+			this.value.build( builder, 'v3' ) + ', ' +
+			this.uv.build( builder, 'v2' ) + ', ' +
+			this.scale.build( builder, 'v2' ) + ' )', this.getType( builder ), output );
+
+	} else {
+
+		console.warn( "THREE.NormalMapNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec3( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+NormalMapNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	this.scale = source.scale;
+	
+};
+
+NormalMapNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.scale = this.scale.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { NormalMapNode };

+ 64 - 0
examples/js/nodes/misc/TextureCubeNode.js

@@ -0,0 +1,64 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { TextureCubeUVNode } from './TextureCubeUVNode.js';
+ 
+function TextureCubeNode( value, uv ) {
+
+	TempNode.call( this, 'v4' );
+
+	this.value = value;
+	this.uv = uv || new TextureCubeUVNode();
+
+};
+
+TextureCubeNode.prototype = Object.create( TempNode.prototype );
+TextureCubeNode.prototype.constructor = TextureCubeNode;
+TextureCubeNode.prototype.nodeType = "TextureCube";
+
+TextureCubeNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		var uv_10 = this.uv.build( builder ) + '.uv_10',
+			uv_20 = this.uv.build( builder ) + '.uv_20',
+			t = this.uv.build( builder ) + '.t';
+		
+		var color10 = builder.getTexelDecodingFunctionFromTexture( 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_10 + ' )', this.value.value ),
+			color20 = builder.getTexelDecodingFunctionFromTexture( 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_20 + ' )', this.value.value );
+
+		return builder.format( 'vec4( mix( ' + color10 + ', ' + color20 + ', ' + t + ' ).rgb, 1.0 )', this.getType( builder ), output );
+			
+	} else {
+
+		console.warn( "THREE.TextureCubeNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+TextureCubeNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.uv = this.uv.toJSON( meta ).uuid;
+		data.textureSize = this.textureSize.toJSON( meta ).uuid;
+		data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;
+
+		if ( this.roughness ) data.roughness = this.roughness.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { TextureCubeNode };

+ 209 - 0
examples/js/nodes/misc/TextureCubeUVNode.js

@@ -0,0 +1,209 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { ConstNode } from '../core/ConstNode.js';
+import { StructNode } from '../core/StructNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { ReflectNode } from '../accessors/ReflectNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { BlinnExponentToRoughnessNode } from '../bsdfs/BlinnExponentToRoughnessNode.js';
+ 
+function TextureCubeUVNode( uv, textureSize, blinnExponentToRoughness ) {
+
+	TempNode.call( this, 'TextureCubeUVData' ); // TextureCubeUVData is type as StructNode
+
+	this.uv = uv || new ReflectNode( ReflectNode.VECTOR );
+	this.textureSize = textureSize || new FloatNode( 1024 );
+	this.blinnExponentToRoughness = this.blinnExponentToRoughness || new BlinnExponentToRoughnessNode();
+
+};
+
+TextureCubeUVNode.Nodes = (function() {
+
+	var TextureCubeUVData = new StructNode([
+		"struct TextureCubeUVData {",
+		"	vec2 uv_10;",
+		"	vec2 uv_20;",
+		"	float t;",
+		"}"
+	].join( "\n" ));
+	
+	var getFaceFromDirection = new FunctionNode( [
+		"int getFaceFromDirection(vec3 direction) {",
+		"	vec3 absDirection = abs(direction);",
+		"	int face = -1;",
+		"	if( absDirection.x > absDirection.z ) {",
+		"		if(absDirection.x > absDirection.y )",
+		"			face = direction.x > 0.0 ? 0 : 3;",
+		"		else",
+		"			face = direction.y > 0.0 ? 1 : 4;",
+		"	}",
+		"	else {",
+		"		if(absDirection.z > absDirection.y )",
+		"			face = direction.z > 0.0 ? 2 : 5;",
+		"		else",
+		"			face = direction.y > 0.0 ? 1 : 4;",
+		"	}",
+		"	return face;",
+		"}"
+	].join( "\n" ) );
+	
+	var cubeUV_maxLods1 = new ConstNode( "#define cubeUV_maxLods1 ( log2( cubeUV_textureSize * 0.25 ) - 1.0 )" );
+	var cubeUV_rangeClamp = new ConstNode( "#define cubeUV_rangeClamp ( exp2( ( 6.0 - 1.0 ) * 2.0 ) )" );
+	
+	var MipLevelInfo = new FunctionNode( [
+		"vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness, in float cubeUV_textureSize ) {",
+		"	float scale = exp2(cubeUV_maxLods1 - roughnessLevel);",
+		"	float dxRoughness = dFdx(roughness);",
+		"	float dyRoughness = dFdy(roughness);",
+		"	vec3 dx = dFdx( vec * scale * dxRoughness );",
+		"	vec3 dy = dFdy( vec * scale * dyRoughness );",
+		"	float d = max( dot( dx, dx ), dot( dy, dy ) );",
+			// Clamp the value to the max mip level counts. hard coded to 6 mips"
+		"	d = clamp(d, 1.0, cubeUV_rangeClamp);",
+		"	float mipLevel = 0.5 * log2(d);",
+		"	return vec2(floor(mipLevel), fract(mipLevel));",
+		"}" 
+	].join( "\n" ), [ cubeUV_maxLods1, cubeUV_rangeClamp ], { derivatives: true } );
+	
+	var cubeUV_maxLods2 = new ConstNode( "#define cubeUV_maxLods2 ( log2( cubeUV_textureSize * 0.25 ) - 2.0 )" );
+	var cubeUV_rcpTextureSize = new ConstNode( "#define cubeUV_rcpTextureSize ( 1.0 / cubeUV_textureSize )" );
+
+	var getCubeUV = new FunctionNode( [
+		"vec2 getCubeUV( vec3 direction, float roughnessLevel, float mipLevel, in float cubeUV_textureSize ) {",
+		"	mipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;",
+		"	float a = 16.0 * cubeUV_rcpTextureSize;",
+		"",
+		"	vec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );",
+		"	vec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;",
+			// float powScale = exp2(roughnessLevel + mipLevel);"
+		"	float powScale = exp2_packed.x * exp2_packed.y;",
+			// float scale =  1.0 / exp2(roughnessLevel + 2.0 + mipLevel);"
+		"	float scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;",
+			// float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);"
+		"	float mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;",
+		"",
+		"	bool bRes = mipLevel == 0.0;",
+		"	scale =  bRes && (scale < a) ? a : scale;",
+		"",
+		"	vec3 r;",
+		"	vec2 offset;",
+		"	int face = getFaceFromDirection(direction);",
+		"",
+		"	float rcpPowScale = 1.0 / powScale;",
+		"",
+		"	if( face == 0) {",
+		"		r = vec3(direction.x, -direction.z, direction.y);",
+		"		offset = vec2(0.0+mipOffset,0.75 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
+		"	}",
+		"	else if( face == 1) {",
+		"		r = vec3(direction.y, direction.x, direction.z);",
+		"		offset = vec2(scale+mipOffset, 0.75 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
+		"	}",
+		"	else if( face == 2) {",
+		"		r = vec3(direction.z, direction.x, direction.y);",
+		"		offset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
+		"	}",
+		"	else if( face == 3) {",
+		"		r = vec3(direction.x, direction.z, direction.y);",
+		"		offset = vec2(0.0+mipOffset,0.5 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
+		"	}",
+		"	else if( face == 4) {",
+		"		r = vec3(direction.y, direction.x, -direction.z);",
+		"		offset = vec2(scale+mipOffset, 0.5 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
+		"	}",
+		"	else {",
+		"		r = vec3(direction.z, -direction.x, direction.y);",
+		"		offset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);",
+		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
+		"	}",
+		"	r = normalize(r);",
+		"	float texelOffset = 0.5 * cubeUV_rcpTextureSize;",
+		"	vec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;",
+		"	vec2 base = offset + vec2( texelOffset );",
+		"	return base + s * ( scale - 2.0 * texelOffset );",
+		"}" 
+	].join( "\n" ), [ cubeUV_maxLods2, cubeUV_rcpTextureSize, getFaceFromDirection ] );
+	
+	var cubeUV_maxLods3 = new ConstNode( "#define cubeUV_maxLods3 ( log2( cubeUV_textureSize * 0.25 ) - 3.0 )" );
+	
+	var textureCubeUV = new FunctionNode( [
+		"TextureCubeUVData textureCubeUV( vec3 reflectedDirection, float roughness, in float cubeUV_textureSize ) {",
+		"	float roughnessVal = roughness * cubeUV_maxLods3;",
+		"	float r1 = floor(roughnessVal);",
+		"	float r2 = r1 + 1.0;",
+		"	float t = fract(roughnessVal);",
+		"	vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness, cubeUV_textureSize);",
+		"	float s = mipInfo.y;",
+		"	float level0 = mipInfo.x;",
+		"	float level1 = level0 + 1.0;",
+		"	level1 = level1 > 5.0 ? 5.0 : level1;",
+		"",
+			// round to nearest mipmap if we are not interpolating."
+		"	level0 += min( floor( s + 0.5 ), 5.0 );",
+		"",
+			// Tri linear interpolation."
+		"	vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0, cubeUV_textureSize);",
+		"	vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, cubeUV_textureSize);",
+		"",
+		"	return TextureCubeUVData(uv_10, uv_20, t);",
+		"}" 
+	].join( "\n" ), [ TextureCubeUVData, cubeUV_maxLods3, MipLevelInfo, getCubeUV ] );
+	
+	return {
+		TextureCubeUVData: TextureCubeUVData,
+		textureCubeUV: textureCubeUV
+	};
+	
+})();
+
+TextureCubeUVNode.prototype = Object.create( TempNode.prototype );
+TextureCubeUVNode.prototype.constructor = TextureCubeUVNode;
+TextureCubeUVNode.prototype.nodeType = "TextureCubeUV";
+
+TextureCubeUVNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		var textureCubeUV = builder.include( TextureCubeUVNode.Nodes.textureCubeUV );
+	
+		return builder.format( textureCubeUV + '( ' + this.uv.build( builder, 'v3' ) + ', ' +
+			this.blinnExponentToRoughness.build( builder, 'f' ) + ', ' +
+			this.textureSize.build( builder, 'f' ) + ' )', this.getType( builder ), output );
+			
+	} else {
+
+		console.warn( "THREE.TextureCubeUVNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+TextureCubeUVNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.uv = this.uv.toJSON( meta ).uuid;
+		data.textureSize = this.textureSize.toJSON( meta ).uuid;
+		data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { TextureCubeUVNode };

+ 21 - 8
examples/js/nodes/postprocessing/NodePass.js

@@ -2,7 +2,12 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodePass = function () {
+import { NodeUtils } from '../core/NodeUtils.js';
+import { NodeMaterial } from '../materials/NodeMaterial.js';
+import { RawNode } from '../materials/nodes/RawNode.js';
+import { ScreenNode } from '../inputs/ScreenNode.js';
+
+function NodePass() {
 
 	THREE.ShaderPass.call( this );
 
@@ -13,21 +18,21 @@ THREE.NodePass = function () {
 
 	this.textureID = 'renderTexture';
 
-	this.fragment = new THREE.RawNode( new THREE.ScreenNode() );
+	this.fragment = new RawNode( new ScreenNode() );
 
-	this.node = new THREE.NodeMaterial();
+	this.node = new NodeMaterial();
 	this.node.fragment = this.fragment;
 
 	this.needsUpdate = true;
 
 };
 
-THREE.NodePass.prototype = Object.create( THREE.ShaderPass.prototype );
-THREE.NodePass.prototype.constructor = THREE.NodePass;
+NodePass.prototype = Object.create( THREE.ShaderPass.prototype );
+NodePass.prototype.constructor = NodePass;
 
-THREE.NodeMaterial.addShortcuts( THREE.NodePass.prototype, 'fragment', [ 'value' ] );
+NodeUtils.addShortcuts( NodePass.prototype, 'fragment', [ 'value' ] );
 
-THREE.NodePass.prototype.render = function () {
+NodePass.prototype.render = function () {
 
 	if ( this.needsUpdate ) {
 
@@ -44,7 +49,13 @@ THREE.NodePass.prototype.render = function () {
 
 };
 
-THREE.NodePass.prototype.toJSON = function ( meta ) {
+NodePass.prototype.copy = function ( source ) {
+	
+	this.value = source.value;
+	
+};
+
+NodePass.prototype.toJSON = function ( meta ) {
 
 	var isRootObject = ( meta === undefined || typeof meta === 'string' );
 
@@ -80,3 +91,5 @@ THREE.NodePass.prototype.toJSON = function ( meta ) {
 	return meta;
 
 };
+
+export { NodePass };

+ 69 - 0
examples/js/nodes/procedural/NoiseNode.js

@@ -0,0 +1,69 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { UVNode } from '../accessors/UVNode.js';
+
+function NoiseNode( uv ) {
+
+	TempNode.call( this, 'f' );
+
+	this.uv = uv || new UVNode();
+
+};
+
+NoiseNode.prototype = Object.create( TempNode.prototype );
+NoiseNode.prototype.constructor = NoiseNode;
+NoiseNode.prototype.nodeType = "Noise";
+
+NoiseNode.Nodes = (function() {
+	
+	var snoise = new FunctionNode( [
+		"float snoise(vec2 co) {",
+		
+		"	return fract( sin( dot( co.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453 );",
+		
+		"}"
+	].join( "\n" ) );
+
+	return {
+		snoise: snoise
+	};
+	
+})();
+
+NoiseNode.prototype.generate = function ( builder, output ) {
+
+	var snoise = builder.include( NoiseNode.Nodes.snoise );
+
+	return builder.format( snoise + '( ' + this.uv.build( builder, 'v2' ) + ' )', this.getType( builder ), output );
+
+};
+
+NoiseNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.uv = source.uv;
+	
+};
+
+NoiseNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.uv = this.uv.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { NoiseNode };

+ 0 - 136
examples/js/nodes/utils/BlurNode.js

@@ -1,136 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.BlurNode = function ( value, coord, radius, size ) {
-
-	THREE.TempNode.call( this, 'v4' );
-
-	this.value = value;
-	this.coord = coord || new THREE.UVNode();
-	this.radius = new THREE.Vector2Node( 1, 1 );
-	this.size = size;
-
-	this.blurX = true;
-	this.blurY = true;
-
-	this.horizontal = new THREE.FloatNode( 1 / 64 );
-	this.vertical = new THREE.FloatNode( 1 / 64 );
-
-};
-
-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;",
-	"}"
-].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;",
-	"}"
-].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 ( frame ) {
-
-	if ( this.size ) {
-
-		this.horizontal.value = this.radius.x / this.size.x;
-		this.vertical.value = this.radius.y / this.size.y;
-
-	} else if ( this.value.value && this.value.value.image ) {
-
-		var image = this.value.value.image;
-
-		this.horizontal.value = this.radius.x / image.width;
-		this.vertical.value = this.radius.y / image.height;
-
-	}
-
-};
-
-THREE.BlurNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material, blurX = THREE.BlurNode.fBlurX, blurY = THREE.BlurNode.fBlurY;
-
-	builder.include( blurX );
-	builder.include( blurY );
-
-	if ( builder.isShader( 'fragment' ) ) {
-
-		var blurCode = [], code;
-
-		if ( this.blurX ) {
-
-			blurCode.push( blurX.name + '(' + this.value.build( builder, 'sampler2D' ) + ',' + this.coord.build( builder, 'v2' ) + ',' + this.horizontal.build( builder, 'fv1' ) + ')' );
-
-		}
-
-		if ( this.blurY ) {
-
-			blurCode.push( blurY.name + '(' + this.value.build( builder, 'sampler2D' ) + ',' + this.coord.build( builder, 'v2' ) + ',' + this.vertical.build( builder, 'fv1' ) + ')' );
-
-		}
-
-		if ( blurCode.length == 2 ) code = '(' + blurCode.join( '+' ) + '/2.0)';
-		else if ( blurCode.length ) code = '(' + blurCode[ 0 ] + ')';
-		else code = 'vec4( 0.0 )';
-
-		return builder.format( code, this.getType( builder ), output );
-
-	} else {
-
-		console.warn( "THREE.BlurNode is not compatible with " + builder.shader + " shader." );
-
-		return builder.format( 'vec4( 0.0 )', this.getType( 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;
-
-};

+ 0 - 68
examples/js/nodes/utils/BumpNode.js

@@ -1,68 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.BumpNode = function ( value, coord, scale ) {
-
-	THREE.TempNode.call( this, 'v3' );
-
-	this.value = value;
-	this.coord = coord || new THREE.UVNode();
-	this.scale = scale || new THREE.Vector2Node( 1, 1 );
-
-};
-
-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 );",
-	"}"
-].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 ) {
-
-	var material = builder.material, func = THREE.BumpNode.fBumpToNormal;
-
-	builder.include( func );
-
-	if ( builder.isShader( 'fragment' ) ) {
-
-		return builder.format( func.name + '(' + this.value.build( builder, 'sampler2D' ) + ',' +
-			this.coord.build( builder, 'v2' ) + ',' +
-			this.scale.build( builder, 'v2' ) + ')', this.getType( builder ), output );
-
-	} else {
-
-		console.warn( "THREE.BumpNode is not compatible with " + builder.shader + " shader." );
-
-		return builder.format( 'vec3( 0.0 )', this.getType( 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;
-
-};

+ 85 - 0
examples/js/nodes/utils/BypassNode.js

@@ -0,0 +1,85 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from '../core/GLNode.js';
+
+function BypassNode( code, value ) {
+
+	GLNode.call( this );
+
+	this.code = code;
+	this.value = value;
+
+};
+
+BypassNode.prototype = Object.create( GLNode.prototype );
+BypassNode.prototype.constructor = BypassNode;
+BypassNode.prototype.nodeType = "Bypass";
+
+BypassNode.prototype.getType = function ( builder ) {
+
+	if ( this.value ) {
+		
+		return this.value.getType( builder );
+		
+	} else if (builder.isShader( 'fragment' )) {
+		
+		return 'f';
+		
+	}
+	
+	return 'void';
+
+};
+
+BypassNode.prototype.generate = function ( builder, output ) {
+
+	var code = this.code.build( builder, output ) + ';';
+
+	builder.addNodeCode( code );
+	
+	if ( builder.isShader( 'vertex' ) ) {
+		
+		if (this.value) {
+		
+			return this.value.build( builder, output );
+			
+		}
+		
+	} else {
+		
+		return this.value ? this.value.build( builder, output ) : builder.format( '0.0', 'f', output );
+		
+	}
+
+};
+
+BypassNode.prototype.copy = function ( source ) {
+	
+	GLNode.prototype.copy.call( this, source );
+	
+	this.code = source.code;
+	this.value = source.value;
+	
+};
+
+BypassNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.code = this.code.toJSON( meta ).uuid;
+
+		if (this.value) data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { BypassNode };

+ 0 - 89
examples/js/nodes/utils/ColorAdjustmentNode.js

@@ -1,89 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.ColorAdjustmentNode = function ( rgb, adjustment, method ) {
-
-	THREE.TempNode.call( this, 'v3' );
-
-	this.rgb = rgb;
-	this.adjustment = adjustment;
-
-	this.method = method || THREE.ColorAdjustmentNode.SATURATION;
-
-};
-
-THREE.ColorAdjustmentNode.SATURATION = 'saturation';
-THREE.ColorAdjustmentNode.HUE = 'hue';
-THREE.ColorAdjustmentNode.VIBRANCE = 'vibrance';
-THREE.ColorAdjustmentNode.BRIGHTNESS = 'brightness';
-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 ) {
-
-	var rgb = this.rgb.build( builder, 'v3' );
-	var adjustment = this.adjustment.build( builder, 'fv1' );
-
-	var name;
-
-	switch ( this.method ) {
-
-		case THREE.ColorAdjustmentNode.SATURATION:
-
-			name = 'saturation_rgb';
-
-			break;
-
-		case THREE.ColorAdjustmentNode.HUE:
-
-			name = 'hue_rgb';
-
-			break;
-
-		case THREE.ColorAdjustmentNode.VIBRANCE:
-
-			name = 'vibrance_rgb';
-
-			break;
-
-		case THREE.ColorAdjustmentNode.BRIGHTNESS:
-
-			return builder.format( '(' + rgb + '+' + adjustment + ')', this.getType( builder ), output );
-
-			break;
-
-		case THREE.ColorAdjustmentNode.CONTRAST:
-
-			return builder.format( '(' + rgb + '*' + adjustment + ')', this.getType( builder ), output );
-
-			break;
-
-	}
-
-	builder.include( name );
-
-	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;
-
-};

+ 35 - 23
examples/js/nodes/utils/JoinNode.js

@@ -2,9 +2,14 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.JoinNode = function ( x, y, z, w ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
+ 
+var inputs = NodeUtils.elements;
+ 
+function JoinNode( x, y, z, w ) {
 
-	THREE.TempNode.call( this, 'fv1' );
+	TempNode.call( this, 'f' );
 
 	this.x = x;
 	this.y = y;
@@ -13,15 +18,12 @@ THREE.JoinNode = function ( x, y, z, w ) {
 
 };
 
-THREE.JoinNode.inputs = [ 'x', 'y', 'z', 'w' ];
+JoinNode.prototype = Object.create( TempNode.prototype );
+JoinNode.prototype.constructor = JoinNode;
+JoinNode.prototype.nodeType = "Join";
 
-THREE.JoinNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.JoinNode.prototype.constructor = THREE.JoinNode;
-THREE.JoinNode.prototype.nodeType = "Join";
+JoinNode.prototype.getNumElements = function () {
 
-THREE.JoinNode.prototype.getNumElements = function () {
-
-	var inputs = THREE.JoinNode.inputs;
 	var i = inputs.length;
 
 	while ( i -- ) {
@@ -29,6 +31,7 @@ THREE.JoinNode.prototype.getNumElements = function () {
 		if ( this[ inputs[ i ] ] !== undefined ) {
 
 			++ i;
+			
 			break;
 
 		}
@@ -39,37 +42,45 @@ THREE.JoinNode.prototype.getNumElements = function () {
 
 };
 
-THREE.JoinNode.prototype.getType = function ( builder ) {
+JoinNode.prototype.getType = function ( builder ) {
 
-	return builder.getFormatFromLength( this.getNumElements() );
+	return builder.getTypeFromLength( this.getNumElements() );
 
 };
 
-THREE.JoinNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getType( builder );
-	var length = this.getNumElements();
+JoinNode.prototype.generate = function ( builder, output ) {
 
-	var inputs = THREE.JoinNode.inputs;
-	var outputs = [];
+	var type = this.getType( builder ),
+		length = this.getNumElements(),
+		outputs = [];
 
 	for ( var i = 0; i < length; i ++ ) {
 
 		var elm = this[ inputs[ i ] ];
 
-		outputs.push( elm ? elm.build( builder, 'fv1' ) : '0.' );
+		outputs.push( elm ? elm.build( builder, 'f' ) : '0.0' );
 
 	}
 
-	var code = ( length > 1 ? builder.getConstructorFromLength( length ) : '' ) + '(' + outputs.join( ',' ) + ')';
+	var code = ( length > 1 ? builder.getConstructorFromLength( length ) : '' ) + '( ' + outputs.join( ', ' ) + ' )';
 
 	return builder.format( code, type, output );
 
 };
 
-THREE.JoinNode.prototype.toJSON = function ( meta ) {
+JoinNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	for ( var prop in source.inputs ) {
+
+		this[ prop ] = source.inputs[ prop ];
+
+	}
+	
+};
+
+JoinNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -80,7 +91,6 @@ THREE.JoinNode.prototype.toJSON = function ( meta ) {
 		data.inputs = {};
 
 		var length = this.getNumElements();
-		var inputs = THREE.JoinNode.inputs;
 
 		for ( var i = 0; i < length; i ++ ) {
 
@@ -100,3 +110,5 @@ THREE.JoinNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { JoinNode };

+ 0 - 39
examples/js/nodes/utils/LuminanceNode.js

@@ -1,39 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.LuminanceNode = function ( rgb ) {
-
-	THREE.TempNode.call( this, 'fv1' );
-
-	this.rgb = 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 ) {
-
-	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;
-
-};

+ 61 - 0
examples/js/nodes/utils/MaxMIPLevelNode.js

@@ -0,0 +1,61 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { FloatNode } from '../inputs/FloatNode.js';
+ 
+function MaxMIPLevelNode( texture ) {
+
+	FloatNode.call( this );
+
+	this.texture = texture;
+
+	this.maxMIPLevel = 0;
+
+};
+
+MaxMIPLevelNode.prototype = Object.create( FloatNode.prototype );
+MaxMIPLevelNode.prototype.constructor = MaxMIPLevelNode;
+MaxMIPLevelNode.prototype.nodeType = "MaxMIPLevel";
+
+Object.defineProperties( MaxMIPLevelNode.prototype, {
+
+	value: {
+		
+		get: function () {
+
+			if ( this.maxMIPLevel === 0 ) {
+
+				var image = this.texture.value.image ? this.texture.value.image[0] : undefined;
+
+				this.maxMIPLevel = image !== undefined ? ( Math.log( Math.max( image.width, image.height ) ) + 1 ) * Math.LOG2E : 0;
+
+			}
+
+			return this.maxMIPLevel;
+
+		},
+		
+		set: function () { }
+		
+	}
+
+} );
+
+MaxMIPLevelNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.texture = this.texture.uuid;
+
+	}
+
+	return data;
+
+};
+
+export { MaxMIPLevelNode };

+ 0 - 39
examples/js/nodes/utils/NoiseNode.js

@@ -1,39 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NoiseNode = function ( coord ) {
-
-	THREE.TempNode.call( this, 'fv1' );
-
-	this.coord = 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 ) {
-
-	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;
-
-};

+ 0 - 63
examples/js/nodes/utils/NormalMapNode.js

@@ -1,63 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NormalMapNode = function ( value, uv, scale, normal, position ) {
-
-	THREE.TempNode.call( this, 'v3' );
-
-	this.value = value;
-	this.scale = scale || new THREE.FloatNode( 1 );
-
-	this.normal = normal || new THREE.NormalNode( THREE.NormalNode.LOCAL );
-	this.position = position || new THREE.PositionNode( THREE.NormalNode.VIEW );
-
-};
-
-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 ) {
-
-	var material = builder.material;
-
-	builder.include( 'perturbNormal2Arb' );
-
-	if ( builder.isShader( 'fragment' ) ) {
-
-		return builder.format( 'perturbNormal2Arb(-' + this.position.build( builder, 'v3' ) + ',' +
-			this.normal.build( builder, 'v3' ) + ',' +
-			this.value.build( builder, 'v3' ) + ',' +
-			this.value.coord.build( builder, 'v2' ) + ',' +
-			this.scale.build( builder, 'v2' ) + ')', this.getType( builder ), output );
-
-	} else {
-
-		console.warn( "THREE.NormalMapNode is not compatible with " + builder.shader + " shader." );
-
-		return builder.format( 'vec3( 0.0 )', this.getType( 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;
-
-};

+ 0 - 41
examples/js/nodes/utils/ResolutionNode.js

@@ -1,41 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.ResolutionNode = function ( renderer ) {
-
-	THREE.Vector2Node.call( this );
-
-	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 ( frame ) {
-
-	var size = this.renderer.getSize(),
-		pixelRatio = this.renderer.getPixelRatio();
-
-	this.x = size.width * pixelRatio;
-	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;
-
-};

+ 0 - 65
examples/js/nodes/utils/RoughnessToBlinnExponentNode.js

@@ -1,65 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.RoughnessToBlinnExponentNode = function () {
-
-	THREE.TempNode.call( this, 'fv1' );
-
-};
-
-THREE.RoughnessToBlinnExponentNode.getSpecularMIPLevel = new THREE.FunctionNode( [
-// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
-	"float getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {",
-
-	//	float envMapWidth = pow( 2.0, maxMIPLevelScalar );
-	//	float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
-	"	float maxMIPLevelScalar = float( maxMIPLevel );",
-	"	float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );",
-
-	// clamp to allowable LOD ranges.
-	"	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
-	"}"
-].join( "\n" ) );
-
-THREE.RoughnessToBlinnExponentNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.RoughnessToBlinnExponentNode.prototype.constructor = THREE.RoughnessToBlinnExponentNode;
-THREE.RoughnessToBlinnExponentNode.prototype.nodeType = "RoughnessToBlinnExponent";
-
-THREE.RoughnessToBlinnExponentNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	if ( builder.isShader( 'fragment' ) ) {
-
-		if ( material.isDefined( 'PHYSICAL' ) ) {
-
-			builder.include( THREE.RoughnessToBlinnExponentNode.getSpecularMIPLevel );
-
-			if ( builder.isCache( 'clearCoat' ) ) {
-
-				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 {
-
-			console.warn( "THREE.RoughnessToBlinnExponentNode is only compatible with PhysicalMaterial." );
-
-			return builder.format( '0.0', this.type, output );
-
-		}
-
-	} else {
-
-		console.warn( "THREE.RoughnessToBlinnExponentNode is not compatible with " + builder.shader + " shader." );
-
-		return builder.format( '0.0', this.type, output );
-
-	}
-
-};

+ 27 - 15
examples/js/nodes/utils/SwitchNode.js

@@ -2,38 +2,39 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SwitchNode = function ( node, components ) {
+import { GLNode } from '../core/GLNode.js';
+ 
+function SwitchNode( node, components ) {
 
-	THREE.GLNode.call( this );
+	GLNode.call( this );
 
 	this.node = node;
 	this.components = components || 'x';
 
 };
 
-THREE.SwitchNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.SwitchNode.prototype.constructor = THREE.SwitchNode;
-THREE.SwitchNode.prototype.nodeType = "Switch";
+SwitchNode.prototype = Object.create( GLNode.prototype );
+SwitchNode.prototype.constructor = SwitchNode;
+SwitchNode.prototype.nodeType = "Switch";
 
-THREE.SwitchNode.prototype.getType = function ( builder ) {
+SwitchNode.prototype.getType = function ( builder ) {
 
-	return builder.getFormatFromLength( this.components.length );
+	return builder.getTypeFromLength( this.components.length );
 
 };
 
-THREE.SwitchNode.prototype.generate = function ( builder, output ) {
+SwitchNode.prototype.generate = function ( builder, output ) {
 
-	var type = this.node.getType( builder );
-	var inputLength = builder.getFormatLength( type ) - 1;
-
-	var node = this.node.build( builder, type );
+	var type = this.node.getType( builder ),
+		node = this.node.build( builder, type ),
+		inputLength = builder.getTypeLength( type ) - 1;
 
 	if ( inputLength > 0 ) {
 
 		// get max length
 
-		var outputLength = 0;
-		var components = builder.colorToVector( this.components );
+		var outputLength = 0,
+			components = builder.colorToVectorProperties( this.components );
 
 		var i, len = components.length;
 
@@ -72,7 +73,16 @@ THREE.SwitchNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.SwitchNode.prototype.toJSON = function ( meta ) {
+SwitchNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	this.node = source.node;
+	this.components = source.components;
+	
+};
+
+SwitchNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -88,3 +98,5 @@ THREE.SwitchNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { SwitchNode };

+ 41 - 18
examples/js/nodes/utils/TimerNode.js

@@ -2,51 +2,54 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TimerNode = function ( scale, scope ) {
+import { FloatNode } from '../inputs/FloatNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+function TimerNode( scale, scope, useTimeScale ) {
 
-	THREE.FloatNode.call( this );
+	FloatNode.call( this );
 
 	this.scale = scale !== undefined ? scale : 1;
-	this.scope = scope || THREE.TimerNode.GLOBAL;
+	this.scope = scope || TimerNode.GLOBAL;
 
-	this.timeScale = this.scale !== 1;
+	this.useTimeScale = useTimeScale !== undefined ? useTimeScale : this.scale !== 1;
 
 };
 
-THREE.TimerNode.GLOBAL = 'global';
-THREE.TimerNode.LOCAL = 'local';
-THREE.TimerNode.DELTA = 'delta';
+TimerNode.GLOBAL = 'global';
+TimerNode.LOCAL = 'local';
+TimerNode.DELTA = 'delta';
 
-THREE.TimerNode.prototype = Object.create( THREE.FloatNode.prototype );
-THREE.TimerNode.prototype.constructor = THREE.TimerNode;
-THREE.TimerNode.prototype.nodeType = "Timer";
+TimerNode.prototype = Object.create( FloatNode.prototype );
+TimerNode.prototype.constructor = TimerNode;
+TimerNode.prototype.nodeType = "Timer";
 
-THREE.TimerNode.prototype.isReadonly = function ( builder ) {
+TimerNode.prototype.isReadonly = function () {
 
 	return false;
 
 };
 
-THREE.TimerNode.prototype.isUnique = function ( builder ) {
+TimerNode.prototype.isUnique = function () {
 
 	// share TimerNode "uniform" input if is used on more time with others TimerNode
-	return this.timeScale && ( this.scope === THREE.TimerNode.GLOBAL || this.scope === THREE.TimerNode.DELTA );
+	return this.timeScale && ( this.scope === TimerNode.GLOBAL || this.scope === TimerNode.DELTA );
 
 };
 
-THREE.TimerNode.prototype.updateFrame = function ( frame ) {
+TimerNode.prototype.updateFrame = function ( frame ) {
 
 	var scale = this.timeScale ? this.scale : 1;
 
 	switch( this.scope ) {
 
-		case THREE.TimerNode.LOCAL:
+		case TimerNode.LOCAL:
 
 			this.value += frame.delta * scale;
 
 			break;
 
-		case THREE.TimerNode.DELTA:
+		case TimerNode.DELTA:
 
 			this.value = frame.delta * scale;
 
@@ -60,7 +63,18 @@ THREE.TimerNode.prototype.updateFrame = function ( frame ) {
 
 };
 
-THREE.TimerNode.prototype.toJSON = function ( meta ) {
+TimerNode.prototype.copy = function ( source ) {
+			
+	FloatNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	this.scale = source.scale;
+	
+	this.useTimeScale = source.useTimeScale;
+	
+};
+
+TimerNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -70,10 +84,19 @@ THREE.TimerNode.prototype.toJSON = function ( meta ) {
 
 		data.scope = this.scope;
 		data.scale = this.scale;
-		data.timeScale = this.timeScale;
+		
+		data.useTimeScale = this.useTimeScale;
 
 	}
 
 	return data;
 
 };
+
+NodeLib.addKeyword( 'time', function () {
+
+	return new TimerNode();
+
+} );
+
+export { TimerNode };

+ 26 - 11
examples/js/nodes/utils/UVTransformNode.js

@@ -2,29 +2,33 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.UVTransformNode = function () {
+import { FunctionNode } from '../core/FunctionNode.js';
+import { Matrix3Node } from '../inputs/Matrix3Node.js';
+import { UVNode } from '../accessors/UVNode.js';
+ 
+function UVTransformNode( uv, transform ) {
 
-	THREE.FunctionNode.call( this, "( uvTransform * vec3( uvNode, 1 ) ).xy", "vec2" );
+	FunctionNode.call( this, "( uvTransform * vec3( uvNode, 1 ) ).xy", "vec2" );
 
-	this.uv = new THREE.UVNode();
-	this.transform = new THREE.Matrix3Node();
+	this.uv = uv || new UVNode();
+	this.transform = transform || new Matrix3Node();
 
 };
 
-THREE.UVTransformNode.prototype = Object.create( THREE.FunctionNode.prototype );
-THREE.UVTransformNode.prototype.constructor = THREE.UVTransformNode;
-THREE.UVTransformNode.prototype.nodeType = "UVTransform";
+UVTransformNode.prototype = Object.create( FunctionNode.prototype );
+UVTransformNode.prototype.constructor = UVTransformNode;
+UVTransformNode.prototype.nodeType = "UVTransform";
 
-THREE.UVTransformNode.prototype.generate = function ( builder, output ) {
+UVTransformNode.prototype.generate = function ( builder, output ) {
 
 	this.keywords[ "uvNode" ] = this.uv;
 	this.keywords[ "uvTransform" ] = this.transform;
 
-	return THREE.FunctionNode.prototype.generate.call( this, builder, output );
+	return FunctionNode.prototype.generate.call( this, builder, output );
 
 };
 
-THREE.UVTransformNode.prototype.setUvTransform = function ( tx, ty, sx, sy, rotation, cx, cy ) {
+UVTransformNode.prototype.setUvTransform = function ( tx, ty, sx, sy, rotation, cx, cy ) {
 
 	cx = cx !== undefined ? cx : .5;
 	cy = cy !== undefined ? cy : .5;
@@ -33,7 +37,16 @@ THREE.UVTransformNode.prototype.setUvTransform = function ( tx, ty, sx, sy, rota
 
 };
 
-THREE.UVTransformNode.prototype.toJSON = function ( meta ) {
+UVTransformNode.prototype.copy = function ( source ) {
+			
+	FunctionNode.prototype.copy.call( this, source );
+	
+	this.uv = source.uv;
+	this.transform = source.transform;
+					
+};
+
+UVTransformNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -49,3 +62,5 @@ THREE.UVTransformNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { UVTransformNode };

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

@@ -2,9 +2,11 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.VelocityNode = function ( target, params ) {
+import { Vector3Node } from '../inputs/Vector3Node.js';
+ 
+function VelocityNode( target, params ) {
 
-	THREE.Vector3Node.call( this );
+	Vector3Node.call( this );
 
 	this.params = {};
 
@@ -15,17 +17,17 @@ THREE.VelocityNode = function ( target, params ) {
 
 };
 
-THREE.VelocityNode.prototype = Object.create( THREE.Vector3Node.prototype );
-THREE.VelocityNode.prototype.constructor = THREE.VelocityNode;
-THREE.VelocityNode.prototype.nodeType = "Velocity";
+VelocityNode.prototype = Object.create( Vector3Node.prototype );
+VelocityNode.prototype.constructor = VelocityNode;
+VelocityNode.prototype.nodeType = "Velocity";
 
-THREE.VelocityNode.prototype.isReadonly = function ( builder ) {
+VelocityNode.prototype.isReadonly = function ( builder ) {
 
 	return false;
 
 };
 
-THREE.VelocityNode.prototype.setParams = function ( params ) {
+VelocityNode.prototype.setParams = function ( params ) {
 
 	switch ( this.params.type ) {
 
@@ -61,7 +63,7 @@ THREE.VelocityNode.prototype.setParams = function ( params ) {
 
 };
 
-THREE.VelocityNode.prototype.setTarget = function ( target ) {
+VelocityNode.prototype.setTarget = function ( target ) {
 
 	if ( this.target ) {
 
@@ -81,7 +83,7 @@ THREE.VelocityNode.prototype.setTarget = function ( target ) {
 
 };
 
-THREE.VelocityNode.prototype.updateFrameVelocity = function ( frame ) {
+VelocityNode.prototype.updateFrameVelocity = function ( frame ) {
 
 	if ( this.target ) {
 
@@ -93,7 +95,7 @@ THREE.VelocityNode.prototype.updateFrameVelocity = function ( frame ) {
 
 };
 
-THREE.VelocityNode.prototype.updateFrame = function ( frame ) {
+VelocityNode.prototype.updateFrame = function ( frame ) {
 
 	this.updateFrameVelocity( frame );
 
@@ -140,7 +142,17 @@ THREE.VelocityNode.prototype.updateFrame = function ( frame ) {
 
 };
 
-THREE.VelocityNode.prototype.toJSON = function ( meta ) {
+VelocityNode.prototype.copy = function ( source ) {
+			
+	Vector3Node.prototype.copy.call( this, source );
+	
+	if ( source.target ) object.setTarget( source.target );
+	
+	object.setParams( source.params );
+	
+};
+
+VelocityNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -158,3 +170,5 @@ THREE.VelocityNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { VelocityNode };

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
examples/nodes/caustic.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
examples/nodes/displace.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
examples/nodes/wave.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
examples/nodes/xray.json


+ 4 - 69
examples/webgl_loader_nodes.html

@@ -40,75 +40,10 @@
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/libs/dat.gui.min.js"></script>
 
-		<!-- NodeLibrary -->
-		<script src="js/nodes/GLNode.js"></script>
-		<script src="js/nodes/RawNode.js"></script>
-		<script src="js/nodes/TempNode.js"></script>
-		<script src="js/nodes/InputNode.js"></script>
-		<script src="js/nodes/ConstNode.js"></script>
-		<script src="js/nodes/VarNode.js"></script>
-		<script src="js/nodes/FunctionNode.js"></script>
-		<script src="js/nodes/FunctionCallNode.js"></script>
-		<script src="js/nodes/AttributeNode.js"></script>
-		<script src="js/nodes/NodeUniform.js"></script>
-		<script src="js/nodes/NodeBuilder.js"></script>
-		<script src="js/nodes/NodeLib.js"></script>
-		<script src="js/nodes/NodeFrame.js"></script>
-		<script src="js/nodes/NodeMaterial.js"></script>
-
-		<!-- Accessors -->
-		<script src="js/nodes/accessors/PositionNode.js"></script>
-		<script src="js/nodes/accessors/NormalNode.js"></script>
-		<script src="js/nodes/accessors/UVNode.js"></script>
-		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
-		<script src="js/nodes/accessors/ColorsNode.js"></script>
-		<script src="js/nodes/accessors/CameraNode.js"></script>
-		<script src="js/nodes/accessors/ReflectNode.js"></script>
-		<script src="js/nodes/accessors/LightNode.js"></script>
-
-		<!-- Inputs -->
-		<script src="js/nodes/inputs/IntNode.js"></script>
-		<script src="js/nodes/inputs/FloatNode.js"></script>
-		<script src="js/nodes/inputs/ColorNode.js"></script>
-		<script src="js/nodes/inputs/Vector2Node.js"></script>
-		<script src="js/nodes/inputs/Vector3Node.js"></script>
-		<script src="js/nodes/inputs/Vector4Node.js"></script>
-		<script src="js/nodes/inputs/TextureNode.js"></script>
-		<script src="js/nodes/inputs/Matrix4Node.js"></script>
-		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
-
-		<!-- Math -->
-		<script src="js/nodes/math/Math1Node.js"></script>
-		<script src="js/nodes/math/Math2Node.js"></script>
-		<script src="js/nodes/math/Math3Node.js"></script>
-		<script src="js/nodes/math/OperatorNode.js"></script>
-
-		<!-- Utils -->
-		<script src="js/nodes/utils/SwitchNode.js"></script>
-		<script src="js/nodes/utils/JoinNode.js"></script>
-		<script src="js/nodes/utils/TimerNode.js"></script>
-		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
-		<script src="js/nodes/utils/VelocityNode.js"></script>
-		<script src="js/nodes/utils/LuminanceNode.js"></script>
-		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
-		<script src="js/nodes/utils/NoiseNode.js"></script>
-		<script src="js/nodes/utils/ResolutionNode.js"></script>
-		<script src="js/nodes/utils/BumpNode.js"></script>
-		<script src="js/nodes/utils/BlurNode.js"></script>
-		<script src="js/nodes/utils/UVTransformNode.js"></script>
-
-		<!-- Phong Material -->
-		<script src="js/nodes/materials/PhongNode.js"></script>
-		<script src="js/nodes/materials/PhongNodeMaterial.js"></script>
-
-		<!-- Standard Material -->
-		<script src="js/nodes/materials/StandardNode.js"></script>
-		<script src="js/nodes/materials/StandardNodeMaterial.js"></script>
-
-		<!-- NodeMaterial Loader -->
-		<script src="js/loaders/NodeMaterialLoader.js"></script>
-
-		<script>
+		<script type="module">
+
+		import './js/nodes/THREE.Nodes.js';
+		import './js/loaders/NodeMaterialLoader.js';
 
 		var container = document.getElementById( 'container' );
 

+ 3 - 62
examples/webgl_materials_compile.html

@@ -59,68 +59,9 @@
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/libs/dat.gui.min.js"></script>
 
-		<!-- NodeLibrary -->
-		<script src="js/nodes/GLNode.js"></script>
-		<script src="js/nodes/RawNode.js"></script>
-		<script src="js/nodes/TempNode.js"></script>
-		<script src="js/nodes/InputNode.js"></script>
-		<script src="js/nodes/ConstNode.js"></script>
-		<script src="js/nodes/VarNode.js"></script>
-		<script src="js/nodes/FunctionNode.js"></script>
-		<script src="js/nodes/FunctionCallNode.js"></script>
-		<script src="js/nodes/AttributeNode.js"></script>
-		<script src="js/nodes/NodeUniform.js"></script>
-		<script src="js/nodes/NodeBuilder.js"></script>
-		<script src="js/nodes/NodeLib.js"></script>
-		<script src="js/nodes/NodeFrame.js"></script>
-		<script src="js/nodes/NodeMaterial.js"></script>
-
-		<!-- Accessors -->
-		<script src="js/nodes/accessors/PositionNode.js"></script>
-		<script src="js/nodes/accessors/NormalNode.js"></script>
-		<script src="js/nodes/accessors/UVNode.js"></script>
-		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
-		<script src="js/nodes/accessors/ColorsNode.js"></script>
-		<script src="js/nodes/accessors/CameraNode.js"></script>
-		<script src="js/nodes/accessors/ReflectNode.js"></script>
-		<script src="js/nodes/accessors/LightNode.js"></script>
-
-		<!-- Inputs -->
-		<script src="js/nodes/inputs/IntNode.js"></script>
-		<script src="js/nodes/inputs/FloatNode.js"></script>
-		<script src="js/nodes/inputs/ColorNode.js"></script>
-		<script src="js/nodes/inputs/Vector2Node.js"></script>
-		<script src="js/nodes/inputs/Vector3Node.js"></script>
-		<script src="js/nodes/inputs/Vector4Node.js"></script>
-		<script src="js/nodes/inputs/TextureNode.js"></script>
-		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
-
-		<!-- Math -->
-		<script src="js/nodes/math/Math1Node.js"></script>
-		<script src="js/nodes/math/Math2Node.js"></script>
-		<script src="js/nodes/math/Math3Node.js"></script>
-		<script src="js/nodes/math/OperatorNode.js"></script>
-
-		<!-- Utils -->
-		<script src="js/nodes/utils/SwitchNode.js"></script>
-		<script src="js/nodes/utils/JoinNode.js"></script>
-		<script src="js/nodes/utils/TimerNode.js"></script>
-		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
-		<script src="js/nodes/utils/VelocityNode.js"></script>
-		<script src="js/nodes/utils/LuminanceNode.js"></script>
-		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
-		<script src="js/nodes/utils/NoiseNode.js"></script>
-		<script src="js/nodes/utils/ResolutionNode.js"></script>
-		<script src="js/nodes/utils/BumpNode.js"></script>
-		<script src="js/nodes/utils/BlurNode.js"></script>
-
-		<!-- Phong Material -->
-		<script src="js/nodes/materials/PhongNode.js"></script>
-		<script src="js/nodes/materials/PhongNodeMaterial.js"></script>
-
-		<script>
-
-		/* global THREE */
+		<script type="module">
+
+		import './js/nodes/THREE.Nodes.js';
 
 		var container = document.getElementById( 'container' );
 

+ 195 - 134
examples/webgl_materials_nodes.html

@@ -31,7 +31,7 @@
 		<div id="container"></div>
 		<div id="info">
 			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Node-Based Material</br>
-			<a id="serialize" onclick="toggleSerialize()" href="javascript:void(0);">Serialize and apply</a>
+			<a id="serialize" href="javascript:void(0);">Serialize and apply</a>
 		</div>
 
 		<script src="../build/three.js"></script>
@@ -39,77 +39,11 @@
 		<script src='js/geometries/TeapotBufferGeometry.js'></script>
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/libs/dat.gui.min.js"></script>
+		
+		<script type="module">
 
-		<!-- NodeLibrary -->
-		<script src="js/nodes/GLNode.js"></script>
-		<script src="js/nodes/RawNode.js"></script>
-		<script src="js/nodes/TempNode.js"></script>
-		<script src="js/nodes/InputNode.js"></script>
-		<script src="js/nodes/ConstNode.js"></script>
-		<script src="js/nodes/VarNode.js"></script>
-		<script src="js/nodes/FunctionNode.js"></script>
-		<script src="js/nodes/FunctionCallNode.js"></script>
-		<script src="js/nodes/AttributeNode.js"></script>
-		<script src="js/nodes/NodeUniform.js"></script>
-		<script src="js/nodes/NodeBuilder.js"></script>
-		<script src="js/nodes/NodeLib.js"></script>
-		<script src="js/nodes/NodeFrame.js"></script>
-		<script src="js/nodes/NodeMaterial.js"></script>
-
-		<!-- Accessors -->
-		<script src="js/nodes/accessors/PositionNode.js"></script>
-		<script src="js/nodes/accessors/NormalNode.js"></script>
-		<script src="js/nodes/accessors/UVNode.js"></script>
-		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
-		<script src="js/nodes/accessors/ColorsNode.js"></script>
-		<script src="js/nodes/accessors/CameraNode.js"></script>
-		<script src="js/nodes/accessors/ReflectNode.js"></script>
-		<script src="js/nodes/accessors/LightNode.js"></script>
-
-		<!-- Inputs -->
-		<script src="js/nodes/inputs/IntNode.js"></script>
-		<script src="js/nodes/inputs/FloatNode.js"></script>
-		<script src="js/nodes/inputs/ColorNode.js"></script>
-		<script src="js/nodes/inputs/Vector2Node.js"></script>
-		<script src="js/nodes/inputs/Vector3Node.js"></script>
-		<script src="js/nodes/inputs/Vector4Node.js"></script>
-		<script src="js/nodes/inputs/TextureNode.js"></script>
-		<script src="js/nodes/inputs/Matrix3Node.js"></script>
-		<script src="js/nodes/inputs/Matrix4Node.js"></script>
-		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
-
-		<!-- Math -->
-		<script src="js/nodes/math/Math1Node.js"></script>
-		<script src="js/nodes/math/Math2Node.js"></script>
-		<script src="js/nodes/math/Math3Node.js"></script>
-		<script src="js/nodes/math/OperatorNode.js"></script>
-
-		<!-- Utils -->
-		<script src="js/nodes/utils/SwitchNode.js"></script>
-		<script src="js/nodes/utils/JoinNode.js"></script>
-		<script src="js/nodes/utils/TimerNode.js"></script>
-		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
-		<script src="js/nodes/utils/VelocityNode.js"></script>
-		<script src="js/nodes/utils/LuminanceNode.js"></script>
-		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
-		<script src="js/nodes/utils/NoiseNode.js"></script>
-		<script src="js/nodes/utils/ResolutionNode.js"></script>
-		<script src="js/nodes/utils/BumpNode.js"></script>
-		<script src="js/nodes/utils/BlurNode.js"></script>
-		<script src="js/nodes/utils/UVTransformNode.js"></script>
-
-		<!-- Phong Material -->
-		<script src="js/nodes/materials/PhongNode.js"></script>
-		<script src="js/nodes/materials/PhongNodeMaterial.js"></script>
-
-		<!-- Standard Material -->
-		<script src="js/nodes/materials/StandardNode.js"></script>
-		<script src="js/nodes/materials/StandardNodeMaterial.js"></script>
-
-		<!-- NodeMaterial Loader -->
-		<script src="js/loaders/NodeMaterialLoader.js"></script>
-
-		<script>
+		import './js/nodes/THREE.Nodes.js';
+		import './js/loaders/NodeMaterialLoader.js';
 
 		var container = document.getElementById( 'container' );
 
@@ -131,7 +65,7 @@
 			spherical: { url: 'textures/envmap.png' }
 		};
 
-		var param = { example: 'standard' };
+		var param = { example: new URL(window.location.href).searchParams.get('e') || 'mesh-standard' };
 
 		function getTexture( name ) {
 
@@ -227,6 +161,7 @@
 			gui = new dat.GUI();
 
 			var example = gui.add( param, 'example', {
+				'basic / mesh-standard': 'mesh-standard',
 				'basic / standard': 'standard',
 				'basic / physical': 'physical',
 				'basic / phong': 'phong',
@@ -257,6 +192,7 @@
 				'misc / firefly': 'firefly',
 				'misc / reserved-keywords': 'reserved-keywords',
 				'misc / varying': 'varying',
+				'misc / void-function': 'void-function',
 				'misc / readonly': 'readonly',
 				'misc / custom-attribute': 'custom-attribute'
 			} ).onFinishChange( function () {
@@ -315,7 +251,7 @@
 
 			if ( rtTexture ) {
 
-				delete library[ rtTexture.uuid ];
+				delete library[ rtTexture.texture.uuid ];
 
 				rtTexture.dispose();
 				rtTexture = null;
@@ -346,8 +282,7 @@
 					//mtl.alpha = // opacity (float)
 					//mtl.specular = // specular color (vec3)
 					//mtl.shininess = // shininess (float)
-					//mtl.normal = // normalmap (vec3)
-					//mtl.normalScale = // normalmap scale (vec2)
+					//mtl.normal = // normal (vec3)
 					//mtl.emissive = // emissive color (vec3)
 					//mtl.ambient = // ambient color (vec3)
 					//mtl.shadow = // shadowmap (vec3)
@@ -365,8 +300,8 @@
 					mtl.shininess = new THREE.FloatNode( 15 );
 					mtl.environment = new THREE.CubeTextureNode( cubemap );
 					mtl.environmentAlpha = mask;
-					mtl.normal = new THREE.TextureNode( getTexture( "grassNormal" ) );
-					mtl.normalScale = new THREE.Math1Node( mask, THREE.Math1Node.INVERT );
+					mtl.normal = new THREE.NormalMapNode( new THREE.TextureNode( getTexture( "grassNormal" ) ) );
+					mtl.normal.scale = new THREE.Math1Node( mask, THREE.Math1Node.INVERT );
 
 					break;
 
@@ -380,8 +315,7 @@
 					//mtl.alpha = // opacity (float)
 					//mtl.roughness = // roughness (float)
 					//mtl.metalness = // metalness (float)
-					//mtl.normal = // normalmap (vec3)
-					//mtl.normalScale = // normalmap scale (vec2)
+					//mtl.normal = // normal (vec3)
 					//mtl.emissive = // emissive color (vec3)
 					//mtl.ambient = // ambient color (vec3)
 					//mtl.shadow = // shadowmap (vec3)
@@ -424,8 +358,8 @@
 					mtl.roughness = roughness;
 					mtl.metalness = metalness;
 					mtl.environment = new THREE.CubeTextureNode( cubemap );
-					mtl.normal = new THREE.TextureNode( getTexture( "grassNormal" ) );
-					mtl.normalScale = normalMask;
+					mtl.normal = new THREE.NormalMapNode( new THREE.TextureNode( getTexture( "grassNormal" ) ) );
+					mtl.normal.scale = normalMask;
 
 					// GUI
 
@@ -467,6 +401,82 @@
 
 					break;
 
+				case 'mesh-standard':
+
+					// MATERIAL
+					
+					var sataturation = new THREE.FloatNode( 1 );
+					
+					function updateMaterial( useNodeMaterial ) {
+					
+						var oldMaterial = mtl;
+					
+						if (oldMaterial) oldMaterial.dispose();
+					
+						mtl = useNodeMaterial ? new THREE.MeshStandardNodeMaterial() : new THREE.MeshStandardMaterial();
+					
+						// default syntax ( backward-compatible )
+					
+						mtl.map = getTexture( "brick" );
+						
+						mtl.normalMap = getTexture( "grassNormal" );
+						mtl.normalScale = new THREE.Vector2( .3, -.3 );
+						
+						mtl.envMap = cubemap;
+						
+						mtl.roughness = oldMaterial ? oldMaterial.roughness : .5;
+						mtl.metalness = oldMaterial ? oldMaterial.metalness : .5;
+						
+						// extended syntax ( only for NodeMaterial )
+						
+						if (useNodeMaterial) {
+						
+							mtl.map = new THREE.ColorAdjustmentNode( 
+								new THREE.TextureNode( mtl.map ), 
+								sataturation, 
+								THREE.ColorAdjustmentNode.SATURATION 
+							);
+							
+						}
+						
+						// apply material
+					
+						mtl.needsUpdate = true;
+					
+						mesh.material = mtl;
+
+					}
+
+					updateMaterial( true );
+					
+					// GUI
+					
+					addGui( 'use node material', true, function ( val ) {
+
+						updateMaterial( val );
+
+					} );
+					
+					addGui( 'roughness', mtl.roughness, function ( val ) {
+
+						mtl.roughness = val;
+
+					}, false, 0, 1 );
+
+					addGui( 'metalness', mtl.roughness, function ( val ) {
+
+						mtl.metalness = val;
+
+					}, false, 0, 1 );
+					
+					addGui( 'sat. (node)', sataturation.value, function ( val ) {
+
+						sataturation.value = val;
+
+					}, false, 0, 2 );
+					
+					break;
+					
 				case 'physical':
 
 					// MATERIAL
@@ -480,8 +490,7 @@
 					//mtl.reflectivity = // reflectivity (float)
 					//mtl.clearCoat = // clearCoat (float)
 					//mtl.clearCoatRoughness = // clearCoatRoughness (float)
-					//mtl.normal = // normalmap (vec3)
-					//mtl.normalScale = // normalmap scale (vec2)
+					//mtl.normal = // normal (vec3)
 					//mtl.emissive = // emissive color (vec3)
 					//mtl.ambient = // ambient color (vec3)
 					//mtl.shadow = // shadowmap (vec3)
@@ -531,8 +540,8 @@
 					mtl.clearCoat = clearCoat;
 					mtl.clearCoatRoughness = clearCoatRoughness;
 					mtl.environment = new THREE.CubeTextureNode( cubemap );
-					mtl.normal = new THREE.TextureNode( getTexture( "grassNormal" ) );
-					mtl.normalScale = normalMask;
+					mtl.normal = new THREE.NormalMapNode( new THREE.TextureNode( getTexture( "grassNormal" ) ) );
+					mtl.normal.scale = normalMask;
 
 					// GUI
 
@@ -858,8 +867,8 @@
 					var scale = new THREE.Vector2( 1, 1 );
 
 					var texture = new THREE.TextureNode( getTexture( "brick" ) );
-					texture.coord = new THREE.UVTransformNode();
-					//texture.coord.uv = new THREE.UVNode( 1 ); // uv2 for example
+					texture.uv = new THREE.UVTransformNode();
+					//texture.uv.uv = new THREE.UVNode( 1 ); // uv2 for example
 
 					mtl.color = texture;
 
@@ -867,7 +876,7 @@
 
 					function updateUVTransform() {
 
-						texture.coord.setUvTransform( translate.x, translate.y, scale.x, scale.y, THREE.Math.degToRad( rotate ) );
+						texture.uv.setUvTransform( translate.x, translate.y, scale.x, scale.y, THREE.Math.degToRad( rotate ) );
 
 					}
 
@@ -921,23 +930,21 @@
 
 					var diffuse = new THREE.TextureNode( getTexture( "brick" ) );
 
-					var bump = new THREE.BumpNode( new THREE.TextureNode( getTexture( "brick" ) ) );
-					bump.scale = new THREE.Vector2Node( - 1.5, - 1.5 );
+					var bumpMap = new THREE.BumpMapNode( new THREE.TextureNode( getTexture( "brick" ) ) );
+					bumpMap.scale = new THREE.FloatNode( .5 );
 
 					mtl.color = diffuse;
-					mtl.normal = bump;
+					mtl.normal = bumpMap;
 
+					// convert BumpMap to NormalMap
+					//bumpMap.toNormalMap = true;
+					//mtl.normal = new THREE.NormalMapNode( bumpMap );
+					
 					// GUI
 
-					addGui( 'scaleX', bump.scale.x, function ( val ) {
-
-						bump.scale.x = val;
-
-					}, false, - 2, 2 );
-
-					addGui( 'scaleY', bump.scale.y, function ( val ) {
+					addGui( 'scale', bumpMap.scale.value, function ( val ) {
 
-						bump.scale.y = val;
+						bumpMap.scale.value = val;
 
 					}, false, - 2, 2 );
 
@@ -1106,12 +1113,12 @@
 					var sat = new THREE.FloatNode( 0 );
 
 					var satrgb = new THREE.FunctionNode( [
-						"vec3 satrgb(vec3 rgb, float adjustment) {",
-						//"	const vec3 W = vec3(0.2125, 0.7154, 0.0721);", // LUMA
-						"	vec3 intensity = vec3(dot(rgb, LUMA));",
-						"	return mix(intensity, rgb, adjustment);",
+						"vec3 satrgb( vec3 rgb, float adjustment ) {",
+						// include luminance function from LuminanceNode
+						"	vec3 intensity = vec3( luminance( rgb ) );",
+						"	return mix( intensity, rgb, adjustment );",
 						"}"
-					].join( "\n" ) );
+					].join( "\n" ), [ THREE.LuminanceNode.Nodes.luminance ] );
 
 					var saturation = new THREE.FunctionCallNode( satrgb );
 					saturation.inputs.rgb = tex;
@@ -1667,8 +1674,8 @@
 					);
 
 					mtl.color = color;
-					mtl.normal = new THREE.TextureNode( getTexture( "grassNormal" ) );
-					mtl.normalScale = furScale;
+					mtl.normal = new THREE.NormalMapNode( new THREE.TextureNode( getTexture( "grassNormal" ) ) );
+					mtl.normal.scale = furScale;
 					mtl.environment = mildnessColor;
 					mtl.environmentAlpha = new THREE.Math1Node( viewZ, THREE.Math1Node.INVERT );
 					mtl.shininess = new THREE.FloatNode( 0 );
@@ -1860,7 +1867,7 @@
 					// APPLY
 
 					mtl.color = color;
-					mtl.light = posCelLight;
+					mtl.light = new THREE.LightNode();
 					mtl.shininess = new THREE.FloatNode( 0 );
 
 					mtl.environment = lineColor;
@@ -1993,36 +2000,76 @@
 					mtl.color = new THREE.FunctionCallNode( keywordsexample, [ new THREE.TextureNode( getTexture( "brick" ) ) ] );
 
 					break;
-
+					
 				case 'varying':
 
 					// MATERIAL
 
 					mtl = new THREE.PhongNodeMaterial();
 
+					var varying = new THREE.VarNode( "vec3" );
+					varying.value = new THREE.NormalNode( THREE.NormalNode.VIEW );
+					
+					// using BypassNode the NormalNode not apply the value in .transform slot
+					// but set the NormalNode value in VarNode
+					// it can be useful to send values between vertex to fragment shader
+					// without affect vertex shader
+					mtl.transform = new THREE.BypassNode( varying );
+					mtl.color = varying;
+					
+					// you can also set a independent value in .transform slot using BypassNode
+					// such this expression using FunctionNode
+					mtl.transform.value = new THREE.FunctionNode("position * ( .1 + abs( sin( time ) ) )", "vec3");
+
+					break;
+					
+				case 'void-function':
+
+					// MATERIAL
+
+					mtl = new THREE.PhongNodeMaterial();
+
 					var varying = new THREE.VarNode( "vec3" );
 
+					// VERTEX
+					
 					var setMyVar = new THREE.FunctionNode( [
-						"float setMyVar( vec3 pos ) {",
+						"void setMyVar( vec3 pos ) {",
 						// set "myVar" in vertex shader in this example,
 						// can be used in fragment shader too or in rest of the current shader
 						"	myVar = pos;",
-						// it is not accept "void" functions for now!
-						"	return 0.;",
+						
 						"}"
 					].join( "\n" ) );
 
 					// add keyword
 					setMyVar.keywords[ "myVar" ] = varying;
 
-					var transform = new THREE.FunctionNode( "setMyVar( position * .1 ) + position", "vec3", [ setMyVar ] );
+					var transform = new THREE.FunctionNode( "setMyVar( position * .1 )", "vec3" );
+					transform.includes = [ setMyVar ];
 					transform.keywords[ "tex" ] = new THREE.TextureNode( getTexture( "brick" ) );
 
-					mtl.transform = transform;
-					mtl.color = varying;
-
-					break;
+					// use BypassNode to "void" functions
+					mtl.transform = new THREE.BypassNode( transform );
+					
+					// FRAGMENT
+					
+					var clipFromPos = new THREE.FunctionNode( [
+						"void clipFromPos( vec3 pos ) {",
+						
+						"	if ( pos.y < .0 ) discard;",
+						
+						"}"
+					].join( "\n" ) );
+					
+					var clipFromPosCall = new THREE.FunctionCallNode( clipFromPos, {
+						pos: varying
+					} );
+					
+					mtl.color = new THREE.BypassNode( clipFromPosCall, varying );
 
+					break;	
+				
 				case 'readonly':
 
 					// MATERIAL
@@ -2191,7 +2238,7 @@
 
 					rtTexture = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBFormat } );
 
-					library[ rtTexture.uuid ] = rtTexture;
+					library[ rtTexture.texture.uuid ] = rtTexture.texture;
 
 					var distanceMtl = new THREE.PhongNodeMaterial();
 					distanceMtl.environment = objectDepth;
@@ -2203,7 +2250,7 @@
 
 					mtl = new THREE.StandardNodeMaterial();
 
-					var backSideDepth = new THREE.TextureNode( rtTexture, new THREE.ScreenUVNode( new THREE.ResolutionNode( renderer ) ) );
+					var backSideDepth = new THREE.TextureNode( rtTexture.texture, new THREE.ScreenUVNode( new THREE.ResolutionNode( renderer ) ) );
 
 					var difference = new THREE.OperatorNode(
 						objectDepth,
@@ -2322,14 +2369,14 @@
 
 		}
 
-		function toggleSerialize() {
+		document.getElementById( 'serialize' ).addEventListener('click', function () {
 
 			if ( serialized ) reset();
 			else serialize();
 
 			serialized = ! serialized;
 
-		}
+		});
 
 		function reset() {
 
@@ -2344,23 +2391,29 @@
 
 		function serialize() {
 
-			var json = mesh.material.toJSON(),
-				loader = new THREE.NodeMaterialLoader( null, library ),
-				material = loader.parse( json );
-
-			mesh.material = material;
-
-			// replace uuid to url (facilitates the load of textures using url otherside uuid)
-			// example:
-
-			THREE.NodeMaterialLoaderUtils.replaceUUID( json, getTexture( "cloud" ), "cloud" );
+			var json = mesh.material.toJSON();
+				
+			// replace uuid to url (facilitates the load of textures using url otherside uuid) e.g:
 
-			// get source
+			var cloud = getTexture( "cloud" );
+			
+			THREE.NodeMaterialLoaderUtils.replaceUUID( json, cloud, "cloud" );
 
+			library[ "cloud" ] = cloud;
+			
+			// --
+			
 			var jsonStr = JSON.stringify( json );
-
+			
 			console.log( jsonStr );
-
+			
+			var loader = new THREE.NodeMaterialLoader( null, library ),
+				material = loader.parse( json );
+			
+			mesh.material.dispose();
+			
+			mesh.material = material;
+			
 			// gui
 
 			var div = document.getElementById( 'serialize' );
@@ -2392,9 +2445,17 @@
 			//mesh.rotation.z += .01;
 
 			// update material animation and/or gpu calcs (pre-renderer)
-			frame.update( delta ).updateNode( mesh.material );
+			
+			frame.update( delta );
+			
+			if ( mesh.material instanceof THREE.NodeMaterial ) {
+			
+				frame.updateNode( mesh.material );
+				
+			}
 
 			// render to texture for sss/translucent material only
+			
 			if ( rtTexture ) {
 
 				scene.overrideMaterial = rtMaterial;

+ 9 - 67
examples/webgl_mirror_nodes.html

@@ -40,68 +40,10 @@
 		<script src="js/objects/ReflectorRTT.js"></script>
 		<script src="js/controls/OrbitControls.js"></script>
 
-		<!-- NodeLibrary -->
-		<script src="js/nodes/GLNode.js"></script>
-		<script src="js/nodes/RawNode.js"></script>
-		<script src="js/nodes/TempNode.js"></script>
-		<script src="js/nodes/InputNode.js"></script>
-		<script src="js/nodes/ConstNode.js"></script>
-		<script src="js/nodes/FunctionNode.js"></script>
-		<script src="js/nodes/FunctionCallNode.js"></script>
-		<script src="js/nodes/NodeUniform.js"></script>
-		<script src="js/nodes/NodeBuilder.js"></script>
-		<script src="js/nodes/NodeLib.js"></script>
-		<script src="js/nodes/NodeFrame.js"></script>
-		<script src="js/nodes/NodeMaterial.js"></script>
-
-		<!-- Accessors -->
-		<script src="js/nodes/accessors/PositionNode.js"></script>
-		<script src="js/nodes/accessors/NormalNode.js"></script>
-		<script src="js/nodes/accessors/UVNode.js"></script>
-		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
-		<script src="js/nodes/accessors/ColorsNode.js"></script>
-		<script src="js/nodes/accessors/CameraNode.js"></script>
-		<script src="js/nodes/accessors/ReflectNode.js"></script>
-		<script src="js/nodes/accessors/LightNode.js"></script>
-
-		<!-- Inputs -->
-		<script src="js/nodes/inputs/IntNode.js"></script>
-		<script src="js/nodes/inputs/FloatNode.js"></script>
-		<script src="js/nodes/inputs/ColorNode.js"></script>
-		<script src="js/nodes/inputs/Vector2Node.js"></script>
-		<script src="js/nodes/inputs/Vector3Node.js"></script>
-		<script src="js/nodes/inputs/Vector4Node.js"></script>
-		<script src="js/nodes/inputs/TextureNode.js"></script>
-		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
-		<script src="js/nodes/inputs/Matrix4Node.js"></script>
-		<script src="js/nodes/inputs/ReflectorNode.js"></script>
-
-		<!-- Math -->
-		<script src="js/nodes/math/Math1Node.js"></script>
-		<script src="js/nodes/math/Math2Node.js"></script>
-		<script src="js/nodes/math/Math3Node.js"></script>
-		<script src="js/nodes/math/OperatorNode.js"></script>
-
-		<!-- Utils -->
-		<script src="js/nodes/utils/SwitchNode.js"></script>
-		<script src="js/nodes/utils/JoinNode.js"></script>
-		<script src="js/nodes/utils/TimerNode.js"></script>
-		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
-		<script src="js/nodes/utils/VelocityNode.js"></script>
-		<script src="js/nodes/utils/LuminanceNode.js"></script>
-		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
-		<script src="js/nodes/utils/NoiseNode.js"></script>
-		<script src="js/nodes/utils/ResolutionNode.js"></script>
-		<script src="js/nodes/utils/BlurNode.js"></script>
-
-		<!-- Phong Material -->
-		<script src="js/nodes/materials/PhongNode.js"></script>
-		<script src="js/nodes/materials/PhongNodeMaterial.js"></script>
-
-		<!-- NodeMaterial Loader -->
-		<script src="js/loaders/NodeMaterialLoader.js"></script>
-
-		<script>
+		<script type="module">
+
+		import './js/nodes/THREE.Nodes.js';
+		import './js/loaders/NodeMaterialLoader.js';
 
 		// scene size
 		var WIDTH = window.innerWidth;
@@ -168,8 +110,8 @@
 
 			var mirror = new THREE.ReflectorNode( groundMirror );
 
-			var normal = new THREE.TextureNode( decalNormal );
-			var normalXY = new THREE.SwitchNode( normal, 'xy' );
+			var normalMap = new THREE.TextureNode( decalNormal );
+			var normalXY = new THREE.SwitchNode( normalMap, 'xy' );
 			var normalXYFlip = new THREE.Math1Node(
 				normalXY,
 				THREE.Math1Node.INVERT
@@ -196,8 +138,8 @@
 
 			var blurMirror = new THREE.BlurNode( mirror );
 			blurMirror.size = new THREE.Vector2( WIDTH, HEIGHT );
-			blurMirror.coord = new THREE.FunctionNode( "projCoord.xyz / projCoord.q", "vec3" );
-			blurMirror.coord.keywords[ "projCoord" ] = new THREE.OperatorNode( mirror.offset, mirror.coord, THREE.OperatorNode.ADD );
+			blurMirror.uv = new THREE.FunctionNode( "projCoord.xyz / projCoord.q", "vec3" );
+			blurMirror.uv.keywords[ "projCoord" ] = new THREE.OperatorNode( mirror.offset, mirror.uv, THREE.OperatorNode.ADD );
 			blurMirror.radius.x = blurMirror.radius.y = 0;
 
 			gui.add( { blur: blurMirror.radius.x }, "blur", 0, 25 ).onChange( function ( v ) {
@@ -209,7 +151,7 @@
 			groundMirrorMaterial = new THREE.PhongNodeMaterial();
 			groundMirrorMaterial.environment = blurMirror; // or add "mirror" variable to disable blur
 			groundMirrorMaterial.environmentAlpha = mask;
-			groundMirrorMaterial.normal = normal;
+			groundMirrorMaterial.normal = new THREE.NormalMapNode( normalMap );
 			//groundMirrorMaterial.normalScale = new THREE.FloatNode( 1 );
 
 			// test serialization

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff