Преглед на файлове

Examples: Move jsm/nodes to ES6. (#21801)

Michael Herzog преди 4 години
родител
ревизия
b13eccc8bf
променени са 69 файла, в които са добавени 4317 реда и са изтрити 4252 реда
  1. 122 120
      examples/jsm/nodes/accessors/CameraNode.js
  2. 26 24
      examples/jsm/nodes/accessors/ColorsNode.js
  3. 28 27
      examples/jsm/nodes/accessors/LightNode.js
  4. 59 57
      examples/jsm/nodes/accessors/NormalNode.js
  5. 65 63
      examples/jsm/nodes/accessors/PositionNode.js
  6. 79 77
      examples/jsm/nodes/accessors/ReflectNode.js
  7. 30 28
      examples/jsm/nodes/accessors/ResolutionNode.js
  8. 30 28
      examples/jsm/nodes/accessors/ScreenUVNode.js
  9. 27 25
      examples/jsm/nodes/accessors/UVNode.js
  10. 34 32
      examples/jsm/nodes/core/AttributeNode.js
  11. 64 62
      examples/jsm/nodes/core/ConstNode.js
  12. 6 4
      examples/jsm/nodes/core/ExpressionNode.js
  13. 54 52
      examples/jsm/nodes/core/FunctionCallNode.js
  14. 135 133
      examples/jsm/nodes/core/FunctionNode.js
  15. 46 45
      examples/jsm/nodes/core/InputNode.js
  16. 47 56
      examples/jsm/nodes/core/Node.js
  17. 247 259
      examples/jsm/nodes/core/NodeBuilder.js
  18. 13 15
      examples/jsm/nodes/core/NodeFrame.js
  19. 1 1
      examples/jsm/nodes/core/NodeLib.js
  20. 13 19
      examples/jsm/nodes/core/NodeUniform.js
  21. 4 4
      examples/jsm/nodes/core/NodeUtils.js
  22. 50 47
      examples/jsm/nodes/core/StructNode.js
  23. 69 70
      examples/jsm/nodes/core/TempNode.js
  24. 32 30
      examples/jsm/nodes/core/VarNode.js
  25. 105 103
      examples/jsm/nodes/effects/BlurNode.js
  26. 69 67
      examples/jsm/nodes/effects/ColorAdjustmentNode.js
  27. 39 37
      examples/jsm/nodes/effects/LuminanceNode.js
  28. 25 23
      examples/jsm/nodes/inputs/BoolNode.js
  29. 28 26
      examples/jsm/nodes/inputs/ColorNode.js
  30. 59 57
      examples/jsm/nodes/inputs/CubeTextureNode.js
  31. 25 23
      examples/jsm/nodes/inputs/FloatNode.js
  32. 25 23
      examples/jsm/nodes/inputs/IntNode.js
  33. 27 34
      examples/jsm/nodes/inputs/Matrix3Node.js
  34. 27 33
      examples/jsm/nodes/inputs/Matrix4Node.js
  35. 22 28
      examples/jsm/nodes/inputs/PropertyNode.js
  36. 80 77
      examples/jsm/nodes/inputs/RTTNode.js
  37. 42 40
      examples/jsm/nodes/inputs/ReflectorNode.js
  38. 14 12
      examples/jsm/nodes/inputs/ScreenNode.js
  39. 65 62
      examples/jsm/nodes/inputs/TextureNode.js
  40. 27 25
      examples/jsm/nodes/inputs/Vector2Node.js
  41. 28 26
      examples/jsm/nodes/inputs/Vector3Node.js
  42. 29 27
      examples/jsm/nodes/inputs/Vector4Node.js
  43. 104 102
      examples/jsm/nodes/materials/nodes/BasicNode.js
  44. 64 62
      examples/jsm/nodes/materials/nodes/MeshStandardNode.js
  45. 259 257
      examples/jsm/nodes/materials/nodes/PhongNode.js
  46. 30 28
      examples/jsm/nodes/materials/nodes/RawNode.js
  47. 140 137
      examples/jsm/nodes/materials/nodes/SpriteNode.js
  48. 370 368
      examples/jsm/nodes/materials/nodes/StandardNode.js
  49. 70 67
      examples/jsm/nodes/math/CondNode.js
  50. 173 171
      examples/jsm/nodes/math/MathNode.js
  51. 47 45
      examples/jsm/nodes/math/OperatorNode.js
  52. 80 78
      examples/jsm/nodes/misc/BumpMapNode.js
  53. 71 69
      examples/jsm/nodes/misc/NormalMapNode.js
  54. 44 42
      examples/jsm/nodes/misc/TextureCubeNode.js
  55. 149 147
      examples/jsm/nodes/misc/TextureCubeUVNode.js
  56. 36 38
      examples/jsm/nodes/postprocessing/NodePostProcessing.js
  57. 40 38
      examples/jsm/nodes/procedural/CheckerNode.js
  58. 36 34
      examples/jsm/nodes/procedural/NoiseNode.js
  59. 42 40
      examples/jsm/nodes/utils/BypassNode.js
  60. 99 97
      examples/jsm/nodes/utils/ColorSpaceNode.js
  61. 54 52
      examples/jsm/nodes/utils/JoinNode.js
  62. 25 28
      examples/jsm/nodes/utils/MaxMIPLevelNode.js
  63. 51 49
      examples/jsm/nodes/utils/RemapNode.js
  64. 55 53
      examples/jsm/nodes/utils/SpecularMIPLevelNode.js
  65. 35 33
      examples/jsm/nodes/utils/SubSlotNode.js
  66. 54 50
      examples/jsm/nodes/utils/SwitchNode.js
  67. 48 46
      examples/jsm/nodes/utils/TimerNode.js
  68. 34 32
      examples/jsm/nodes/utils/UVTransformNode.js
  69. 90 88
      examples/jsm/nodes/utils/VelocityNode.js

+ 122 - 120
examples/jsm/nodes/accessors/CameraNode.js

@@ -3,232 +3,234 @@ import { FunctionNode } from '../core/FunctionNode.js';
 import { FloatNode } from '../inputs/FloatNode.js';
 import { FloatNode } from '../inputs/FloatNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 
 
-function CameraNode( scope, camera ) {
+class CameraNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( scope, camera ) {
 
 
-	this.setScope( scope || CameraNode.POSITION );
-	this.setCamera( camera );
+		super( 'v3' );
 
 
-}
-
-CameraNode.Nodes = ( function () {
-
-	var depthColor = new FunctionNode( [
-		'float depthColor( float mNear, float mFar ) {',
-
-		'	#ifdef USE_LOGDEPTHBUF_EXT',
+		this.setScope( scope || CameraNode.POSITION );
+		this.setCamera( camera );
 
 
-		'		float depth = gl_FragDepthEXT / gl_FragCoord.w;',
+	}
 
 
-		'	#else',
+	setCamera( camera ) {
 
 
-		'		float depth = gl_FragCoord.z / gl_FragCoord.w;',
+		this.camera = camera;
+		this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
 
 
-		'	#endif',
+	}
 
 
-		'	return 1.0 - smoothstep( mNear, mFar, depth );',
+	setScope( scope ) {
 
 
-		'}'
-	].join( '\n' ) );
+		switch ( this.scope ) {
 
 
-	return {
-		depthColor: depthColor
-	};
+			case CameraNode.DEPTH:
 
 
-} )();
+				delete this.near;
+				delete this.far;
 
 
-CameraNode.POSITION = 'position';
-CameraNode.DEPTH = 'depth';
-CameraNode.TO_VERTEX = 'toVertex';
-
-CameraNode.prototype = Object.create( TempNode.prototype );
-CameraNode.prototype.constructor = CameraNode;
-CameraNode.prototype.nodeType = 'Camera';
+				break;
 
 
-CameraNode.prototype.setCamera = function ( camera ) {
+		}
 
 
-	this.camera = camera;
-	this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
+		this.scope = scope;
 
 
-};
+		switch ( scope ) {
 
 
-CameraNode.prototype.setScope = function ( scope ) {
+			case CameraNode.DEPTH:
 
 
-	switch ( this.scope ) {
+				const camera = this.camera;
 
 
-		case CameraNode.DEPTH:
+				this.near = new FloatNode( camera ? camera.near : 1 );
+				this.far = new FloatNode( camera ? camera.far : 1200 );
 
 
-			delete this.near;
-			delete this.far;
+				break;
 
 
-			break;
+		}
 
 
 	}
 	}
 
 
-	this.scope = scope;
+	getType( /* builder */ ) {
 
 
-	switch ( scope ) {
+		switch ( this.scope ) {
 
 
-		case CameraNode.DEPTH:
+			case CameraNode.DEPTH:
 
 
-			var camera = this.camera;
+				return 'f';
 
 
-			this.near = new FloatNode( camera ? camera.near : 1 );
-			this.far = new FloatNode( camera ? camera.far : 1200 );
+		}
 
 
-			break;
+		return this.type;
 
 
 	}
 	}
 
 
-};
+	getUnique( /* builder */ ) {
+
+		switch ( this.scope ) {
 
 
-CameraNode.prototype.getType = function ( /* builder */ ) {
+			case CameraNode.DEPTH:
+			case CameraNode.TO_VERTEX:
 
 
-	switch ( this.scope ) {
+				return true;
 
 
-		case CameraNode.DEPTH:
+		}
 
 
-			return 'f';
+		return false;
 
 
 	}
 	}
 
 
-	return this.type;
+	getShared( /* builder */ ) {
 
 
-};
+		switch ( this.scope ) {
 
 
-CameraNode.prototype.getUnique = function ( /* builder */ ) {
+			case CameraNode.POSITION:
 
 
-	switch ( this.scope ) {
+				return false;
 
 
-		case CameraNode.DEPTH:
-		case CameraNode.TO_VERTEX:
+		}
 
 
-			return true;
+		return true;
 
 
 	}
 	}
 
 
-	return false;
+	generate( builder, output ) {
 
 
-};
+		let result;
 
 
-CameraNode.prototype.getShared = function ( /* builder */ ) {
+		switch ( this.scope ) {
 
 
-	switch ( this.scope ) {
+			case CameraNode.POSITION:
 
 
-		case CameraNode.POSITION:
+				result = 'cameraPosition';
 
 
-			return false;
+				break;
 
 
-	}
+			case CameraNode.DEPTH:
 
 
-	return true;
+				const depthColor = builder.include( CameraNode.Nodes.depthColor );
 
 
-};
+				result = depthColor + '( ' + this.near.build( builder, 'f' ) + ', ' + this.far.build( builder, 'f' ) + ' )';
 
 
-CameraNode.prototype.generate = function ( builder, output ) {
+				break;
+
+			case CameraNode.TO_VERTEX:
 
 
-	var result;
+				result = 'normalize( ' + new PositionNode( PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
 
 
-	switch ( this.scope ) {
+				break;
 
 
-		case CameraNode.POSITION:
+		}
 
 
-			result = 'cameraPosition';
+		return builder.format( result, this.getType( builder ), output );
 
 
-			break;
+	}
 
 
-		case CameraNode.DEPTH:
+	onUpdateFrame( /* frame */ ) {
 
 
-			var depthColor = builder.include( CameraNode.Nodes.depthColor );
+		switch ( this.scope ) {
 
 
-			result = depthColor + '( ' + this.near.build( builder, 'f' ) + ', ' + this.far.build( builder, 'f' ) + ' )';
+			case CameraNode.DEPTH:
 
 
-			break;
+				const camera = this.camera;
 
 
-		case CameraNode.TO_VERTEX:
+				this.near.value = camera.near;
+				this.far.value = camera.far;
 
 
-			result = 'normalize( ' + new PositionNode( PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
+				break;
 
 
-			break;
+		}
 
 
 	}
 	}
 
 
-	return builder.format( result, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-CameraNode.prototype.onUpdateFrame = function ( /* frame */ ) {
+		this.setScope( source.scope );
 
 
-	switch ( this.scope ) {
+		if ( source.camera ) {
 
 
-		case CameraNode.DEPTH:
+			this.setCamera( source.camera );
 
 
-			var camera = this.camera;
+		}
+
+		switch ( source.scope ) {
 
 
-			this.near.value = camera.near;
-			this.far.value = camera.far;
+			case CameraNode.DEPTH:
 
 
-			break;
+				this.near.number = source.near;
+				this.far.number = source.far;
+
+				break;
+
+		}
+
+		return this;
 
 
 	}
 	}
 
 
-};
+	toJSON( meta ) {
 
 
-CameraNode.prototype.copy = function ( source ) {
+		let data = this.getJSONNode( meta );
 
 
-	TempNode.prototype.copy.call( this, source );
+		if ( ! data ) {
 
 
-	this.setScope( source.scope );
+			data = this.createJSONNode( meta );
 
 
-	if ( source.camera ) {
+			data.scope = this.scope;
 
 
-		this.setCamera( source.camera );
+			if ( this.camera ) data.camera = this.camera.uuid;
 
 
-	}
+			switch ( this.scope ) {
 
 
-	switch ( source.scope ) {
+				case CameraNode.DEPTH:
 
 
-		case CameraNode.DEPTH:
+					data.near = this.near.value;
+					data.far = this.far.value;
 
 
-			this.near.number = source.near;
-			this.far.number = source.far;
+					break;
 
 
-			break;
+			}
 
 
-	}
+		}
 
 
-	return this;
+		return data;
 
 
-};
+	}
 
 
-CameraNode.prototype.toJSON = function ( meta ) {
+}
 
 
-	var data = this.getJSONNode( meta );
+CameraNode.Nodes = ( function () {
 
 
-	if ( ! data ) {
+	const depthColor = new FunctionNode( [
+		'float depthColor( float mNear, float mFar ) {',
 
 
-		data = this.createJSONNode( meta );
+		'	#ifdef USE_LOGDEPTHBUF_EXT',
 
 
-		data.scope = this.scope;
+		'		float depth = gl_FragDepthEXT / gl_FragCoord.w;',
 
 
-		if ( this.camera ) data.camera = this.camera.uuid;
+		'	#else',
 
 
-		switch ( this.scope ) {
+		'		float depth = gl_FragCoord.z / gl_FragCoord.w;',
 
 
-			case CameraNode.DEPTH:
+		'	#endif',
 
 
-				data.near = this.near.value;
-				data.far = this.far.value;
+		'	return 1.0 - smoothstep( mNear, mFar, depth );',
 
 
-				break;
+		'}'
+	].join( '\n' ) );
 
 
-		}
+	return {
+		depthColor: depthColor
+	};
 
 
-	}
+} )();
 
 
-	return data;
+CameraNode.POSITION = 'position';
+CameraNode.DEPTH = 'depth';
+CameraNode.TO_VERTEX = 'toVertex';
 
 
-};
+CameraNode.prototype.nodeType = 'Camera';
 
 
 export { CameraNode };
 export { CameraNode };

+ 26 - 24
examples/jsm/nodes/accessors/ColorsNode.js

@@ -3,52 +3,54 @@ import { TempNode } from '../core/TempNode.js';
 var vertexDict = [ 'color', 'color2' ],
 var vertexDict = [ 'color', 'color2' ],
 	fragmentDict = [ 'vColor', 'vColor2' ];
 	fragmentDict = [ 'vColor', 'vColor2' ];
 
 
-function ColorsNode( index ) {
+class ColorsNode extends TempNode {
 
 
-	TempNode.call( this, 'v4', { shared: false } );
+	constructor( index ) {
 
 
-	this.index = index || 0;
+		super( 'v4', { shared: false } );
 
 
-}
+		this.index = index || 0;
 
 
-ColorsNode.prototype = Object.create( TempNode.prototype );
-ColorsNode.prototype.constructor = ColorsNode;
-ColorsNode.prototype.nodeType = 'Colors';
+	}
 
 
-ColorsNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	builder.requires.color[ this.index ] = true;
+		builder.requires.color[ this.index ] = true;
 
 
-	var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
+		const result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
 
 
-	return builder.format( result, this.getType( builder ), output );
+		return builder.format( result, this.getType( builder ), output );
 
 
-};
+	}
 
 
-ColorsNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.index = source.index;
+		this.index = source.index;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-ColorsNode.prototype.toJSON = function ( meta ) {
+	toJSON( meta ) {
 
 
-	var data = this.getJSONNode( meta );
+		let data = this.getJSONNode( meta );
 
 
-	if ( ! data ) {
+		if ( ! data ) {
 
 
-		data = this.createJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-		data.index = this.index;
+			data.index = this.index;
+
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+ColorsNode.prototype.nodeType = 'Colors';
 
 
 export { ColorsNode };
 export { ColorsNode };

+ 28 - 27
examples/jsm/nodes/accessors/LightNode.js

@@ -1,59 +1,60 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function LightNode( scope ) {
+class LightNode extends TempNode {
 
 
-	TempNode.call( this, 'v3', { shared: false } );
+	constructor( scope ) {
 
 
-	this.scope = scope || LightNode.TOTAL;
+		super( 'v3', { shared: false } );
 
 
-}
+		this.scope = scope || LightNode.TOTAL;
 
 
-LightNode.TOTAL = 'total';
+	}
 
 
-LightNode.prototype = Object.create( TempNode.prototype );
-LightNode.prototype.constructor = LightNode;
-LightNode.prototype.nodeType = 'Light';
+	generate( builder, output ) {
 
 
-LightNode.prototype.generate = function ( builder, output ) {
+		if ( builder.isCache( 'light' ) ) {
 
 
-	if ( builder.isCache( 'light' ) ) {
+			return builder.format( 'reflectedLight.directDiffuse', this.type, output );
 
 
-		return builder.format( 'reflectedLight.directDiffuse', this.type, output );
+		} else {
 
 
-	} else {
+			console.warn( 'THREE.LightNode is only compatible in "light" channel.' );
 
 
-		console.warn( 'THREE.LightNode is only compatible in "light" channel.' );
+			return builder.format( 'vec3( 0.0 )', this.type, output );
 
 
-		return builder.format( 'vec3( 0.0 )', this.type, output );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-LightNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	TempNode.prototype.copy.call( this, source );
+		this.scope = source.scope;
 
 
-	this.scope = source.scope;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-LightNode.prototype.toJSON = function ( meta ) {
+		var data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.scope = this.scope;
 
 
-		data.scope = this.scope;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+LightNode.TOTAL = 'total';
+LightNode.prototype.nodeType = 'Light';
 
 
 export { LightNode };
 export { LightNode };

+ 59 - 57
examples/jsm/nodes/accessors/NormalNode.js

@@ -1,120 +1,122 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 import { NodeLib } from '../core/NodeLib.js';
 import { NodeLib } from '../core/NodeLib.js';
 
 
-function NormalNode( scope ) {
+class NormalNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( scope ) {
 
 
-	this.scope = scope || NormalNode.VIEW;
+		super( 'v3' );
 
 
-}
+		this.scope = scope || NormalNode.VIEW;
 
 
-NormalNode.LOCAL = 'local';
-NormalNode.WORLD = 'world';
-NormalNode.VIEW = 'view';
+	}
 
 
-NormalNode.prototype = Object.create( TempNode.prototype );
-NormalNode.prototype.constructor = NormalNode;
-NormalNode.prototype.nodeType = 'Normal';
+	getShared() {
 
 
-NormalNode.prototype.getShared = function () {
+		// if shared is false, TempNode will not create temp variable (for optimization)
 
 
-	// if shared is false, TempNode will not create temp variable (for optimization)
+		return this.scope === NormalNode.WORLD;
+
+	}
 
 
-	return this.scope === NormalNode.WORLD;
+	build( builder, output, uuid, ns ) {
 
 
-};
+		const contextNormal = builder.context[ this.scope + 'Normal' ];
 
 
-NormalNode.prototype.build = function ( builder, output, uuid, ns ) {
+		if ( contextNormal ) {
 
 
-	var contextNormal = builder.context[ this.scope + 'Normal' ];
+			return contextNormal.build( builder, output, uuid, ns );
 
 
-	if ( contextNormal ) {
+		}
 
 
-		return contextNormal.build( builder, output, uuid, ns );
+		return super.build( builder, output, uuid );
 
 
 	}
 	}
 
 
-	return TempNode.prototype.build.call( this, builder, output, uuid );
+	generate( builder, output ) {
 
 
-};
+		let result;
 
 
-NormalNode.prototype.generate = function ( builder, output ) {
+		switch ( this.scope ) {
 
 
-	var result;
+			case NormalNode.VIEW:
 
 
-	switch ( this.scope ) {
+				if ( builder.isShader( 'vertex' ) ) result = 'transformedNormal';
+				else result = 'geometryNormal';
 
 
-		case NormalNode.VIEW:
+				break;
 
 
-			if ( builder.isShader( 'vertex' ) ) result = 'transformedNormal';
-			else result = 'geometryNormal';
+			case NormalNode.LOCAL:
 
 
-			break;
+				if ( builder.isShader( 'vertex' ) ) {
 
 
-		case NormalNode.LOCAL:
+					result = 'objectNormal';
 
 
-			if ( builder.isShader( 'vertex' ) ) {
+				} else {
 
 
-				result = 'objectNormal';
+					builder.requires.normal = true;
 
 
-			} else {
+					result = 'vObjectNormal';
 
 
-				builder.requires.normal = true;
+				}
 
 
-				result = 'vObjectNormal';
+				break;
 
 
-			}
+			case NormalNode.WORLD:
 
 
-			break;
+				if ( builder.isShader( 'vertex' ) ) {
 
 
-		case NormalNode.WORLD:
+					result = 'inverseTransformDirection( transformedNormal, viewMatrix ).xyz';
 
 
-			if ( builder.isShader( 'vertex' ) ) {
+				} else {
 
 
-				result = 'inverseTransformDirection( transformedNormal, viewMatrix ).xyz';
+					builder.requires.worldNormal = true;
 
 
-			} else {
+					result = 'vWNormal';
 
 
-				builder.requires.worldNormal = true;
+				}
 
 
-				result = 'vWNormal';
+				break;
 
 
-			}
+		}
 
 
-			break;
+		return builder.format( result, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-	return builder.format( result, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-NormalNode.prototype.copy = function ( source ) {
+		this.scope = source.scope;
 
 
-	TempNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.scope = source.scope;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-NormalNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.scope = this.scope;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.scope = this.scope;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+NormalNode.LOCAL = 'local';
+NormalNode.WORLD = 'world';
+NormalNode.VIEW = 'view';
+
+NormalNode.prototype.nodeType = 'Normal';
 
 
 NodeLib.addKeyword( 'viewNormal', function () {
 NodeLib.addKeyword( 'viewNormal', function () {
 
 

+ 65 - 63
examples/jsm/nodes/accessors/PositionNode.js

@@ -1,133 +1,135 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 import { NodeLib } from '../core/NodeLib.js';
 import { NodeLib } from '../core/NodeLib.js';
 
 
-function PositionNode( scope ) {
+class PositionNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( scope ) {
 
 
-	this.scope = scope || PositionNode.LOCAL;
+		super( 'v3' );
 
 
-}
+		this.scope = scope || PositionNode.LOCAL;
 
 
-PositionNode.LOCAL = 'local';
-PositionNode.WORLD = 'world';
-PositionNode.VIEW = 'view';
-PositionNode.PROJECTION = 'projection';
+	}
 
 
-PositionNode.prototype = Object.create( TempNode.prototype );
-PositionNode.prototype.constructor = PositionNode;
-PositionNode.prototype.nodeType = 'Position';
+	getType( ) {
+
+		switch ( this.scope ) {
 
 
-PositionNode.prototype.getType = function ( ) {
+			case PositionNode.PROJECTION:
 
 
-	switch ( this.scope ) {
+				return 'v4';
 
 
-		case PositionNode.PROJECTION:
+		}
 
 
-			return 'v4';
+		return this.type;
 
 
 	}
 	}
 
 
-	return this.type;
+	getShared( /* builder */ ) {
 
 
-};
+		switch ( this.scope ) {
 
 
-PositionNode.prototype.getShared = function ( /* builder */ ) {
+			case PositionNode.LOCAL:
+			case PositionNode.WORLD:
 
 
-	switch ( this.scope ) {
+				return false;
 
 
-		case PositionNode.LOCAL:
-		case PositionNode.WORLD:
+		}
 
 
-			return false;
+		return true;
 
 
 	}
 	}
 
 
-	return true;
+	generate( builder, output ) {
 
 
-};
+		let result;
 
 
-PositionNode.prototype.generate = function ( builder, output ) {
+		switch ( this.scope ) {
 
 
-	var result;
+			case PositionNode.LOCAL:
 
 
-	switch ( this.scope ) {
+				if ( builder.isShader( 'vertex' ) ) {
 
 
-		case PositionNode.LOCAL:
+					result = 'transformed';
 
 
-			if ( builder.isShader( 'vertex' ) ) {
+				} else {
 
 
-				result = 'transformed';
+					builder.requires.position = true;
 
 
-			} else {
+					result = 'vPosition';
 
 
-				builder.requires.position = true;
+				}
 
 
-				result = 'vPosition';
+				break;
 
 
-			}
+			case PositionNode.WORLD:
 
 
-			break;
+				if ( builder.isShader( 'vertex' ) ) {
 
 
-		case PositionNode.WORLD:
+					return '( modelMatrix * vec4( transformed, 1.0 ) ).xyz';
 
 
-			if ( builder.isShader( 'vertex' ) ) {
+				} else {
 
 
-				return '( modelMatrix * vec4( transformed, 1.0 ) ).xyz';
+					builder.requires.worldPosition = true;
 
 
-			} else {
+					result = 'vWPosition';
 
 
-				builder.requires.worldPosition = true;
+				}
 
 
-				result = 'vWPosition';
+				break;
 
 
-			}
+			case PositionNode.VIEW:
 
 
-			break;
+				result = builder.isShader( 'vertex' ) ? '-mvPosition.xyz' : 'vViewPosition';
 
 
-		case PositionNode.VIEW:
+				break;
 
 
-			result = builder.isShader( 'vertex' ) ? '-mvPosition.xyz' : 'vViewPosition';
+			case PositionNode.PROJECTION:
 
 
-			break;
+				result = builder.isShader( 'vertex' ) ? '( projectionMatrix * modelViewMatrix * vec4( position, 1.0 ) )' : 'vec4( 0.0 )';
 
 
-		case PositionNode.PROJECTION:
+				break;
 
 
-			result = builder.isShader( 'vertex' ) ? '( projectionMatrix * modelViewMatrix * vec4( position, 1.0 ) )' : 'vec4( 0.0 )';
+		}
 
 
-			break;
+		return builder.format( result, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-	return builder.format( result, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-PositionNode.prototype.copy = function ( source ) {
+		this.scope = source.scope;
 
 
-	TempNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.scope = source.scope;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-PositionNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.scope = this.scope;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.scope = this.scope;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
+
+PositionNode.LOCAL = 'local';
+PositionNode.WORLD = 'world';
+PositionNode.VIEW = 'view';
+PositionNode.PROJECTION = 'projection';
 
 
-};
+PositionNode.prototype.nodeType = 'Position';
 
 
 NodeLib.addKeyword( 'position', function () {
 NodeLib.addKeyword( 'position', function () {
 
 

+ 79 - 77
examples/jsm/nodes/accessors/ReflectNode.js

@@ -2,154 +2,156 @@ import { TempNode } from '../core/TempNode.js';
 import { PositionNode } from './PositionNode.js';
 import { PositionNode } from './PositionNode.js';
 import { NormalNode } from './NormalNode.js';
 import { NormalNode } from './NormalNode.js';
 
 
-function ReflectNode( scope ) {
+class ReflectNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( scope ) {
 
 
-	this.scope = scope || ReflectNode.CUBE;
+		super( 'v3' );
 
 
-}
+		this.scope = scope || ReflectNode.CUBE;
 
 
-ReflectNode.CUBE = 'cube';
-ReflectNode.SPHERE = 'sphere';
-ReflectNode.VECTOR = 'vector';
+	}
 
 
-ReflectNode.prototype = Object.create( TempNode.prototype );
-ReflectNode.prototype.constructor = ReflectNode;
-ReflectNode.prototype.nodeType = 'Reflect';
+	getUnique( builder ) {
 
 
-ReflectNode.prototype.getUnique = function ( builder ) {
+		return ! builder.context.viewNormal;
 
 
-	return ! builder.context.viewNormal;
+	}
+
+	getType( /* builder */ ) {
 
 
-};
+		switch ( this.scope ) {
 
 
-ReflectNode.prototype.getType = function ( /* builder */ ) {
+			case ReflectNode.SPHERE:
 
 
-	switch ( this.scope ) {
+				return 'v2';
 
 
-		case ReflectNode.SPHERE:
+		}
 
 
-			return 'v2';
+		return this.type;
 
 
 	}
 	}
 
 
-	return this.type;
-
-};
+	generate( builder, output ) {
 
 
-ReflectNode.prototype.generate = function ( builder, output ) {
+		const isUnique = this.getUnique( builder );
 
 
-	var isUnique = this.getUnique( builder );
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+			let result, code, reflectVec;
 
 
-		var result;
+			switch ( this.scope ) {
 
 
-		switch ( this.scope ) {
+				case ReflectNode.VECTOR:
 
 
-			case ReflectNode.VECTOR:
+					const viewNormalNode = new NormalNode( NormalNode.VIEW );
+					const roughnessNode = builder.context.roughness;
 
 
-				var viewNormalNode = new NormalNode( NormalNode.VIEW );
-				var roughnessNode = builder.context.roughness;
+					const viewNormal = viewNormalNode.build( builder, 'v3' );
+					const viewPosition = new PositionNode( PositionNode.VIEW ).build( builder, 'v3' );
+					const roughness = roughnessNode ? roughnessNode.build( builder, 'f' ) : undefined;
 
 
-				var viewNormal = viewNormalNode.build( builder, 'v3' );
-				var viewPosition = new PositionNode( PositionNode.VIEW ).build( builder, 'v3' );
-				var roughness = roughnessNode ? roughnessNode.build( builder, 'f' ) : undefined;
+					let method = `reflect( -normalize( ${viewPosition} ), ${viewNormal} )`;
 
 
-				var method = `reflect( -normalize( ${viewPosition} ), ${viewNormal} )`;
+					if ( roughness ) {
 
 
-				if ( roughness ) {
+						// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
+						method = `normalize( mix( ${method}, ${viewNormal}, ${roughness} * ${roughness} ) )`;
 
 
-					// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
-					method = `normalize( mix( ${method}, ${viewNormal}, ${roughness} * ${roughness} ) )`;
+					}
 
 
-				}
+					code = `inverseTransformDirection( ${method}, viewMatrix )`;
 
 
-				var code = `inverseTransformDirection( ${method}, viewMatrix )`;
+					if ( isUnique ) {
 
 
-				if ( isUnique ) {
+						builder.addNodeCode( `vec3 reflectVec = ${code};` );
 
 
-					builder.addNodeCode( `vec3 reflectVec = ${code};` );
+						result = 'reflectVec';
 
 
-					result = 'reflectVec';
+					} else {
 
 
-				} else {
+						result = code;
 
 
-					result = code;
+					}
 
 
-				}
+					break;
 
 
-				break;
+				case ReflectNode.CUBE:
 
 
-			case ReflectNode.CUBE:
+					reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
 
-				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
+					code = 'vec3( -' + reflectVec + '.x, ' + reflectVec + '.yz )';
 
 
-				var code = 'vec3( -' + reflectVec + '.x, ' + reflectVec + '.yz )';
+					if ( isUnique ) {
 
 
-				if ( isUnique ) {
+						builder.addNodeCode( `vec3 reflectCubeVec = ${code};` );
 
 
-					builder.addNodeCode( `vec3 reflectCubeVec = ${code};` );
+						result = 'reflectCubeVec';
 
 
-					result = 'reflectCubeVec';
+					} else {
 
 
-				} else {
+						result = code;
 
 
-					result = code;
+					}
 
 
-				}
+					break;
 
 
-				break;
+				case ReflectNode.SPHERE:
 
 
-			case ReflectNode.SPHERE:
+					reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
 
-				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
+					code = 'normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5';
 
 
-				var code = 'normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5';
+					if ( isUnique ) {
 
 
-				if ( isUnique ) {
+						builder.addNodeCode( `vec2 reflectSphereVec = ${code};` );
 
 
-					builder.addNodeCode( `vec2 reflectSphereVec = ${code};` );
+						result = 'reflectSphereVec';
 
 
-					result = 'reflectSphereVec';
+					} else {
 
 
-				} else {
+						result = code;
 
 
-					result = code;
+					}
 
 
-				}
+					break;
 
 
-				break;
+			}
 
 
-		}
+			return builder.format( result, this.getType( builder ), output );
 
 
-		return builder.format( result, this.getType( builder ), output );
+		} else {
 
 
-	} else {
+			console.warn( 'THREE.ReflectNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-		console.warn( 'THREE.ReflectNode is not compatible with ' + builder.shader + ' shader.' );
+			return builder.format( 'vec3( 0.0 )', this.type, output );
 
 
-		return builder.format( 'vec3( 0.0 )', this.type, output );
+		}
 
 
 	}
 	}
 
 
-};
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
 
 
-ReflectNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.scope = this.scope;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.scope = this.scope;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
+
+ReflectNode.CUBE = 'cube';
+ReflectNode.SPHERE = 'sphere';
+ReflectNode.VECTOR = 'vector';
 
 
-};
+ReflectNode.prototype.nodeType = 'Reflect';
 
 
 export { ReflectNode };
 export { ReflectNode };

+ 30 - 28
examples/jsm/nodes/accessors/ResolutionNode.js

@@ -2,61 +2,63 @@ import { Vector2 } from '../../../../build/three.module.js';
 
 
 import { Vector2Node } from '../inputs/Vector2Node.js';
 import { Vector2Node } from '../inputs/Vector2Node.js';
 
 
-function ResolutionNode() {
+class ResolutionNode extends Vector2Node {
 
 
-	Vector2Node.call( this );
+	constructor() {
 
 
-	this.size = new Vector2();
+		super();
 
 
-}
+		this.size = new Vector2();
 
 
-ResolutionNode.prototype = Object.create( Vector2Node.prototype );
-ResolutionNode.prototype.constructor = ResolutionNode;
-ResolutionNode.prototype.nodeType = 'Resolution';
+	}
+
+	updateFrame( frame ) {
 
 
-ResolutionNode.prototype.updateFrame = function ( frame ) {
+		if ( frame.renderer ) {
 
 
-	if ( frame.renderer ) {
+			frame.renderer.getSize( this.size );
 
 
-		frame.renderer.getSize( this.size );
+			const pixelRatio = frame.renderer.getPixelRatio();
 
 
-		var pixelRatio = frame.renderer.getPixelRatio();
+			this.x = this.size.width * pixelRatio;
+			this.y = this.size.height * pixelRatio;
 
 
-		this.x = this.size.width * pixelRatio;
-		this.y = this.size.height * pixelRatio;
+		} else {
 
 
-	} else {
+			console.warn( 'ResolutionNode need a renderer in NodeFrame' );
 
 
-		console.warn( 'ResolutionNode need a renderer in NodeFrame' );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-ResolutionNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	Vector2Node.prototype.copy.call( this, source );
+		this.renderer = source.renderer;
 
 
-	this.renderer = source.renderer;
+		return this;
 
 
-	return this;
+	}
+
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-ResolutionNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.renderer = this.renderer.uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.renderer = this.renderer.uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+ResolutionNode.prototype.nodeType = 'Resolution';
 
 
 export { ResolutionNode };
 export { ResolutionNode };

+ 30 - 28
examples/jsm/nodes/accessors/ScreenUVNode.js

@@ -1,62 +1,64 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 import { ResolutionNode } from './ResolutionNode.js';
 import { ResolutionNode } from './ResolutionNode.js';
 
 
-function ScreenUVNode( resolution ) {
+class ScreenUVNode extends TempNode {
 
 
-	TempNode.call( this, 'v2' );
+	constructor( resolution ) {
 
 
-	this.resolution = resolution || new ResolutionNode();
+		super( 'v2' );
 
 
-}
+		this.resolution = resolution || new ResolutionNode();
 
 
-ScreenUVNode.prototype = Object.create( TempNode.prototype );
-ScreenUVNode.prototype.constructor = ScreenUVNode;
-ScreenUVNode.prototype.nodeType = 'ScreenUV';
+	}
+
+	generate( builder, output ) {
 
 
-ScreenUVNode.prototype.generate = function ( builder, output ) {
+		let result;
 
 
-	var result;
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+			result = '( gl_FragCoord.xy / ' + this.resolution.build( builder, 'v2' ) + ')';
 
 
-		result = '( gl_FragCoord.xy / ' + this.resolution.build( builder, 'v2' ) + ')';
+		} else {
 
 
-	} else {
+			console.warn( 'THREE.ScreenUVNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-		console.warn( 'THREE.ScreenUVNode is not compatible with ' + builder.shader + ' shader.' );
+			result = 'vec2( 0.0 )';
 
 
-		result = 'vec2( 0.0 )';
+		}
+
+		return builder.format( result, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-	return builder.format( result, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-ScreenUVNode.prototype.copy = function ( source ) {
+		this.resolution = source.resolution;
 
 
-	TempNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.resolution = source.resolution;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-ScreenUVNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.resolution = this.resolution.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.resolution = this.resolution.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+ScreenUVNode.prototype.nodeType = 'ScreenUV';
 
 
 export { ScreenUVNode };
 export { ScreenUVNode };

+ 27 - 25
examples/jsm/nodes/accessors/UVNode.js

@@ -1,54 +1,56 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 import { NodeLib } from '../core/NodeLib.js';
 import { NodeLib } from '../core/NodeLib.js';
 
 
-function UVNode( index ) {
+class UVNode extends TempNode {
 
 
-	TempNode.call( this, 'v2', { shared: false } );
+	constructor( index ) {
 
 
-	this.index = index || 0;
+		super( 'v2', { shared: false } );
 
 
-}
+		this.index = index || 0;
 
 
-UVNode.prototype = Object.create( TempNode.prototype );
-UVNode.prototype.constructor = UVNode;
-UVNode.prototype.nodeType = 'UV';
+	}
 
 
-UVNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	builder.requires.uv[ this.index ] = true;
+		builder.requires.uv[ this.index ] = true;
 
 
-	var uvIndex = this.index > 0 ? this.index + 1 : '';
-	var result = builder.isShader( 'vertex' ) ? 'uv' + uvIndex : 'vUv' + uvIndex;
+		const uvIndex = this.index > 0 ? this.index + 1 : '';
+		const result = builder.isShader( 'vertex' ) ? 'uv' + uvIndex : 'vUv' + uvIndex;
 
 
-	return builder.format( result, this.getType( builder ), output );
+		return builder.format( result, this.getType( builder ), output );
 
 
-};
+	}
 
 
-UVNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.index = source.index;
+		this.index = source.index;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-UVNode.prototype.toJSON = function ( meta ) {
+	toJSON( meta ) {
 
 
-	var data = this.getJSONNode( meta );
+		let data = this.getJSONNode( meta );
 
 
-	if ( ! data ) {
+		if ( ! data ) {
 
 
-		data = this.createJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-		data.index = this.index;
+			data.index = this.index;
+
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+UVNode.prototype.nodeType = 'UV';
 
 
 NodeLib.addKeyword( 'uv', function () {
 NodeLib.addKeyword( 'uv', function () {
 
 

+ 34 - 32
examples/jsm/nodes/core/AttributeNode.js

@@ -1,66 +1,68 @@
 import { Node } from './Node.js';
 import { Node } from './Node.js';
 
 
-function AttributeNode( name, type ) {
+class AttributeNode extends Node {
 
 
-	Node.call( this, type );
+	constructor( name, type ) {
 
 
-	this.name = name;
+		super( type );
 
 
-}
+		this.name = name;
 
 
-AttributeNode.prototype = Object.create( Node.prototype );
-AttributeNode.prototype.constructor = AttributeNode;
-AttributeNode.prototype.nodeType = 'Attribute';
+	}
 
 
-AttributeNode.prototype.getAttributeType = function ( builder ) {
+	getAttributeType( builder ) {
 
 
-	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
+		return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
 
 
-};
+	}
 
 
-AttributeNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	var type = this.getAttributeType( builder );
+		const type = this.getAttributeType( builder );
 
 
-	return builder.getTypeByFormat( type );
+		return builder.getTypeByFormat( type );
 
 
-};
+	}
 
 
-AttributeNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	var type = this.getAttributeType( builder );
+		const type = this.getAttributeType( builder );
 
 
-	var attribute = builder.getAttribute( this.name, type ),
-		name = builder.isShader( 'vertex' ) ? this.name : attribute.varying.name;
+		const attribute = builder.getAttribute( this.name, type ),
+			name = builder.isShader( 'vertex' ) ? this.name : attribute.varying.name;
 
 
-	return builder.format( name, this.getType( builder ), output );
+		return builder.format( name, this.getType( builder ), output );
 
 
-};
+	}
 
 
-AttributeNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	Node.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.type = source.type;
+		this.type = source.type;
 
 
-	return this;
+		return this;
 
 
-};
+	}
+
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
 
 
-AttributeNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.type = this.type;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.type = this.type;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+AttributeNode.prototype.nodeType = 'Attribute';
 
 
 export { AttributeNode };
 export { AttributeNode };

+ 64 - 62
examples/jsm/nodes/core/ConstNode.js

@@ -1,123 +1,125 @@
 import { TempNode } from './TempNode.js';
 import { TempNode } from './TempNode.js';
 
 
-var declarationRegexp = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
+const declarationRegexp = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
 
 
-function ConstNode( src, useDefine ) {
+class ConstNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( src, useDefine ) {
 
 
-	this.parse( src || ConstNode.PI, useDefine );
+		super();
 
 
-}
+		this.parse( 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.prototype = Object.create( TempNode.prototype );
-ConstNode.prototype.constructor = ConstNode;
-ConstNode.prototype.nodeType = 'Const';
+	getType( builder ) {
 
 
-ConstNode.prototype.getType = function ( builder ) {
+		return builder.getTypeByFormat( this.type );
 
 
-	return builder.getTypeByFormat( this.type );
+	}
 
 
-};
+	parse( src, useDefine ) {
 
 
-ConstNode.prototype.parse = function ( src, useDefine ) {
+		this.src = src || '';
 
 
-	this.src = src || '';
+		let name, type, value = '';
 
 
-	var name, type, value = '';
+		const match = this.src.match( declarationRegexp );
 
 
-	var match = this.src.match( declarationRegexp );
+		this.useDefine = useDefine || this.src.charAt( 0 ) === '#';
 
 
-	this.useDefine = useDefine || this.src.charAt( 0 ) === '#';
+		if ( match && match.length > 1 ) {
 
 
-	if ( match && match.length > 1 ) {
+			type = match[ 1 ];
+			name = match[ 2 ];
+			value = match[ 3 ];
 
 
-		type = match[ 1 ];
-		name = match[ 2 ];
-		value = match[ 3 ];
+		} else {
 
 
-	} else {
+			name = this.src;
+			type = 'f';
 
 
-		name = this.src;
-		type = 'f';
+		}
+
+		this.name = name;
+		this.type = type;
+		this.value = value;
 
 
 	}
 	}
 
 
-	this.name = name;
-	this.type = type;
-	this.value = value;
+	build( builder, output ) {
+
+		if ( output === 'source' ) {
+
+			if ( this.value ) {
 
 
-};
+				if ( this.useDefine ) {
 
 
-ConstNode.prototype.build = function ( builder, output ) {
+					return '#define ' + this.name + ' ' + this.value;
 
 
-	if ( output === 'source' ) {
+				}
 
 
-		if ( this.value ) {
+				return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
 
 
-			if ( this.useDefine ) {
+			} else if ( this.useDefine ) {
 
 
-				return '#define ' + this.name + ' ' + this.value;
+				return this.src;
 
 
 			}
 			}
 
 
-			return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
+		} else {
 
 
-		} else if ( this.useDefine ) {
+			builder.include( this );
 
 
-			return this.src;
+			return builder.format( this.name, this.getType( builder ), output );
 
 
 		}
 		}
 
 
-	} else {
+	}
 
 
-		builder.include( this );
+	generate( builder, output ) {
 
 
 		return builder.format( this.name, this.getType( builder ), output );
 		return builder.format( this.name, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-};
-
-ConstNode.prototype.generate = function ( builder, output ) {
+	copy( source ) {
 
 
-	return builder.format( this.name, this.getType( builder ), output );
+		super.copy( source );
 
 
-};
+		this.parse( source.src, source.useDefine );
 
 
-ConstNode.prototype.copy = function ( source ) {
+		return this;
 
 
-	TempNode.prototype.copy.call( this, source );
-
-	this.parse( source.src, source.useDefine );
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-ConstNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.src = this.src;
 
 
-		data = this.createJSONNode( meta );
+			if ( data.useDefine === true ) data.useDefine = true;
 
 
-		data.src = this.src;
+		}
 
 
-		if ( data.useDefine === true ) data.useDefine = true;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
+
+ConstNode.prototype.nodeType = 'Const';
 
 
-};
+ConstNode.PI = 'PI';
+ConstNode.PI2 = 'PI2';
+ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
+ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
+ConstNode.LOG2 = 'LOG2';
+ConstNode.EPSILON = 'EPSILON';
 
 
 export { ConstNode };
 export { ConstNode };

+ 6 - 4
examples/jsm/nodes/core/ExpressionNode.js

@@ -1,13 +1,15 @@
 import { FunctionNode } from './FunctionNode.js';
 import { FunctionNode } from './FunctionNode.js';
 
 
-function ExpressionNode( src, type, keywords, extensions, includes ) {
+class ExpressionNode extends FunctionNode {
 
 
-	FunctionNode.call( this, src, includes, extensions, keywords, type );
+	constructor( src, type, keywords, extensions, includes ) {
+
+		super( src, includes, extensions, keywords, type );
+
+	}
 
 
 }
 }
 
 
-ExpressionNode.prototype = Object.create( FunctionNode.prototype );
-ExpressionNode.prototype.constructor = ExpressionNode;
 ExpressionNode.prototype.nodeType = 'Expression';
 ExpressionNode.prototype.nodeType = 'Expression';
 
 
 export { ExpressionNode };
 export { ExpressionNode };

+ 54 - 52
examples/jsm/nodes/core/FunctionCallNode.js

@@ -1,106 +1,108 @@
 import { TempNode } from './TempNode.js';
 import { TempNode } from './TempNode.js';
 
 
-function FunctionCallNode( func, inputs ) {
+class FunctionCallNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( func, inputs ) {
 
 
-	this.setFunction( func, inputs );
+		super();
 
 
-}
+		this.setFunction( func, inputs );
 
 
-FunctionCallNode.prototype = Object.create( TempNode.prototype );
-FunctionCallNode.prototype.constructor = FunctionCallNode;
-FunctionCallNode.prototype.nodeType = 'FunctionCall';
+	}
 
 
-FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
+	setFunction( func, inputs = [] ) {
 
 
-	this.value = func;
-	this.inputs = inputs || [];
+		this.value = func;
+		this.inputs = inputs;
 
 
-};
+	}
 
 
-FunctionCallNode.prototype.getFunction = function () {
+	getFunction() {
 
 
-	return this.value;
+		return this.value;
 
 
-};
+	}
 
 
-FunctionCallNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	return this.value.getType( builder );
+		return this.value.getType( builder );
 
 
-};
+	}
 
 
-FunctionCallNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	var type = this.getType( builder ),
-		func = this.value;
+		const type = this.getType( builder ),
+			func = this.value;
 
 
-	var code = func.build( builder, output ) + '( ',
-		params = [];
+		let code = func.build( builder, output ) + '( ';
+		const params = [];
 
 
-	for ( var i = 0; i < func.inputs.length; i ++ ) {
+		for ( let i = 0; i < func.inputs.length; i ++ ) {
 
 
-		var inpt = func.inputs[ i ],
-			param = this.inputs[ i ] || this.inputs[ inpt.name ];
+			const inpt = func.inputs[ i ],
+				param = this.inputs[ i ] || this.inputs[ inpt.name ];
 
 
-		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
+			params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
 
 
-	}
+		}
 
 
-	code += params.join( ', ' ) + ' )';
+		code += params.join( ', ' ) + ' )';
 
 
-	return builder.format( code, type, output );
+		return builder.format( code, type, output );
 
 
-};
+	}
 
 
-FunctionCallNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	for ( var prop in source.inputs ) {
+		for ( const prop in source.inputs ) {
 
 
-		this.inputs[ prop ] = source.inputs[ prop ];
+			this.inputs[ prop ] = source.inputs[ prop ];
 
 
-	}
+		}
+
+		this.value = source.value;
 
 
-	this.value = source.value;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-FunctionCallNode.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			const func = this.value;
 
 
-		var func = this.value;
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.value = this.value.toJSON( meta ).uuid;
 
 
-		data.value = this.value.toJSON( meta ).uuid;
+			if ( func.inputs.length ) {
 
 
-		if ( func.inputs.length ) {
+				data.inputs = {};
 
 
-			data.inputs = {};
+				for ( let i = 0; i < func.inputs.length; i ++ ) {
 
 
-			for ( var i = 0; i < func.inputs.length; i ++ ) {
+					const inpt = func.inputs[ i ],
+						node = this.inputs[ i ] || this.inputs[ inpt.name ];
 
 
-				var inpt = func.inputs[ i ],
-					node = this.inputs[ i ] || this.inputs[ inpt.name ];
+					data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
 
 
-				data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
+				}
 
 
 			}
 			}
 
 
 		}
 		}
 
 
+		return data;
+
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+FunctionCallNode.prototype.nodeType = 'FunctionCall';
 
 
 export { FunctionCallNode };
 export { FunctionCallNode };

+ 135 - 133
examples/jsm/nodes/core/FunctionNode.js

@@ -1,276 +1,278 @@
 import { TempNode } from './TempNode.js';
 import { TempNode } from './TempNode.js';
 import { NodeLib } from './NodeLib.js';
 import { NodeLib } from './NodeLib.js';
 
 
-var declarationRegexp = /^\s*([a-z_0-9]+)\s+([a-z_0-9]+)\s*\(([\s\S]*?)\)/i,
+const declarationRegexp = /^\s*([a-z_0-9]+)\s+([a-z_0-9]+)\s*\(([\s\S]*?)\)/i,
 	propertiesRegexp = /[a-z_0-9]+/ig;
 	propertiesRegexp = /[a-z_0-9]+/ig;
 
 
-function FunctionNode( src, includes, extensions, keywords, type ) {
+class FunctionNode extends TempNode {
 
 
-	this.isMethod = type === undefined;
-	this.isInterface = false;
+	constructor( src, includes, extensions, keywords, type ) {
 
 
-	TempNode.call( this, type );
+		super( type );
 
 
-	this.parse( src, includes, extensions, keywords );
+		this.isMethod = type === undefined;
+		this.isInterface = false;
 
 
-}
+		this.parse( src, includes, extensions, keywords );
 
 
-FunctionNode.prototype = Object.create( TempNode.prototype );
-FunctionNode.prototype.constructor = FunctionNode;
-FunctionNode.prototype.nodeType = 'Function';
+	}
 
 
-FunctionNode.prototype.useKeywords = true;
+	getShared( /* builder, output */ ) {
 
 
-FunctionNode.prototype.getShared = function ( /* builder, output */ ) {
+		return ! this.isMethod;
 
 
-	return ! this.isMethod;
+	}
 
 
-};
+	getType( builder ) {
 
 
-FunctionNode.prototype.getType = function ( builder ) {
+		return builder.getTypeByFormat( this.type );
 
 
-	return builder.getTypeByFormat( this.type );
+	}
 
 
-};
+	getInputByName( name ) {
 
 
-FunctionNode.prototype.getInputByName = function ( name ) {
+		let i = this.inputs.length;
 
 
-	var i = this.inputs.length;
+		while ( i -- ) {
 
 
-	while ( i -- ) {
+			if ( this.inputs[ i ].name === name ) {
 
 
-		if ( this.inputs[ i ].name === name ) {
+				return this.inputs[ i ];
 
 
-			return this.inputs[ i ];
+			}
 
 
 		}
 		}
 
 
 	}
 	}
 
 
-};
+	getIncludeByName( name ) {
 
 
-FunctionNode.prototype.getIncludeByName = function ( name ) {
+		let i = this.includes.length;
 
 
-	var i = this.includes.length;
+		while ( i -- ) {
 
 
-	while ( i -- ) {
+			if ( this.includes[ i ].name === name ) {
 
 
-		if ( this.includes[ i ].name === name ) {
+				return this.includes[ i ];
 
 
-			return this.includes[ i ];
+			}
 
 
 		}
 		}
 
 
 	}
 	}
 
 
-};
+	generate( builder, output ) {
 
 
-FunctionNode.prototype.generate = function ( builder, output ) {
+		let match, offset = 0, src = this.src;
 
 
-	var match, offset = 0, src = this.src;
+		for ( let i = 0; i < this.includes.length; i ++ ) {
 
 
-	for ( var i = 0; i < this.includes.length; i ++ ) {
+			builder.include( this.includes[ i ], this );
 
 
-		builder.include( this.includes[ i ], this );
+		}
 
 
-	}
+		for ( const ext in this.extensions ) {
 
 
-	for ( var ext in this.extensions ) {
+			builder.extensions[ ext ] = true;
 
 
-		builder.extensions[ ext ] = true;
+		}
 
 
-	}
+		const matches = [];
 
 
-	var matches = [];
+		while ( match = propertiesRegexp.exec( this.src ) ) matches.push( match );
 
 
-	while ( match = propertiesRegexp.exec( this.src ) ) matches.push( match );
+		for ( let i = 0; i < matches.length; i ++ ) {
 
 
-	for ( var i = 0; i < matches.length; i ++ ) {
+			const match = matches[ i ];
 
 
-		var match = matches[ i ];
+			const prop = match[ 0 ],
+				isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true;
 
 
-		var prop = match[ 0 ],
-			isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true,
-			reference = prop;
+			let reference = prop;
 
 
-		if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) {
+			if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) {
 
 
-			var node = this.keywords[ prop ];
+				let node = this.keywords[ prop ];
 
 
-			if ( ! node ) {
+				if ( ! node ) {
 
 
-				var keyword = NodeLib.getKeywordData( prop );
+					const keyword = NodeLib.getKeywordData( prop );
 
 
-				if ( keyword.cache ) node = builder.keywords[ prop ];
+					if ( keyword.cache ) node = builder.keywords[ prop ];
 
 
-				node = node || NodeLib.getKeyword( prop, builder );
+					node = node || NodeLib.getKeyword( prop, builder );
 
 
-				if ( keyword.cache ) builder.keywords[ prop ] = node;
+					if ( keyword.cache ) builder.keywords[ prop ] = node;
 
 
-			}
+				}
 
 
-			reference = node.build( builder );
+				reference = node.build( builder );
 
 
-		}
+			}
 
 
-		if ( prop !== reference ) {
+			if ( prop !== reference ) {
 
 
-			src = src.substring( 0, match.index + offset ) + reference + src.substring( match.index + prop.length + offset );
+				src = src.substring( 0, match.index + offset ) + reference + src.substring( match.index + prop.length + offset );
 
 
-			offset += reference.length - prop.length;
+				offset += reference.length - prop.length;
 
 
-		}
+			}
+
+			if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) {
 
 
-		if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) {
+				builder.include( NodeLib.get( reference ) );
 
 
-			builder.include( NodeLib.get( reference ) );
+			}
 
 
 		}
 		}
 
 
-	}
+		if ( output === 'source' ) {
 
 
-	if ( output === 'source' ) {
+			return src;
 
 
-		return src;
+		} else if ( this.isMethod ) {
 
 
-	} else if ( this.isMethod ) {
+			if ( ! this.isInterface ) {
 
 
-		if ( ! this.isInterface ) {
+				builder.include( this, false, src );
 
 
-			builder.include( this, false, src );
+			}
 
 
-		}
+			return this.name;
 
 
-		return this.name;
+		} else {
 
 
-	} else {
+			return builder.format( '( ' + src + ' )', this.getType( builder ), output );
 
 
-		return builder.format( '( ' + src + ' )', this.getType( builder ), output );
+		}
 
 
 	}
 	}
 
 
-};
+	parse( src, includes, extensions, keywords ) {
 
 
-FunctionNode.prototype.parse = function ( src, includes, extensions, keywords ) {
+		this.src = src || '';
 
 
-	this.src = src || '';
+		this.includes = includes || [];
+		this.extensions = extensions || {};
+		this.keywords = keywords || {};
 
 
-	this.includes = includes || [];
-	this.extensions = extensions || {};
-	this.keywords = keywords || {};
+		if ( this.isMethod ) {
 
 
-	if ( this.isMethod ) {
+			const match = this.src.match( declarationRegexp );
 
 
-		var match = this.src.match( declarationRegexp );
+			this.inputs = [];
 
 
-		this.inputs = [];
+			if ( match && match.length == 4 ) {
 
 
-		if ( match && match.length == 4 ) {
+				this.type = match[ 1 ];
+				this.name = match[ 2 ];
 
 
-			this.type = match[ 1 ];
-			this.name = match[ 2 ];
+				const inputs = match[ 3 ].match( propertiesRegexp );
 
 
-			var inputs = match[ 3 ].match( propertiesRegexp );
+				if ( inputs ) {
 
 
-			if ( inputs ) {
+					let i = 0;
 
 
-				var i = 0;
+					while ( i < inputs.length ) {
 
 
-				while ( i < inputs.length ) {
+						let qualifier = inputs[ i ++ ];
+						let type;
 
 
-					var qualifier = inputs[ i ++ ];
-					var type, name;
+						if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) {
 
 
-					if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) {
+							type = inputs[ i ++ ];
 
 
-						type = inputs[ i ++ ];
+						} else {
 
 
-					} else {
+							type = qualifier;
+							qualifier = '';
 
 
-						type = qualifier;
-						qualifier = '';
+						}
 
 
-					}
+						const name = inputs[ i ++ ];
 
 
-					name = inputs[ i ++ ];
+						this.inputs.push( {
+							name: name,
+							type: type,
+							qualifier: qualifier
+						} );
 
 
-					this.inputs.push( {
-						name: name,
-						type: type,
-						qualifier: qualifier
-					} );
+					}
 
 
 				}
 				}
 
 
-			}
+				this.isInterface = this.src.indexOf( '{' ) === - 1;
 
 
-			this.isInterface = this.src.indexOf( '{' ) === - 1;
+			} else {
 
 
-		} else {
+				this.type = '';
+				this.name = '';
 
 
-			this.type = '';
-			this.name = '';
+			}
 
 
 		}
 		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-FunctionNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	TempNode.prototype.copy.call( this, source );
+		this.isMethod = source.isMethod;
+		this.useKeywords = source.useKeywords;
 
 
-	this.isMethod = source.isMethod;
-	this.useKeywords = source.useKeywords;
+		this.parse( source.src, source.includes, source.extensions, source.keywords );
 
 
-	this.parse( source.src, source.includes, source.extensions, source.keywords );
+		if ( source.type !== undefined ) this.type = source.type;
 
 
-	if ( source.type !== undefined ) this.type = source.type;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-FunctionNode.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.src = this.src;
+			data.isMethod = this.isMethod;
+			data.useKeywords = this.useKeywords;
 
 
-		data.src = this.src;
-		data.isMethod = this.isMethod;
-		data.useKeywords = this.useKeywords;
+			if ( ! this.isMethod ) data.type = this.type;
 
 
-		if ( ! this.isMethod ) data.type = this.type;
+			data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
+			data.keywords = {};
 
 
-		data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
-		data.keywords = {};
+			for ( const keyword in this.keywords ) {
 
 
-		for ( var keyword in this.keywords ) {
+				data.keywords[ keyword ] = this.keywords[ keyword ].toJSON( meta ).uuid;
 
 
-			data.keywords[ keyword ] = this.keywords[ keyword ].toJSON( meta ).uuid;
+			}
 
 
-		}
+			if ( this.includes.length ) {
 
 
-		if ( this.includes.length ) {
+				data.includes = [];
 
 
-			data.includes = [];
+				for ( let i = 0; i < this.includes.length; i ++ ) {
 
 
-			for ( var i = 0; i < this.includes.length; i ++ ) {
+					data.includes.push( this.includes[ i ].toJSON( meta ).uuid );
 
 
-				data.includes.push( this.includes[ i ].toJSON( meta ).uuid );
+				}
 
 
 			}
 			}
 
 
 		}
 		}
 
 
+		return data;
+
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+FunctionNode.prototype.nodeType = 'Function';
+FunctionNode.prototype.useKeywords = true;
 
 
 export { FunctionNode };
 export { FunctionNode };

+ 46 - 45
examples/jsm/nodes/core/InputNode.js

@@ -1,93 +1,94 @@
 import { TempNode } from './TempNode.js';
 import { TempNode } from './TempNode.js';
 
 
-function InputNode( type, params ) {
+class InputNode extends TempNode {
 
 
-	params = params || {};
-	params.shared = params.shared !== undefined ? params.shared : false;
+	constructor( type, params ) {
 
 
-	TempNode.call( this, type, params );
+		params = params || {};
+		params.shared = params.shared !== undefined ? params.shared : false;
 
 
-	this.readonly = false;
+		super( type, params );
 
 
-}
+		this.readonly = false;
 
 
-InputNode.prototype = Object.create( TempNode.prototype );
-InputNode.prototype.constructor = InputNode;
+	}
 
 
-InputNode.prototype.setReadonly = function ( value ) {
+	setReadonly( value ) {
 
 
-	this.readonly = value;
+		this.readonly = value;
 
 
-	this.hashProperties = this.readonly ? [ 'value' ] : undefined;
+		this.hashProperties = this.readonly ? [ 'value' ] : undefined;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-InputNode.prototype.getReadonly = function ( /* builder */ ) {
+	getReadonly( /* builder */ ) {
 
 
-	return this.readonly;
+		return this.readonly;
 
 
-};
+	}
 
 
-InputNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	if ( source.readonly !== undefined ) this.readonly = source.readonly;
+		if ( source.readonly !== undefined ) this.readonly = source.readonly;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-InputNode.prototype.createJSONNode = function ( meta ) {
+	createJSONNode( meta ) {
 
 
-	var data = TempNode.prototype.createJSONNode.call( this, meta );
+		const data = super.createJSONNode( meta );
 
 
-	if ( this.readonly === true ) data.readonly = this.readonly;
+		if ( this.readonly === true ) data.readonly = this.readonly;
 
 
-	return data;
+		return data;
 
 
-};
+	}
 
 
-InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
+	generate( builder, output, uuid, type, ns, needsUpdate ) {
 
 
-	uuid = builder.getUuid( uuid || this.getUuid() );
-	type = type || this.getType( builder );
+		uuid = builder.getUuid( uuid || this.getUuid() );
+		type = type || this.getType( builder );
 
 
-	var data = builder.getNodeData( uuid ),
-		readonly = this.getReadonly( builder ) && this.generateReadonly !== undefined;
+		const data = builder.getNodeData( uuid ),
+			readonly = this.getReadonly( builder ) && this.generateReadonly !== undefined;
 
 
-	if ( readonly ) {
+		if ( readonly ) {
 
 
-		return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
+			return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
 
 
-	} else {
+		} else {
 
 
-		if ( builder.isShader( 'vertex' ) ) {
+			if ( builder.isShader( 'vertex' ) ) {
 
 
-			if ( ! data.vertex ) {
+				if ( ! data.vertex ) {
 
 
-				data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate, this.getLabel() );
+					data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate, this.getLabel() );
 
 
-			}
+				}
 
 
-			return builder.format( data.vertex.name, type, output );
+				return builder.format( data.vertex.name, type, output );
 
 
-		} else {
+			} else {
 
 
-			if ( ! data.fragment ) {
+				if ( ! data.fragment ) {
 
 
-				data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate, this.getLabel() );
+					data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate, this.getLabel() );
 
 
-			}
+				}
 
 
-			return builder.format( data.fragment.name, type, output );
+				return builder.format( data.fragment.name, type, output );
+
+			}
 
 
 		}
 		}
 
 
 	}
 	}
 
 
-};
+}
 
 
 export { InputNode };
 export { InputNode };

+ 47 - 56
examples/jsm/nodes/core/Node.js

@@ -1,28 +1,20 @@
 import { MathUtils } from '../../../../build/three.module.js';
 import { MathUtils } from '../../../../build/three.module.js';
 
 
-function Node( type ) {
+class Node {
 
 
-	this.uuid = MathUtils.generateUUID();
+	constructor( type ) {
 
 
-	this.name = '';
+		this.uuid = MathUtils.generateUUID();
 
 
-	this.type = type;
+		this.name = '';
 
 
-	this.userData = {};
+		this.type = type;
 
 
-}
-
-Node.prototype = {
-
-	constructor: Node,
+		this.userData = {};
 
 
-	isNode: true,
-
-	hashProperties: undefined,
-
-	analyze: function ( builder, settings ) {
+	}
 
 
-		settings = settings || {};
+	analyze( builder, settings = {} ) {
 
 
 		builder.analyzing = true;
 		builder.analyzing = true;
 
 
@@ -35,25 +27,21 @@ Node.prototype = {
 
 
 		builder.analyzing = false;
 		builder.analyzing = false;
 
 
-	},
-
-	analyzeAndFlow: function ( builder, output, settings ) {
+	}
 
 
-		settings = settings || {};
+	analyzeAndFlow( builder, output, settings = {} ) {
 
 
 		this.analyze( builder, settings );
 		this.analyze( builder, settings );
 
 
 		return this.flow( builder, output, settings );
 		return this.flow( builder, output, settings );
 
 
-	},
-
-	flow: function ( builder, output, settings ) {
+	}
 
 
-		settings = settings || {};
+	flow( builder, output, settings = {} ) {
 
 
 		builder.addFlow( settings.slot, settings.cache, settings.context );
 		builder.addFlow( settings.slot, settings.cache, settings.context );
 
 
-		var flow = {};
+		const flow = {};
 		flow.result = this.build( builder, output );
 		flow.result = this.build( builder, output );
 		flow.code = builder.clearNodeCode();
 		flow.code = builder.clearNodeCode();
 		flow.extra = builder.context.extra;
 		flow.extra = builder.context.extra;
@@ -62,13 +50,13 @@ Node.prototype = {
 
 
 		return flow;
 		return flow;
 
 
-	},
+	}
 
 
-	build: function ( builder, output, uuid ) {
+	build( builder, output, uuid ) {
 
 
 		output = output || this.getType( builder, output );
 		output = output || this.getType( builder, output );
 
 
-		var data = builder.getNodeData( uuid || this );
+		const data = builder.getNodeData( uuid || this );
 
 
 		if ( builder.analyzing ) {
 		if ( builder.analyzing ) {
 
 
@@ -90,18 +78,18 @@ Node.prototype = {
 
 
 		return this.generate( builder, output, uuid );
 		return this.generate( builder, output, uuid );
 
 
-	},
+	}
 
 
-	generate: function ( /* builder, output, uuid, type, ns */ ) {
+	generate( /* builder, output, uuid, type, ns */ ) {
 
 
 		// This method needs to be implemented in subclasses
 		// This method needs to be implemented in subclasses
 
 
-	},
+	}
 
 
-	getHash: function () {
+	getHash() {
 
 
-		var hash = '{';
-		var prop, obj;
+		let hash = '{';
+		let prop, obj;
 
 
 		for ( prop in this ) {
 		for ( prop in this ) {
 
 
@@ -117,7 +105,7 @@ Node.prototype = {
 
 
 		if ( this.hashProperties ) {
 		if ( this.hashProperties ) {
 
 
-			for ( var i = 0; i < this.hashProperties.length; i ++ ) {
+			for ( let i = 0; i < this.hashProperties.length; i ++ ) {
 
 
 				prop = this.hashProperties[ i ];
 				prop = this.hashProperties[ i ];
 				obj = this[ prop ];
 				obj = this[ prop ];
@@ -132,13 +120,13 @@ Node.prototype = {
 
 
 		return hash;
 		return hash;
 
 
-	},
+	}
 
 
-	appendDepsNode: function ( builder, data, output ) {
+	appendDepsNode( builder, data, output ) {
 
 
 		data.deps = ( data.deps || 0 ) + 1;
 		data.deps = ( data.deps || 0 ) + 1;
 
 
-		var outputLen = builder.getTypeLength( output );
+		const outputLen = builder.getTypeLength( output );
 
 
 		if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
 		if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
 
 
@@ -147,31 +135,31 @@ Node.prototype = {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setName: function ( name ) {
+	setName( name ) {
 
 
 		this.name = name;
 		this.name = name;
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	getName: function ( /* builder */ ) {
+	getName( /* builder */ ) {
 
 
 		return this.name;
 		return this.name;
 
 
-	},
+	}
 
 
-	getType: function ( builder, output ) {
+	getType( builder, output ) {
 
 
 		return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
 		return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
 
 
-	},
+	}
 
 
-	getJSONNode: function ( meta ) {
+	getJSONNode( meta ) {
 
 
-		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+		const isRootObject = ( meta === undefined || typeof meta === 'string' );
 
 
 		if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
 		if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
 
 
@@ -179,9 +167,9 @@ Node.prototype = {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	copy: function ( source ) {
+	copy( source ) {
 
 
 		if ( source.name !== undefined ) this.name = source.name;
 		if ( source.name !== undefined ) this.name = source.name;
 
 
@@ -189,13 +177,13 @@ Node.prototype = {
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	createJSONNode: function ( meta ) {
+	createJSONNode( meta ) {
 
 
-		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+		const isRootObject = ( meta === undefined || typeof meta === 'string' );
 
 
-		var data = {};
+		const data = {};
 
 
 		if ( typeof this.nodeType !== 'string' ) throw new Error( 'Node does not allow serialization.' );
 		if ( typeof this.nodeType !== 'string' ) throw new Error( 'Node does not allow serialization.' );
 
 
@@ -214,14 +202,17 @@ Node.prototype = {
 
 
 		return data;
 		return data;
 
 
-	},
+	}
 
 
-	toJSON: function ( meta ) {
+	toJSON( meta ) {
 
 
 		return this.getJSONNode( meta ) || this.createJSONNode( meta );
 		return this.getJSONNode( meta ) || this.createJSONNode( meta );
 
 
 	}
 	}
 
 
-};
+}
+
+Node.prototype.isNode = true;
+Node.prototype.hashProperties = undefined;
 
 
 export { Node };
 export { Node };

+ 247 - 259
examples/jsm/nodes/core/NodeBuilder.js

@@ -21,7 +21,7 @@ import { CubeTextureNode } from '../inputs/CubeTextureNode.js';
 import { TextureCubeNode } from '../misc/TextureCubeNode.js';
 import { TextureCubeNode } from '../misc/TextureCubeNode.js';
 
 
 
 
-var elements = NodeUtils.elements,
+const elements = NodeUtils.elements,
 	constructors = [ 'float', 'vec2', 'vec3', 'vec4' ],
 	constructors = [ 'float', 'vec2', 'vec3', 'vec4' ],
 	convertFormatToType = {
 	convertFormatToType = {
 		float: 'f',
 		float: 'f',
@@ -46,127 +46,125 @@ var elements = NodeUtils.elements,
 		m4: 'mat4'
 		m4: 'mat4'
 	};
 	};
 
 
-function NodeBuilder() {
+class NodeBuilder {
 
 
-	this.slots = [];
-	this.caches = [];
-	this.contexts = [];
+	constructor() {
 
 
-	this.keywords = {};
+		this.slots = [];
+		this.caches = [];
+		this.contexts = [];
 
 
-	this.nodeData = {};
+		this.keywords = {};
 
 
-	this.requires = {
-		uv: [],
-		color: [],
-		lights: false,
-		fog: false,
-		transparent: false,
-		irradiance: false
-	};
-
-	this.includes = {
-		consts: [],
-		functions: [],
-		structs: []
-	};
+		this.nodeData = {};
 
 
-	this.attributes = {};
+		this.requires = {
+			uv: [],
+			color: [],
+			lights: false,
+			fog: false,
+			transparent: false,
+			irradiance: false
+		};
 
 
-	this.prefixCode = [
-		'#ifdef TEXTURE_LOD_EXT',
+		this.includes = {
+			consts: [],
+			functions: [],
+			structs: []
+		};
 
 
-		'	#define texCube(a, b) textureCube(a, b)',
-		'	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)',
+		this.attributes = {};
 
 
-		'	#define tex2D(a, b) texture2D(a, b)',
-		'	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)',
+		this.prefixCode = [
+			'#ifdef TEXTURE_LOD_EXT',
 
 
-		'#else',
+			'	#define texCube(a, b) textureCube(a, b)',
+			'	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)',
 
 
-		'	#define texCube(a, b) textureCube(a, b)',
-		'	#define texCubeBias(a, b, c) textureCube(a, b, c)',
+			'	#define tex2D(a, b) texture2D(a, b)',
+			'	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)',
 
 
-		'	#define tex2D(a, b) texture2D(a, b)',
-		'	#define tex2DBias(a, b, c) texture2D(a, b, c)',
+			'#else',
 
 
-		'#endif',
+			'	#define texCube(a, b) textureCube(a, b)',
+			'	#define texCubeBias(a, b, c) textureCube(a, b, c)',
 
 
-		'#include <packing>',
-		'#include <common>'
+			'	#define tex2D(a, b) texture2D(a, b)',
+			'	#define tex2DBias(a, b, c) texture2D(a, b, c)',
 
 
-	].join( '\n' );
+			'#endif',
 
 
-	this.parsCode = {
-		vertex: '',
-		fragment: ''
-	};
+			'#include <packing>',
+			'#include <common>'
 
 
-	this.code = {
-		vertex: '',
-		fragment: ''
-	};
+		].join( '\n' );
 
 
-	this.nodeCode = {
-		vertex: '',
-		fragment: ''
-	};
+		this.parsCode = {
+			vertex: '',
+			fragment: ''
+		};
 
 
-	this.resultCode = {
-		vertex: '',
-		fragment: ''
-	};
+		this.code = {
+			vertex: '',
+			fragment: ''
+		};
 
 
-	this.finalCode = {
-		vertex: '',
-		fragment: ''
-	};
+		this.nodeCode = {
+			vertex: '',
+			fragment: ''
+		};
 
 
-	this.inputs = {
-		uniforms: {
-			list: [],
-			vertex: [],
-			fragment: []
-		},
-		vars: {
-			varying: [],
-			vertex: [],
-			fragment: []
-		}
-	};
+		this.resultCode = {
+			vertex: '',
+			fragment: ''
+		};
 
 
-	// send to material
+		this.finalCode = {
+			vertex: '',
+			fragment: ''
+		};
 
 
-	this.defines = {};
+		this.inputs = {
+			uniforms: {
+				list: [],
+				vertex: [],
+				fragment: []
+			},
+			vars: {
+				varying: [],
+				vertex: [],
+				fragment: []
+			}
+		};
 
 
-	this.uniforms = {};
+		// send to material
 
 
-	this.extensions = {};
+		this.defines = {};
 
 
-	this.updaters = [];
+		this.uniforms = {};
 
 
-	this.nodes = [];
+		this.extensions = {};
 
 
-	// --
+		this.updaters = [];
 
 
-	this.analyzing = false;
+		this.nodes = [];
 
 
-}
+		// --
 
 
-NodeBuilder.prototype = {
+		this.analyzing = false;
 
 
-	constructor: NodeBuilder,
+	}
 
 
-	build: function ( vertex, fragment ) {
+	build( vertex, fragment ) {
 
 
 		this.buildShader( 'vertex', vertex );
 		this.buildShader( 'vertex', vertex );
 		this.buildShader( 'fragment', fragment );
 		this.buildShader( 'fragment', fragment );
 
 
-		for ( var i = 0; i < this.requires.uv.length; i ++ ) {
+		for ( let i = 0; i < this.requires.uv.length; i ++ ) {
 
 
 			if ( this.requires.uv[ i ] ) {
 			if ( this.requires.uv[ i ] ) {
 
 
-				var uvIndex = i > 0 ? i + 1 : '';
+				const uvIndex = i > 0 ? i + 1 : '';
 
 
 				this.addVaryCode( 'varying vec2 vUv' + uvIndex + ';' );
 				this.addVaryCode( 'varying vec2 vUv' + uvIndex + ';' );
 
 
@@ -234,15 +232,15 @@ NodeBuilder.prototype = {
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	buildShader: function ( shader, node ) {
+	buildShader( shader, node ) {
 
 
 		this.resultCode[ shader ] = node.build( this.setShader( shader ), 'v4' );
 		this.resultCode[ shader ] = node.build( this.setShader( shader ), 'v4' );
 
 
-	},
+	}
 
 
-	setMaterial: function ( material, renderer ) {
+	setMaterial( material, renderer ) {
 
 
 		this.material = material;
 		this.material = material;
 		this.renderer = renderer;
 		this.renderer = renderer;
@@ -254,39 +252,39 @@ NodeBuilder.prototype = {
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	addFlow: function ( slot, cache, context ) {
+	addFlow( slot, cache, context ) {
 
 
 		return this.addSlot( slot ).addCache( cache ).addContext( context );
 		return this.addSlot( slot ).addCache( cache ).addContext( context );
 
 
-	},
+	}
 
 
-	removeFlow: function () {
+	removeFlow() {
 
 
 		return this.removeSlot().removeCache().removeContext();
 		return this.removeSlot().removeCache().removeContext();
 
 
-	},
+	}
 
 
-	addCache: function ( name ) {
+	addCache( name ) {
 
 
 		this.cache = name || '';
 		this.cache = name || '';
 		this.caches.push( this.cache );
 		this.caches.push( this.cache );
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	removeCache: function () {
+	removeCache() {
 
 
 		this.caches.pop();
 		this.caches.pop();
 		this.cache = this.caches[ this.caches.length - 1 ] || '';
 		this.cache = this.caches[ this.caches.length - 1 ] || '';
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	addContext: function ( context ) {
+	addContext( context ) {
 
 
 		this.context = Object.assign( {}, this.context, context );
 		this.context = Object.assign( {}, this.context, context );
 		this.context.extra = this.context.extra || {};
 		this.context.extra = this.context.extra || {};
@@ -295,181 +293,176 @@ NodeBuilder.prototype = {
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	removeContext: function () {
+	removeContext() {
 
 
 		this.contexts.pop();
 		this.contexts.pop();
 		this.context = this.contexts[ this.contexts.length - 1 ] || {};
 		this.context = this.contexts[ this.contexts.length - 1 ] || {};
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	addSlot: function ( name ) {
+	addSlot( name = '' ) {
 
 
-		this.slot = name || '';
+		this.slot = name;
 		this.slots.push( this.slot );
 		this.slots.push( this.slot );
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	removeSlot: function () {
+	removeSlot() {
 
 
 		this.slots.pop();
 		this.slots.pop();
 		this.slot = this.slots[ this.slots.length - 1 ] || '';
 		this.slot = this.slots[ this.slots.length - 1 ] || '';
 
 
 		return this;
 		return this;
 
 
-	},
-
+	}
 
 
-	addVertexCode: function ( code ) {
+	addVertexCode( code ) {
 
 
 		this.addCode( code, 'vertex' );
 		this.addCode( code, 'vertex' );
 
 
-	},
+	}
 
 
-	addFragmentCode: function ( code ) {
+	addFragmentCode( code ) {
 
 
 		this.addCode( code, 'fragment' );
 		this.addCode( code, 'fragment' );
 
 
-	},
+	}
 
 
-	addCode: function ( code, shader ) {
+	addCode( code, shader ) {
 
 
 		this.code[ shader || this.shader ] += code + '\n';
 		this.code[ shader || this.shader ] += code + '\n';
 
 
-	},
-
+	}
 
 
-	addVertexNodeCode: function ( code ) {
+	addVertexNodeCode( code ) {
 
 
 		this.addNodeCode( code, 'vertex' );
 		this.addNodeCode( code, 'vertex' );
 
 
-	},
+	}
 
 
-	addFragmentNodeCode: function ( code ) {
+	addFragmentNodeCode( code ) {
 
 
 		this.addNodeCode( code, 'fragment' );
 		this.addNodeCode( code, 'fragment' );
 
 
-	},
+	}
 
 
-	addNodeCode: function ( code, shader ) {
+	addNodeCode( code, shader ) {
 
 
 		this.nodeCode[ shader || this.shader ] += code + '\n';
 		this.nodeCode[ shader || this.shader ] += code + '\n';
 
 
-	},
+	}
 
 
-	clearNodeCode: function ( shader ) {
+	clearNodeCode( shader ) {
 
 
 		shader = shader || this.shader;
 		shader = shader || this.shader;
 
 
-		var code = this.nodeCode[ shader ];
+		const code = this.nodeCode[ shader ];
 
 
 		this.nodeCode[ shader ] = '';
 		this.nodeCode[ shader ] = '';
 
 
 		return code;
 		return code;
 
 
-	},
+	}
 
 
-	clearVertexNodeCode: function ( ) {
+	clearVertexNodeCode( ) {
 
 
 		return this.clearNodeCode( 'vertex' );
 		return this.clearNodeCode( 'vertex' );
 
 
-	},
+	}
 
 
-	clearFragmentNodeCode: function ( ) {
+	clearFragmentNodeCode( ) {
 
 
 		return this.clearNodeCode( 'fragment' );
 		return this.clearNodeCode( 'fragment' );
 
 
-	},
+	}
 
 
-	addVertexFinalCode: function ( code ) {
+	addVertexFinalCode( code ) {
 
 
 		this.addFinalCode( code, 'vertex' );
 		this.addFinalCode( code, 'vertex' );
 
 
-	},
+	}
 
 
-	addFragmentFinalCode: function ( code ) {
+	addFragmentFinalCode( code ) {
 
 
 		this.addFinalCode( code, 'fragment' );
 		this.addFinalCode( code, 'fragment' );
 
 
-	},
+	}
 
 
-	addFinalCode: function ( code, shader ) {
+	addFinalCode( code, shader ) {
 
 
 		this.finalCode[ shader || this.shader ] += code + '\n';
 		this.finalCode[ shader || this.shader ] += code + '\n';
 
 
-	},
-
+	}
 
 
-	addVertexParsCode: function ( code ) {
+	addVertexParsCode( code ) {
 
 
 		this.addParsCode( code, 'vertex' );
 		this.addParsCode( code, 'vertex' );
 
 
-	},
+	}
 
 
-	addFragmentParsCode: function ( code ) {
+	addFragmentParsCode( code ) {
 
 
 		this.addParsCode( code, 'fragment' );
 		this.addParsCode( code, 'fragment' );
 
 
-	},
+	}
 
 
-	addParsCode: function ( code, shader ) {
+	addParsCode( code, shader ) {
 
 
 		this.parsCode[ shader || this.shader ] += code + '\n';
 		this.parsCode[ shader || this.shader ] += code + '\n';
 
 
-	},
-
+	}
 
 
-	addVaryCode: function ( code ) {
+	addVaryCode( code ) {
 
 
 		this.addVertexParsCode( code );
 		this.addVertexParsCode( code );
 		this.addFragmentParsCode( code );
 		this.addFragmentParsCode( code );
 
 
-	},
-
+	}
 
 
-	isCache: function ( name ) {
+	isCache( name ) {
 
 
 		return this.caches.indexOf( name ) !== - 1;
 		return this.caches.indexOf( name ) !== - 1;
 
 
-	},
+	}
 
 
-	isSlot: function ( name ) {
+	isSlot( name ) {
 
 
 		return this.slots.indexOf( name ) !== - 1;
 		return this.slots.indexOf( name ) !== - 1;
 
 
-	},
+	}
 
 
-	define: function ( name, value ) {
+	define( name, value ) {
 
 
 		this.defines[ name ] = value === undefined ? 1 : value;
 		this.defines[ name ] = value === undefined ? 1 : value;
 
 
-	},
+	}
 
 
-	require: function ( name ) {
+	require( name ) {
 
 
 		this.requires[ name ] = true;
 		this.requires[ name ] = true;
 
 
-	},
+	}
 
 
-	isDefined: function ( name ) {
+	isDefined( name ) {
 
 
 		return this.defines[ name ] !== undefined;
 		return this.defines[ name ] !== undefined;
 
 
-	},
+	}
 
 
-	getVar: function ( uuid, type, ns, shader = 'varying', prefix = 'V', label = '' ) {
+	getVar( uuid, type, ns, shader = 'varying', prefix = 'V', label = '' ) {
 
 
-		var vars = this.getVars( shader ),
-			data = vars[ uuid ];
+		const vars = this.getVars( shader );
+		let data = vars[ uuid ];
 
 
 		if ( ! data ) {
 		if ( ! data ) {
 
 
-			var index = vars.length,
+			const index = vars.length,
 				name = ns ? ns : 'node' + prefix + index + ( label ? '_' + label : '' );
 				name = ns ? ns : 'node' + prefix + index + ( label ? '_' + label : '' );
 
 
 			data = { name: name, type: type };
 			data = { name: name, type: type };
@@ -481,19 +474,19 @@ NodeBuilder.prototype = {
 
 
 		return data;
 		return data;
 
 
-	},
+	}
 
 
-	getTempVar: function ( uuid, type, ns, label ) {
+	getTempVar( uuid, type, ns, label ) {
 
 
 		return this.getVar( uuid, type, ns, this.shader, 'T', label );
 		return this.getVar( uuid, type, ns, this.shader, 'T', label );
 
 
-	},
+	}
 
 
-	getAttribute: function ( name, type ) {
+	getAttribute( name, type ) {
 
 
 		if ( ! this.attributes[ name ] ) {
 		if ( ! this.attributes[ name ] ) {
 
 
-			var varying = this.getVar( name, type );
+			const varying = this.getVar( name, type );
 
 
 			this.addVertexParsCode( 'attribute ' + type + ' ' + name + ';' );
 			this.addVertexParsCode( 'attribute ' + type + ' ' + name + ';' );
 			this.addVertexFinalCode( varying.name + ' = ' + name + ';' );
 			this.addVertexFinalCode( varying.name + ' = ' + name + ';' );
@@ -504,9 +497,9 @@ NodeBuilder.prototype = {
 
 
 		return this.attributes[ name ];
 		return this.attributes[ name ];
 
 
-	},
+	}
 
 
-	getCode: function ( shader ) {
+	getCode( shader ) {
 
 
 		return [
 		return [
 			this.prefixCode,
 			this.prefixCode,
@@ -524,21 +517,19 @@ NodeBuilder.prototype = {
 			'}'
 			'}'
 		].join( '\n' );
 		].join( '\n' );
 
 
-	},
-
-	getVarListCode: function ( vars, prefix ) {
+	}
 
 
-		prefix = prefix || '';
+	getVarListCode( vars, prefix = '' ) {
 
 
-		var code = '';
+		let code = '';
 
 
-		for ( var i = 0, l = vars.length; i < l; ++ i ) {
+		for ( let i = 0, l = vars.length; i < l; ++ i ) {
 
 
-			var nVar = vars[ i ],
+			const nVar = vars[ i ],
 				type = nVar.type,
 				type = nVar.type,
 				name = nVar.name;
 				name = nVar.name;
 
 
-			var formatType = this.getFormatByType( type );
+			const formatType = this.getFormatByType( type );
 
 
 			if ( formatType === undefined ) {
 			if ( formatType === undefined ) {
 
 
@@ -552,28 +543,28 @@ NodeBuilder.prototype = {
 
 
 		return code;
 		return code;
 
 
-	},
+	}
 
 
-	getVars: function ( shader ) {
+	getVars( shader ) {
 
 
 		return this.inputs.vars[ shader || this.shader ];
 		return this.inputs.vars[ shader || this.shader ];
 
 
-	},
+	}
 
 
-	getNodeData: function ( node ) {
+	getNodeData( node ) {
 
 
-		var uuid = node.isNode ? node.uuid : node;
+		const uuid = node.isNode ? node.uuid : node;
 
 
 		return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
 		return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
 
 
-	},
+	}
 
 
-	createUniform: function ( shader, type, node, ns, needsUpdate, label ) {
+	createUniform( shader, type, node, ns, needsUpdate, label ) {
 
 
-		var uniforms = this.inputs.uniforms,
+		const uniforms = this.inputs.uniforms,
 			index = uniforms.list.length;
 			index = uniforms.list.length;
 
 
-		var uniform = new NodeUniform( {
+		const uniform = new NodeUniform( {
 			type: type,
 			type: type,
 			name: ns ? ns : 'nodeU' + index + ( label ? '_' + label : '' ),
 			name: ns ? ns : 'nodeU' + index + ( label ? '_' + label : '' ),
 			node: node,
 			node: node,
@@ -589,23 +580,23 @@ NodeBuilder.prototype = {
 
 
 		return uniform;
 		return uniform;
 
 
-	},
+	}
 
 
-	createVertexUniform: function ( type, node, ns, needsUpdate, label ) {
+	createVertexUniform( type, node, ns, needsUpdate, label ) {
 
 
 		return this.createUniform( 'vertex', type, node, ns, needsUpdate, label );
 		return this.createUniform( 'vertex', type, node, ns, needsUpdate, label );
 
 
-	},
+	}
 
 
-	createFragmentUniform: function ( type, node, ns, needsUpdate, label ) {
+	createFragmentUniform( type, node, ns, needsUpdate, label ) {
 
 
 		return this.createUniform( 'fragment', type, node, ns, needsUpdate, label );
 		return this.createUniform( 'fragment', type, node, ns, needsUpdate, label );
 
 
-	},
+	}
 
 
-	include: function ( node, parent, source ) {
+	include( node, parent, source ) {
 
 
-		var includesStruct;
+		let includesStruct;
 
 
 		node = typeof node === 'string' ? NodeLib.get( node ) : node;
 		node = typeof node === 'string' ? NodeLib.get( node ) : node;
 
 
@@ -630,11 +621,11 @@ NodeBuilder.prototype = {
 
 
 		}
 		}
 
 
-		var includes = includesStruct[ this.shader ] = includesStruct[ this.shader ] || [];
+		const includes = includesStruct[ this.shader ] = includesStruct[ this.shader ] || [];
 
 
 		if ( node ) {
 		if ( node ) {
 
 
-			var included = includes[ node.name ];
+			let included = includes[ node.name ];
 
 
 			if ( ! included ) {
 			if ( ! included ) {
 
 
@@ -655,7 +646,7 @@ NodeBuilder.prototype = {
 
 
 				if ( node.includes && node.includes.length ) {
 				if ( node.includes && node.includes.length ) {
 
 
-					var i = 0;
+					let i = 0;
 
 
 					do {
 					do {
 
 
@@ -681,88 +672,79 @@ NodeBuilder.prototype = {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	colorToVectorProperties: function ( color ) {
+	colorToVectorProperties( color ) {
 
 
 		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
 		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
 
 
-	},
+	}
 
 
-	colorToVector: function ( color ) {
+	colorToVector( color ) {
 
 
 		return color.replace( /c/g, 'v3' );
 		return color.replace( /c/g, 'v3' );
 
 
-	},
+	}
 
 
-	getIncludes: function ( type, shader ) {
+	getIncludes( type, shader ) {
 
 
 		return this.includes[ type ][ shader || this.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 ) {
+	getIncludesCode( type, shader ) {
 
 
-			var includes = this.getIncludes( type, shader );
+		let includes = this.getIncludes( type, shader );
 
 
-			if ( ! includes ) return '';
+		if ( ! includes ) return '';
 
 
-			var code = '',
-				includes = includes.sort( sortByPosition );
+		let code = '';
 
 
-			for ( var i = 0; i < includes.length; i ++ ) {
+		includes = includes.sort( sortByPosition );
 
 
-				if ( includes[ i ].src ) code += includes[ i ].src + '\n';
+		for ( let i = 0; i < includes.length; i ++ ) {
 
 
-			}
+			if ( includes[ i ].src ) code += includes[ i ].src + '\n';
 
 
-			return code;
+		}
 
 
-		};
+		return code;
 
 
-	}(),
+	}
 
 
-	getConstructorFromLength: function ( len ) {
+	getConstructorFromLength( len ) {
 
 
 		return constructors[ len - 1 ];
 		return constructors[ len - 1 ];
 
 
-	},
+	}
 
 
-	isTypeMatrix: function ( format ) {
+	isTypeMatrix( format ) {
 
 
 		return /^m/.test( format );
 		return /^m/.test( format );
 
 
-	},
+	}
 
 
-	getTypeLength: function ( type ) {
+	getTypeLength( type ) {
 
 
 		if ( type === 'f' ) return 1;
 		if ( type === 'f' ) return 1;
 
 
 		return parseInt( this.colorToVector( type ).substr( 1 ) );
 		return parseInt( this.colorToVector( type ).substr( 1 ) );
 
 
-	},
+	}
 
 
-	getTypeFromLength: function ( len ) {
+	getTypeFromLength( len ) {
 
 
 		if ( len === 1 ) return 'f';
 		if ( len === 1 ) return 'f';
 
 
 		return 'v' + len;
 		return 'v' + len;
 
 
-	},
+	}
 
 
-	findNode: function () {
+	findNode() {
 
 
-		for ( var i = 0; i < arguments.length; i ++ ) {
+		for ( let i = 0; i < arguments.length; i ++ ) {
 
 
-			var nodeCandidate = arguments[ i ];
+			const nodeCandidate = arguments[ i ];
 
 
 			if ( nodeCandidate !== undefined && nodeCandidate.isNode ) {
 			if ( nodeCandidate !== undefined && nodeCandidate.isNode ) {
 
 
@@ -772,13 +754,13 @@ NodeBuilder.prototype = {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	resolve: function () {
+	resolve() {
 
 
-		for ( var i = 0; i < arguments.length; i ++ ) {
+		for ( let i = 0; i < arguments.length; i ++ ) {
 
 
-			var nodeCandidate = arguments[ i ];
+			const nodeCandidate = arguments[ i ];
 
 
 			if ( nodeCandidate !== undefined ) {
 			if ( nodeCandidate !== undefined ) {
 
 
@@ -828,11 +810,11 @@ NodeBuilder.prototype = {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	format: function ( code, from, to ) {
+	format( code, from, to ) {
 
 
-		var typeToType = this.colorToVector( to + ' <- ' + from );
+		const typeToType = this.colorToVector( to + ' <- ' + from );
 
 
 		switch ( typeToType ) {
 		switch ( typeToType ) {
 
 
@@ -876,21 +858,21 @@ NodeBuilder.prototype = {
 
 
 		return code;
 		return code;
 
 
-	},
+	}
 
 
-	getTypeByFormat: function ( format ) {
+	getTypeByFormat( format ) {
 
 
 		return convertFormatToType[ format ] || format;
 		return convertFormatToType[ format ] || format;
 
 
-	},
+	}
 
 
-	getFormatByType: function ( type ) {
+	getFormatByType( type ) {
 
 
 		return convertTypeToFormat[ type ] || type;
 		return convertTypeToFormat[ type ] || type;
 
 
-	},
+	}
 
 
-	getUuid: function ( uuid, useCache ) {
+	getUuid( uuid, useCache ) {
 
 
 		useCache = useCache !== undefined ? useCache : true;
 		useCache = useCache !== undefined ? useCache : true;
 
 
@@ -898,37 +880,37 @@ NodeBuilder.prototype = {
 
 
 		return uuid;
 		return uuid;
 
 
-	},
+	}
 
 
-	getElementByIndex: function ( index ) {
+	getElementByIndex( index ) {
 
 
 		return elements[ index ];
 		return elements[ index ];
 
 
-	},
+	}
 
 
-	getIndexByElement: function ( elm ) {
+	getIndexByElement( elm ) {
 
 
 		return elements.indexOf( elm );
 		return elements.indexOf( elm );
 
 
-	},
+	}
 
 
-	isShader: function ( shader ) {
+	isShader( shader ) {
 
 
 		return this.shader === shader;
 		return this.shader === shader;
 
 
-	},
+	}
 
 
-	setShader: function ( shader ) {
+	setShader( shader ) {
 
 
 		this.shader = shader;
 		this.shader = shader;
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	mergeDefines: function ( defines ) {
+	mergeDefines( defines ) {
 
 
-		for ( var name in defines ) {
+		for ( const name in defines ) {
 
 
 			this.defines[ name ] = defines[ name ];
 			this.defines[ name ] = defines[ name ];
 
 
@@ -936,11 +918,11 @@ NodeBuilder.prototype = {
 
 
 		return this.defines;
 		return this.defines;
 
 
-	},
+	}
 
 
-	mergeUniform: function ( uniforms ) {
+	mergeUniform( uniforms ) {
 
 
-		for ( var name in uniforms ) {
+		for ( const name in uniforms ) {
 
 
 			this.uniforms[ name ] = uniforms[ name ];
 			this.uniforms[ name ] = uniforms[ name ];
 
 
@@ -948,11 +930,11 @@ NodeBuilder.prototype = {
 
 
 		return this.uniforms;
 		return this.uniforms;
 
 
-	},
+	}
 
 
-	getTextureEncodingFromMap: function ( map ) {
+	getTextureEncodingFromMap( map ) {
 
 
-		var encoding;
+		let encoding;
 
 
 		if ( ! map ) {
 		if ( ! map ) {
 
 
@@ -979,6 +961,12 @@ NodeBuilder.prototype = {
 
 
 	}
 	}
 
 
-};
+}
+
+function sortByPosition( a, b ) {
+
+	return a.deps.length - b.deps.length;
+
+}
 
 
 export { NodeBuilder };
 export { NodeBuilder };

+ 13 - 15
examples/jsm/nodes/core/NodeFrame.js

@@ -1,16 +1,14 @@
-function NodeFrame( time ) {
+class NodeFrame {
 
 
-	this.time = time !== undefined ? time : 0;
+	constructor( time ) {
 
 
-	this.id = 0;
+		this.time = time !== undefined ? time : 0;
 
 
-}
-
-NodeFrame.prototype = {
+		this.id = 0;
 
 
-	constructor: NodeFrame,
+	}
 
 
-	update: function ( delta ) {
+	update( delta ) {
 
 
 		++ this.id;
 		++ this.id;
 
 
@@ -19,25 +17,25 @@ NodeFrame.prototype = {
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	setRenderer: function ( renderer ) {
+	setRenderer( renderer ) {
 
 
 		this.renderer = renderer;
 		this.renderer = renderer;
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	setRenderTexture: function ( renderTexture ) {
+	setRenderTexture( renderTexture ) {
 
 
 		this.renderTexture = renderTexture;
 		this.renderTexture = renderTexture;
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	updateNode: function ( node ) {
+	updateNode( node ) {
 
 
 		if ( node.frameId === this.id ) return this;
 		if ( node.frameId === this.id ) return this;
 
 
@@ -49,6 +47,6 @@ NodeFrame.prototype = {
 
 
 	}
 	}
 
 
-};
+}
 
 
 export { NodeFrame };
 export { NodeFrame };

+ 1 - 1
examples/jsm/nodes/core/NodeLib.js

@@ -1,4 +1,4 @@
-var NodeLib = {
+const NodeLib = {
 
 
 	nodes: {},
 	nodes: {},
 	keywords: {},
 	keywords: {},

+ 13 - 19
examples/jsm/nodes/core/NodeUniform.js

@@ -1,32 +1,26 @@
-function NodeUniform( params ) {
+class NodeUniform {
 
 
-	params = params || {};
+	constructor( params = {} ) {
 
 
-	this.name = params.name;
-	this.type = params.type;
-	this.node = params.node;
-	this.needsUpdate = params.needsUpdate;
+		this.name = params.name;
+		this.type = params.type;
+		this.node = params.node;
+		this.needsUpdate = params.needsUpdate;
 
 
-}
-
-Object.defineProperties( NodeUniform.prototype, {
-
-	value: {
-
-		get: function () {
+	}
 
 
-			return this.node.value;
+	get value() {
 
 
-		},
+		return this.node.value;
 
 
-		set: function ( val ) {
+	}
 
 
-			this.node.value = val;
+	set value( val ) {
 
 
-		}
+		this.node.value = val;
 
 
 	}
 	}
 
 
-} );
+}
 
 
 export { NodeUniform };
 export { NodeUniform };

+ 4 - 4
examples/jsm/nodes/core/NodeUtils.js

@@ -1,4 +1,4 @@
-var NodeUtils = {
+const NodeUtils = {
 
 
 	elements: [ 'x', 'y', 'z', 'w' ],
 	elements: [ 'x', 'y', 'z', 'w' ],
 
 
@@ -48,11 +48,11 @@ var NodeUtils = {
 
 
 		return function addShortcuts( proto, proxy, list ) {
 		return function addShortcuts( proto, proxy, list ) {
 
 
-			var shortcuts = {};
+			const shortcuts = {};
 
 
-			for ( var i = 0; i < list.length; ++ i ) {
+			for ( let i = 0; i < list.length; ++ i ) {
 
 
-				var data = list[ i ].split( '.' ),
+				const data = list[ i ].split( '.' ),
 					property = data[ 0 ],
 					property = data[ 0 ],
 					subProperty = data[ 1 ];
 					subProperty = data[ 1 ];
 
 

+ 50 - 47
examples/jsm/nodes/core/StructNode.js

@@ -1,103 +1,106 @@
 import { TempNode } from './TempNode.js';
 import { TempNode } from './TempNode.js';
 
 
-var declarationRegexp = /^struct\s*([a-z_0-9]+)\s*{\s*((.|\n)*?)}/img,
+const declarationRegexp = /^struct\s*([a-z_0-9]+)\s*{\s*((.|\n)*?)}/img,
 	propertiesRegexp = /\s*(\w*?)\s*(\w*?)(\=|\;)/img;
 	propertiesRegexp = /\s*(\w*?)\s*(\w*?)(\=|\;)/img;
 
 
-function StructNode( src ) {
+class StructNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( src ) {
 
 
-	this.parse( src );
+		super();
 
 
-}
+		this.parse( src );
 
 
-StructNode.prototype = Object.create( TempNode.prototype );
-StructNode.prototype.constructor = StructNode;
-StructNode.prototype.nodeType = 'Struct';
+	}
 
 
-StructNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	return builder.getTypeByFormat( this.name );
+		return builder.getTypeByFormat( this.name );
 
 
-};
+	}
+
+	getInputByName( name ) {
 
 
-StructNode.prototype.getInputByName = function ( name ) {
+		let i = this.inputs.length;
 
 
-	var i = this.inputs.length;
+		while ( i -- ) {
 
 
-	while ( i -- ) {
+			if ( this.inputs[ i ].name === name ) {
 
 
-		if ( this.inputs[ i ].name === name ) {
+				return this.inputs[ i ];
 
 
-			return this.inputs[ i ];
+			}
 
 
 		}
 		}
 
 
 	}
 	}
 
 
-};
+	generate( builder, output ) {
 
 
-StructNode.prototype.generate = function ( builder, output ) {
+		if ( output === 'source' ) {
 
 
-	if ( output === 'source' ) {
+			return this.src + ';';
 
 
-		return this.src + ';';
+		} else {
 
 
-	} else {
+			return builder.format( '( ' + this.src + ' )', this.getType( builder ), output );
 
 
-		return builder.format( '( ' + this.src + ' )', this.getType( builder ), output );
+		}
 
 
 	}
 	}
 
 
-};
+	parse( src = '' ) {
 
 
-StructNode.prototype.parse = function ( src ) {
+		this.src = src;
 
 
-	this.src = src || '';
+		this.inputs = [];
 
 
-	this.inputs = [];
+		const declaration = declarationRegexp.exec( this.src );
 
 
-	var declaration = declarationRegexp.exec( this.src );
+		if ( declaration ) {
 
 
-	if ( declaration ) {
+			const properties = declaration[ 2 ];
+			let match;
 
 
-		var properties = declaration[ 2 ], match;
+			while ( match = propertiesRegexp.exec( properties ) ) {
 
 
-		while ( match = propertiesRegexp.exec( properties ) ) {
+				this.inputs.push( {
+					type: match[ 1 ],
+					name: match[ 2 ]
+				} );
 
 
-			this.inputs.push( {
-				type: match[ 1 ],
-				name: match[ 2 ]
-			} );
+			}
 
 
-		}
+			this.name = declaration[ 1 ];
+
+		} else {
 
 
-		this.name = declaration[ 1 ];
+			this.name = '';
 
 
-	} else {
+		}
 
 
-		this.name = '';
+		this.type = this.name;
 
 
 	}
 	}
 
 
-	this.type = this.name;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-StructNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.src = this.src;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.src = this.src;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+StructNode.prototype.nodeType = 'Struct';
 
 
 export { StructNode };
 export { StructNode };

+ 69 - 70
examples/jsm/nodes/core/TempNode.js

@@ -1,143 +1,142 @@
 import { MathUtils } from '../../../../build/three.module.js';
 import { MathUtils } from '../../../../build/three.module.js';
 import { Node } from './Node.js';
 import { Node } from './Node.js';
 
 
-function TempNode( type, params ) {
+class TempNode extends Node {
 
 
-	Node.call( this, type );
+	constructor( type, params = {} ) {
 
 
-	params = params || {};
+		super( type );
 
 
-	this.shared = params.shared !== undefined ? params.shared : true;
-	this.unique = params.unique !== undefined ? params.unique : false;
+		this.shared = params.shared !== undefined ? params.shared : true;
+		this.unique = params.unique !== undefined ? params.unique : false;
 
 
-}
+	}
 
 
-TempNode.prototype = Object.create( Node.prototype );
-TempNode.prototype.constructor = TempNode;
+	build( builder, output, uuid, ns ) {
 
 
-TempNode.prototype.build = function ( builder, output, uuid, ns ) {
+		output = output || this.getType( builder );
 
 
-	output = output || this.getType( builder );
+		if ( this.getShared( builder, output ) ) {
 
 
-	if ( this.getShared( builder, output ) ) {
+			const isUnique = this.getUnique( builder, output );
 
 
-		var isUnique = this.getUnique( builder, output );
+			if ( isUnique && this.constructor.uuid === undefined ) {
 
 
-		if ( isUnique && this.constructor.uuid === undefined ) {
+				this.constructor.uuid = MathUtils.generateUUID();
 
 
-			this.constructor.uuid = MathUtils.generateUUID();
+			}
 
 
-		}
+			uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
 
 
-		uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
+			const data = builder.getNodeData( uuid ),
+				type = data.output || this.getType( builder );
 
 
-		var data = builder.getNodeData( uuid ),
-			type = data.output || this.getType( builder );
+			if ( builder.analyzing ) {
 
 
-		if ( builder.analyzing ) {
+				if ( ( data.deps || 0 ) > 0 || this.getLabel() ) {
 
 
-			if ( ( data.deps || 0 ) > 0 || this.getLabel() ) {
+					this.appendDepsNode( builder, data, output );
 
 
-				this.appendDepsNode( builder, data, output );
+					return this.generate( builder, output, uuid );
 
 
-				return this.generate( builder, output, uuid );
+				}
 
 
-			}
+				return super.build( builder, output, uuid );
 
 
-			return Node.prototype.build.call( this, builder, output, uuid );
+			} else if ( isUnique ) {
 
 
-		} else if ( isUnique ) {
+				data.name = data.name || super.build( builder, output, uuid );
 
 
-			data.name = data.name || Node.prototype.build.call( this, builder, output, uuid );
+				return data.name;
 
 
-			return data.name;
+			} else if ( ! this.getLabel() && ( ! this.getShared( builder, type ) || ( builder.context.ignoreCache || data.deps === 1 ) ) ) {
 
 
-		} else if ( ! this.getLabel() && ( ! this.getShared( builder, type ) || ( builder.context.ignoreCache || data.deps === 1 ) ) ) {
+				return super.build( builder, output, uuid );
 
 
-			return Node.prototype.build.call( this, builder, output, uuid );
+			}
 
 
-		}
+			uuid = this.getUuid( false );
 
 
-		uuid = this.getUuid( false );
+			let name = this.getTemp( builder, uuid );
 
 
-		var name = this.getTemp( builder, uuid );
+			if ( name ) {
 
 
-		if ( name ) {
+				return builder.format( name, type, output );
 
 
-			return builder.format( name, type, output );
+			} else {
 
 
-		} else {
+				name = TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
 
 
-			name = TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
+				const code = this.generate( builder, type, uuid );
 
 
-			var code = this.generate( builder, type, uuid );
+				builder.addNodeCode( name + ' = ' + code + ';' );
 
 
-			builder.addNodeCode( name + ' = ' + code + ';' );
+				return builder.format( name, type, output );
 
 
-			return builder.format( name, type, output );
+			}
 
 
 		}
 		}
 
 
-	}
+		return super.build( builder, output, uuid );
 
 
-	return Node.prototype.build.call( this, builder, output, uuid );
+	}
 
 
-};
+	getShared( builder, output ) {
 
 
-TempNode.prototype.getShared = function ( builder, output ) {
+		return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
 
 
-	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
+	}
 
 
-};
+	getUnique( /* builder, output */ ) {
 
 
-TempNode.prototype.getUnique = function ( /* builder, output */ ) {
+		return this.unique;
 
 
-	return this.unique;
+	}
 
 
-};
+	setLabel( name ) {
 
 
-TempNode.prototype.setLabel = function ( name ) {
+		this.label = name;
 
 
-	this.label = name;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	getLabel( /* builder */ ) {
 
 
-TempNode.prototype.getLabel = function ( /* builder */ ) {
+		return this.label;
 
 
-	return this.label;
+	}
 
 
-};
+	getUuid( unique ) {
 
 
-TempNode.prototype.getUuid = function ( unique ) {
+		let uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
 
 
-	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
+		if ( typeof this.scope === 'string' ) uuid = this.scope + '-' + uuid;
 
 
-	if ( typeof this.scope === 'string' ) uuid = this.scope + '-' + uuid;
+		return uuid;
 
 
-	return uuid;
+	}
 
 
-};
+	getTemp( builder, uuid ) {
 
 
-TempNode.prototype.getTemp = function ( builder, uuid ) {
+		uuid = uuid || this.uuid;
 
 
-	uuid = uuid || this.uuid;
+		const tempVar = builder.getVars()[ uuid ];
 
 
-	var tempVar = builder.getVars()[ uuid ];
+		return tempVar ? tempVar.name : undefined;
 
 
-	return tempVar ? tempVar.name : undefined;
+	}
 
 
-};
+	generate( builder, output, uuid, type, ns ) {
 
 
-TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
+		if ( ! this.getShared( builder, output ) ) console.error( 'THREE.TempNode is not shared!' );
 
 
-	if ( ! this.getShared( builder, output ) ) console.error( 'THREE.TempNode is not shared!' );
+		uuid = uuid || this.uuid;
 
 
-	uuid = uuid || this.uuid;
+		return builder.getTempVar( uuid, type || this.getType( builder ), ns, this.getLabel() ).name;
 
 
-	return builder.getTempVar( uuid, type || this.getType( builder ), ns, this.getLabel() ).name;
+	}
 
 
-};
+}
 
 
 export { TempNode };
 export { TempNode };

+ 32 - 30
examples/jsm/nodes/core/VarNode.js

@@ -1,64 +1,66 @@
 import { Node } from './Node.js';
 import { Node } from './Node.js';
 
 
-function VarNode( type, value ) {
+class VarNode extends Node {
 
 
-	Node.call( this, type );
+	constructor( type, value ) {
 
 
-	this.value = value;
+		super( type );
 
 
-}
+		this.value = value;
 
 
-VarNode.prototype = Object.create( Node.prototype );
-VarNode.prototype.constructor = VarNode;
-VarNode.prototype.nodeType = 'Var';
+	}
 
 
-VarNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	return builder.getTypeByFormat( this.type );
+		return builder.getTypeByFormat( this.type );
+
+	}
 
 
-};
+	generate( builder, output ) {
 
 
-VarNode.prototype.generate = function ( builder, output ) {
+		const varying = builder.getVar( this.uuid, this.type );
 
 
-	var varying = builder.getVar( this.uuid, this.type );
+		if ( this.value && builder.isShader( 'vertex' ) ) {
 
 
-	if ( this.value && builder.isShader( 'vertex' ) ) {
+			builder.addNodeCode( varying.name + ' = ' + this.value.build( builder, this.getType( builder ) ) + ';' );
 
 
-		builder.addNodeCode( varying.name + ' = ' + this.value.build( builder, this.getType( builder ) ) + ';' );
+		}
+
+		return builder.format( varying.name, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-	return builder.format( varying.name, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-VarNode.prototype.copy = function ( source ) {
+		this.type = source.type;
+		this.value = source.value;
 
 
-	Node.prototype.copy.call( this, source );
+		return this;
 
 
-	this.type = source.type;
-	this.value = source.value;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-VarNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.type = this.type;
 
 
-		data = this.createJSONNode( meta );
+			if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
 
 
-		data.type = this.type;
+		}
 
 
-		if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+VarNode.prototype.nodeType = 'Var';
 
 
 export { VarNode };
 export { VarNode };

+ 105 - 103
examples/jsm/nodes/effects/BlurNode.js

@@ -6,164 +6,166 @@ import { FloatNode } from '../inputs/FloatNode.js';
 import { Vector2Node } from '../inputs/Vector2Node.js';
 import { Vector2Node } from '../inputs/Vector2Node.js';
 import { UVNode } from '../accessors/UVNode.js';
 import { UVNode } from '../accessors/UVNode.js';
 
 
-function BlurNode( value, uv, radius, size ) {
+class BlurNode extends TempNode {
 
 
-	TempNode.call( this, 'v4' );
+	constructor( value, uv, radius, size ) {
 
 
-	this.value = value;
-	this.uv = uv || new UVNode();
-	this.radius = radius || new Vector2Node( 1, 1 );
+		super( 'v4' );
 
 
-	this.size = size;
+		this.value = value;
+		this.uv = uv || new UVNode();
+		this.radius = radius || new Vector2Node( 1, 1 );
 
 
-	this.blurX = true;
-	this.blurY = true;
+		this.size = size;
 
 
-	this.horizontal = new FloatNode( 1 / 64 );
-	this.vertical = new FloatNode( 1 / 64 );
+		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 tex, vec2 uv, float s ) {',
-		'	vec4 sum = vec4( 0.0 );',
-		'	sum += texture2D( tex, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;',
-		'	sum += texture2D( tex, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;',
-		'	sum += texture2D( tex, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;',
-		'	sum += texture2D( tex, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y ) ) * 0.1633;',
-		'	sum += texture2D( tex, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;',
-		'	sum += texture2D( tex, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;',
-		'	sum += texture2D( tex, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;',
-		'	sum += texture2D( tex, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;',
-		'	return sum * .667;',
-		'}'
-	].join( '\n' ) );
+	updateFrame( /* frame */ ) {
 
 
-	var blurY = new FunctionNode( [
-		'vec4 blurY( sampler2D tex, vec2 uv, float s ) {',
-		'	vec4 sum = vec4( 0.0 );',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y ) ) * 0.1633;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;',
-		'	sum += texture2D( tex, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;',
-		'	return sum * .667;',
-		'}'
-	].join( '\n' ) );
+		if ( this.size ) {
 
 
-	return {
-		blurX: blurX,
-		blurY: blurY
-	};
+			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 ) {
 
 
+			const image = this.value.value.image;
 
 
-BlurNode.prototype = Object.create( TempNode.prototype );
-BlurNode.prototype.constructor = BlurNode;
-BlurNode.prototype.nodeType = 'Blur';
-BlurNode.prototype.hashProperties = [ 'blurX', 'blurY' ];
+			this.horizontal.value = this.radius.x / image.width;
+			this.vertical.value = this.radius.y / image.height;
 
 
-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;
+	generate( builder, output ) {
 
 
-	} else if ( this.value.value && this.value.value.image ) {
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-		var image = this.value.value.image;
+			const blurCode = [];
+			let code;
 
 
-		this.horizontal.value = this.radius.x / image.width;
-		this.vertical.value = this.radius.y / image.height;
+			const 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' ) + ' )' );
 
 
-BlurNode.prototype.generate = function ( builder, output ) {
+			}
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+			if ( this.blurY ) {
 
 
-		var blurCode = [], code;
+				blurCode.push( blurY + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.vertical.build( builder, 'f' ) + ' )' );
 
 
-		var blurX = builder.include( BlurNode.Nodes.blurX ),
-			blurY = builder.include( BlurNode.Nodes.blurY );
+			}
 
 
-		if ( this.blurX ) {
+			if ( blurCode.length == 2 ) code = '( ' + blurCode.join( ' + ' ) + ' / 2.0 )';
+			else if ( blurCode.length ) code = '( ' + blurCode[ 0 ] + ' )';
+			else code = 'vec4( 0.0 )';
 
 
-			blurCode.push( blurX + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.horizontal.build( builder, 'f' ) + ' )' );
+			return builder.format( code, this.getType( builder ), output );
 
 
-		}
+		} else {
 
 
-		if ( this.blurY ) {
+			console.warn( 'THREE.BlurNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-			blurCode.push( blurY + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.vertical.build( builder, 'f' ) + ' )' );
+			return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
 
 
 		}
 		}
 
 
-		if ( blurCode.length == 2 ) code = '( ' + blurCode.join( ' + ' ) + ' / 2.0 )';
-		else if ( blurCode.length ) code = '( ' + blurCode[ 0 ] + ' )';
-		else code = 'vec4( 0.0 )';
+	}
+
+	copy( source ) {
 
 
-		return builder.format( code, this.getType( builder ), output );
+		super.copy( source );
 
 
-	} else {
+		this.value = source.value;
+		this.uv = source.uv;
+		this.radius = source.radius;
 
 
-		console.warn( 'THREE.BlurNode is not compatible with ' + builder.shader + ' shader.' );
+		if ( source.size !== undefined ) this.size = new Vector2( source.size.x, source.size.y );
 
 
-		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+		this.blurX = source.blurX;
+		this.blurY = source.blurY;
 
 
-	}
+		return this;
 
 
-};
+	}
 
 
-BlurNode.prototype.copy = function ( source ) {
+	toJSON( meta ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+		let data = this.getJSONNode( meta );
 
 
-	this.value = source.value;
-	this.uv = source.uv;
-	this.radius = source.radius;
+		if ( ! data ) {
 
 
-	if ( source.size !== undefined ) this.size = new Vector2( source.size.x, source.size.y );
+			data = this.createJSONNode( meta );
 
 
-	this.blurX = source.blurX;
-	this.blurY = source.blurY;
+			data.value = this.value.toJSON( meta ).uuid;
+			data.uv = this.uv.toJSON( meta ).uuid;
+			data.radius = this.radius.toJSON( meta ).uuid;
 
 
-	return this;
+			if ( this.size ) data.size = { x: this.size.x, y: this.size.y };
 
 
-};
+			data.blurX = this.blurX;
+			data.blurY = this.blurY;
 
 
-BlurNode.prototype.toJSON = function ( meta ) {
+		}
 
 
-	var data = this.getJSONNode( meta );
+		return data;
 
 
-	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;
+BlurNode.Nodes = ( function () {
 
 
-		if ( this.size ) data.size = { x: this.size.x, y: this.size.y };
+	const blurX = new FunctionNode( [
+		'vec4 blurX( sampler2D tex, vec2 uv, float s ) {',
+		'	vec4 sum = vec4( 0.0 );',
+		'	sum += texture2D( tex, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;',
+		'	sum += texture2D( tex, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;',
+		'	sum += texture2D( tex, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;',
+		'	sum += texture2D( tex, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y ) ) * 0.1633;',
+		'	sum += texture2D( tex, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;',
+		'	sum += texture2D( tex, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;',
+		'	sum += texture2D( tex, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;',
+		'	sum += texture2D( tex, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;',
+		'	return sum * .667;',
+		'}'
+	].join( '\n' ) );
 
 
-		data.blurX = this.blurX;
-		data.blurY = this.blurY;
+	const blurY = new FunctionNode( [
+		'vec4 blurY( sampler2D tex, vec2 uv, float s ) {',
+		'	vec4 sum = vec4( 0.0 );',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y ) ) * 0.1633;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;',
+		'	sum += texture2D( tex, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;',
+		'	return sum * .667;',
+		'}'
+	].join( '\n' ) );
 
 
-	}
+	return {
+		blurX: blurX,
+		blurY: blurY
+	};
 
 
-	return data;
+} )();
 
 
-};
+BlurNode.prototype.nodeType = 'Blur';
+BlurNode.prototype.hashProperties = [ 'blurX', 'blurY' ];
 
 
 export { BlurNode };
 export { BlurNode };

+ 69 - 67
examples/jsm/nodes/effects/ColorAdjustmentNode.js

@@ -2,20 +2,81 @@ import { TempNode } from '../core/TempNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { LuminanceNode } from './LuminanceNode.js';
 import { LuminanceNode } from './LuminanceNode.js';
 
 
-function ColorAdjustmentNode( rgb, adjustment, method ) {
+class ColorAdjustmentNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( rgb, adjustment, method ) {
 
 
-	this.rgb = rgb;
-	this.adjustment = adjustment;
+		super( 'v3' );
 
 
-	this.method = method || ColorAdjustmentNode.SATURATION;
+		this.rgb = rgb;
+		this.adjustment = adjustment;
+
+		this.method = method || ColorAdjustmentNode.SATURATION;
+
+	}
+
+	generate( builder, output ) {
+
+		const 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;
+
+		}
+
+		const method = builder.include( ColorAdjustmentNode.Nodes[ this.method ] );
+
+		return builder.format( method + '( ' + rgb + ', ' + adjustment + ' )', this.getType( builder ), output );
+
+	}
+
+	copy( source ) {
+
+		super.copy( source );
+
+		this.rgb = source.rgb;
+		this.adjustment = source.adjustment;
+		this.method = source.method;
+
+		return this;
+
+	}
+
+	toJSON( meta ) {
+
+		let 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;
+
+	}
 
 
 }
 }
 
 
 ColorAdjustmentNode.Nodes = ( function () {
 ColorAdjustmentNode.Nodes = ( function () {
 
 
-	var hue = new FunctionNode( [
+	const hue = new FunctionNode( [
 		'vec3 hue(vec3 rgb, float adjustment) {',
 		'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 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);',
@@ -31,7 +92,7 @@ ColorAdjustmentNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var saturation = new FunctionNode( [
+	const saturation = new FunctionNode( [
 		// Algorithm from Chapter 16 of OpenGL Shading Language
 		// Algorithm from Chapter 16 of OpenGL Shading Language
 		'vec3 saturation(vec3 rgb, float adjustment) {',
 		'vec3 saturation(vec3 rgb, float adjustment) {',
 
 
@@ -42,7 +103,7 @@ ColorAdjustmentNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ), [ LuminanceNode.Nodes.luminance ] ); // include LuminanceNode function
 	].join( '\n' ), [ LuminanceNode.Nodes.luminance ] ); // include LuminanceNode function
 
 
-	var vibrance = new FunctionNode( [
+	const vibrance = new FunctionNode( [
 		// Shader by Evan Wallace adapted by @lo-th
 		// Shader by Evan Wallace adapted by @lo-th
 		'vec3 vibrance(vec3 rgb, float adjustment) {',
 		'vec3 vibrance(vec3 rgb, float adjustment) {',
 
 
@@ -70,66 +131,7 @@ ColorAdjustmentNode.VIBRANCE = 'vibrance';
 ColorAdjustmentNode.BRIGHTNESS = 'brightness';
 ColorAdjustmentNode.BRIGHTNESS = 'brightness';
 ColorAdjustmentNode.CONTRAST = 'contrast';
 ColorAdjustmentNode.CONTRAST = 'contrast';
 
 
-ColorAdjustmentNode.prototype = Object.create( TempNode.prototype );
-ColorAdjustmentNode.prototype.constructor = ColorAdjustmentNode;
 ColorAdjustmentNode.prototype.nodeType = 'ColorAdjustment';
 ColorAdjustmentNode.prototype.nodeType = 'ColorAdjustment';
 ColorAdjustmentNode.prototype.hashProperties = [ 'method' ];
 ColorAdjustmentNode.prototype.hashProperties = [ 'method' ];
 
 
-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;
-
-	return this;
-
-};
-
-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 };
 export { ColorAdjustmentNode };

+ 39 - 37
examples/jsm/nodes/effects/LuminanceNode.js

@@ -2,70 +2,72 @@ import { TempNode } from '../core/TempNode.js';
 import { ConstNode } from '../core/ConstNode.js';
 import { ConstNode } from '../core/ConstNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 
 
-function LuminanceNode( rgb ) {
+class LuminanceNode extends TempNode {
 
 
-	TempNode.call( this, 'f' );
+	constructor( rgb ) {
 
 
-	this.rgb = rgb;
+		super( 'f' );
 
 
-}
+		this.rgb = rgb;
 
 
-LuminanceNode.Nodes = ( function () {
+	}
 
 
-	var LUMA = new ConstNode( 'vec3 LUMA vec3( 0.2125, 0.7154, 0.0721 )' );
+	generate( builder, output ) {
 
 
-	var luminance = new FunctionNode( [
-		// Algorithm from Chapter 10 of Graphics Shaders
-		'float luminance( vec3 rgb ) {',
+		const luminance = builder.include( LuminanceNode.Nodes.luminance );
 
 
-		'	return dot( rgb, LUMA );',
+		return builder.format( luminance + '( ' + this.rgb.build( builder, 'v3' ) + ' )', this.getType( builder ), output );
 
 
-		'}'
-	].join( '\n' ), [ LUMA ] );
+	}
 
 
-	return {
-		LUMA: LUMA,
-		luminance: luminance
-	};
+	copy( source ) {
 
 
-} )();
+		super.copy( source );
 
 
-LuminanceNode.prototype = Object.create( TempNode.prototype );
-LuminanceNode.prototype.constructor = LuminanceNode;
-LuminanceNode.prototype.nodeType = 'Luminance';
+		this.rgb = source.rgb;
 
 
-LuminanceNode.prototype.generate = function ( builder, output ) {
+		return this;
 
 
-	var luminance = builder.include( LuminanceNode.Nodes.luminance );
+	}
 
 
-	return builder.format( luminance + '( ' + this.rgb.build( builder, 'v3' ) + ' )', this.getType( builder ), output );
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-LuminanceNode.prototype.copy = function ( source ) {
+		if ( ! data ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+			data = this.createJSONNode( meta );
 
 
-	this.rgb = source.rgb;
+			data.rgb = this.rgb.toJSON( meta ).uuid;
 
 
-	return this;
+		}
 
 
-};
+		return data;
 
 
-LuminanceNode.prototype.toJSON = function ( meta ) {
+	}
 
 
-	var data = this.getJSONNode( meta );
+}
+
+LuminanceNode.Nodes = ( function () {
 
 
-	if ( ! data ) {
+	const LUMA = new ConstNode( 'vec3 LUMA vec3( 0.2125, 0.7154, 0.0721 )' );
 
 
-		data = this.createJSONNode( meta );
+	const luminance = new FunctionNode( [
+		// Algorithm from Chapter 10 of Graphics Shaders
+		'float luminance( vec3 rgb ) {',
 
 
-		data.rgb = this.rgb.toJSON( meta ).uuid;
+		'	return dot( rgb, LUMA );',
 
 
-	}
+		'}'
+	].join( '\n' ), [ LUMA ] );
+
+	return {
+		LUMA: LUMA,
+		luminance: luminance
+	};
 
 
-	return data;
+} )();
 
 
-};
+LuminanceNode.prototype.nodeType = 'Luminance';
 
 
 export { LuminanceNode };
 export { LuminanceNode };

+ 25 - 23
examples/jsm/nodes/inputs/BoolNode.js

@@ -1,49 +1,51 @@
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function BoolNode( value ) {
+class BoolNode extends InputNode {
 
 
-	InputNode.call( this, 'b' );
+	constructor( value ) {
 
 
-	this.value = Boolean( value );
+		super( 'b' );
 
 
-}
+		this.value = Boolean( value );
 
 
-BoolNode.prototype = Object.create( InputNode.prototype );
-BoolNode.prototype.constructor = BoolNode;
-BoolNode.prototype.nodeType = 'Bool';
+	}
 
 
-BoolNode.prototype.generateReadonly = function ( builder, output, uuid, type/*, ns, needsUpdate */ ) {
+	generateReadonly( builder, output, uuid, type/*, ns, needsUpdate */ ) {
 
 
-	return builder.format( this.value, type, output );
+		return builder.format( this.value, type, output );
 
 
-};
+	}
 
 
-BoolNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	InputNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.value = source.value;
+		this.value = source.value;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-BoolNode.prototype.toJSON = function ( meta ) {
+	toJSON( meta ) {
 
 
-	var data = this.getJSONNode( meta );
+		let data = this.getJSONNode( meta );
 
 
-	if ( ! data ) {
+		if ( ! data ) {
 
 
-		data = this.createJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-		data.value = this.value;
+			data.value = this.value;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+			if ( this.readonly === true ) data.readonly = true;
+
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+BoolNode.prototype.nodeType = 'Bool';
 
 
 export { BoolNode };
 export { BoolNode };

+ 28 - 26
examples/jsm/nodes/inputs/ColorNode.js

@@ -3,54 +3,56 @@ import { Color } from '../../../../build/three.module.js';
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 
 
-function ColorNode( color, g, b ) {
+class ColorNode extends InputNode {
 
 
-	InputNode.call( this, 'c' );
+	constructor( color, g, b ) {
 
 
-	this.value = color instanceof Color ? color : new Color( color || 0, g, b );
+		super( 'c' );
 
 
-}
+		this.value = color instanceof Color ? color : new Color( color || 0, g, b );
 
 
-ColorNode.prototype = Object.create( InputNode.prototype );
-ColorNode.prototype.constructor = ColorNode;
-ColorNode.prototype.nodeType = 'Color';
+	}
 
 
-NodeUtils.addShortcuts( ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
+	generateReadonly( 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 );
 
 
-	return builder.format( 'vec3( ' + this.r + ', ' + this.g + ', ' + this.b + ' )', type, output );
+	}
 
 
-};
+	copy( source ) {
 
 
-ColorNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	InputNode.prototype.copy.call( this, source );
+		this.value.copy( source );
 
 
-	this.value.copy( source );
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-ColorNode.prototype.toJSON = function ( meta ) {
+		var data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.r = this.r;
+			data.g = this.g;
+			data.b = this.b;
 
 
-		data.r = this.r;
-		data.g = this.g;
-		data.b = this.b;
+			if ( this.readonly === true ) data.readonly = true;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+ColorNode.prototype.nodeType = 'Color';
+
+NodeUtils.addShortcuts( ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
 
 
 export { ColorNode };
 export { ColorNode };

+ 59 - 57
examples/jsm/nodes/inputs/CubeTextureNode.js

@@ -3,104 +3,106 @@ import { ReflectNode } from '../accessors/ReflectNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 
 
-function CubeTextureNode( value, uv, bias ) {
+class CubeTextureNode extends InputNode {
 
 
-	InputNode.call( this, 'v4', { shared: true } );
+	constructor( value, uv, bias ) {
 
 
-	this.value = value;
-	this.uv = uv || new ReflectNode();
-	this.bias = bias;
+		super( 'v4', { shared: true } );
 
 
-}
+		this.value = value;
+		this.uv = uv || new ReflectNode();
+		this.bias = bias;
 
 
-CubeTextureNode.prototype = Object.create( InputNode.prototype );
-CubeTextureNode.prototype.constructor = CubeTextureNode;
-CubeTextureNode.prototype.nodeType = 'CubeTexture';
+	}
 
 
-CubeTextureNode.prototype.getTexture = function ( builder, output ) {
+	getTexture( builder, output ) {
 
 
-	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 'tc' );
+		return super.generate( builder, output, this.value.uuid, 'tc' );
 
 
-};
+	}
 
 
-CubeTextureNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	if ( output === 'samplerCube' ) {
+		if ( output === 'samplerCube' ) {
 
 
-		return this.getTexture( builder, output );
+			return this.getTexture( builder, output );
 
 
-	}
+		}
 
 
-	var cubetex = this.getTexture( builder, output );
-	var uv = this.uv.build( builder, 'v3' );
-	var bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
+		const cubetex = this.getTexture( builder, output );
+		const uv = this.uv.build( builder, 'v3' );
+		let bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
 
-	if ( bias === undefined && builder.context.bias ) {
+		if ( bias === undefined && builder.context.bias ) {
 
 
-		bias = builder.context.bias.setTexture( this ).build( builder, 'f' );
+			bias = builder.context.bias.setTexture( this ).build( builder, 'f' );
 
 
-	}
+		}
 
 
-	var code;
+		let code;
 
 
-	if ( bias ) code = 'texCubeBias( ' + cubetex + ', ' + uv + ', ' + bias + ' )';
-	else code = 'texCube( ' + cubetex + ', ' + uv + ' )';
+		if ( bias ) code = 'texCubeBias( ' + cubetex + ', ' + uv + ', ' + bias + ' )';
+		else code = 'texCube( ' + cubetex + ', ' + uv + ' )';
 
 
-	// add a custom context for fix incompatibility with the core
-	// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
-	// this should be removed in the future
-	// context.include =: is used to include or not functions if used FunctionNode
-	// context.ignoreCache =: not create variables temp nodeT0..9 to optimize the code
-	var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
-	var outputType = this.getType( builder );
+		// add a custom context for fix incompatibility with the core
+		// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
+		// this should be removed in the future
+		// context.include =: is used to include or not functions if used FunctionNode
+		// context.ignoreCache =: not create variables temp nodeT0..9 to optimize the code
+		const context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
+		const outputType = this.getType( builder );
 
 
-	builder.addContext( context );
+		builder.addContext( context );
 
 
-	this.colorSpace = this.colorSpace || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
-	this.colorSpace.fromDecoding( builder.getTextureEncodingFromMap( this.value ) );
-	this.colorSpace.input.parse( code );
+		this.colorSpace = this.colorSpace || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
+		this.colorSpace.fromDecoding( builder.getTextureEncodingFromMap( this.value ) );
+		this.colorSpace.input.parse( code );
 
 
-	code = this.colorSpace.build( builder, outputType );
+		code = this.colorSpace.build( builder, outputType );
 
 
-	// end custom context
+		// end custom context
 
 
-	builder.removeContext();
+		builder.removeContext();
 
 
-	return builder.format( code, outputType, output );
+		return builder.format( code, outputType, output );
 
 
-};
+	}
+
+	copy( source ) {
+
+		super.copy( source );
 
 
-CubeTextureNode.prototype.copy = function ( source ) {
+		if ( source.value ) this.value = source.value;
 
 
-	InputNode.prototype.copy.call( this, source );
+		this.uv = source.uv;
 
 
-	if ( source.value ) this.value = source.value;
+		if ( source.bias ) this.bias = source.bias;
 
 
-	this.uv = source.uv;
+		return this;
 
 
-	if ( source.bias ) this.bias = source.bias;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-CubeTextureNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.value = this.value.uuid;
+			data.uv = this.uv.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+			if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
 
 
-		data.value = this.value.uuid;
-		data.uv = this.uv.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+CubeTextureNode.prototype.nodeType = 'CubeTexture';
 
 
 export { CubeTextureNode };
 export { CubeTextureNode };

+ 25 - 23
examples/jsm/nodes/inputs/FloatNode.js

@@ -1,49 +1,51 @@
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function FloatNode( value ) {
+class FloatNode extends InputNode {
 
 
-	InputNode.call( this, 'f' );
+	constructor( value ) {
 
 
-	this.value = value || 0;
+		super( 'f' );
 
 
-}
+		this.value = value || 0;
 
 
-FloatNode.prototype = Object.create( InputNode.prototype );
-FloatNode.prototype.constructor = FloatNode;
-FloatNode.prototype.nodeType = 'Float';
+	}
 
 
-FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type/*, ns, needsUpdate */ ) {
+	generateReadonly( builder, output, uuid, type/*, ns, needsUpdate */ ) {
 
 
-	return builder.format( this.value + ( this.value % 1 ? '' : '.0' ), type, output );
+		return builder.format( this.value + ( this.value % 1 ? '' : '.0' ), type, output );
 
 
-};
+	}
 
 
-FloatNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	InputNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.value = source.value;
+		this.value = source.value;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-FloatNode.prototype.toJSON = function ( meta ) {
+	toJSON( meta ) {
 
 
-	var data = this.getJSONNode( meta );
+		let data = this.getJSONNode( meta );
 
 
-	if ( ! data ) {
+		if ( ! data ) {
 
 
-		data = this.createJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-		data.value = this.value;
+			data.value = this.value;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+			if ( this.readonly === true ) data.readonly = true;
+
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+FloatNode.prototype.nodeType = 'Float';
 
 
 export { FloatNode };
 export { FloatNode };

+ 25 - 23
examples/jsm/nodes/inputs/IntNode.js

@@ -1,49 +1,51 @@
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function IntNode( value ) {
+class IntNode extends InputNode {
 
 
-	InputNode.call( this, 'i' );
+	constructor( value ) {
 
 
-	this.value = Math.floor( value || 0 );
+		super( 'i' );
 
 
-}
+		this.value = Math.floor( value || 0 );
 
 
-IntNode.prototype = Object.create( InputNode.prototype );
-IntNode.prototype.constructor = IntNode;
-IntNode.prototype.nodeType = 'Int';
+	}
 
 
-IntNode.prototype.generateReadonly = function ( builder, output, uuid, type/*, ns, needsUpdate */ ) {
+	generateReadonly( builder, output, uuid, type/*, ns, needsUpdate */ ) {
 
 
-	return builder.format( this.value, type, output );
+		return builder.format( this.value, type, output );
 
 
-};
+	}
 
 
-IntNode.prototype.copy = function ( source ) {
+	copy( source ) {
 
 
-	InputNode.prototype.copy.call( this, source );
+		super.copy( source );
 
 
-	this.value = source.value;
+		this.value = source.value;
 
 
-	return this;
+		return this;
 
 
-};
+	}
 
 
-IntNode.prototype.toJSON = function ( meta ) {
+	toJSON( meta ) {
 
 
-	var data = this.getJSONNode( meta );
+		let data = this.getJSONNode( meta );
 
 
-	if ( ! data ) {
+		if ( ! data ) {
 
 
-		data = this.createJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-		data.value = this.value;
+			data.value = this.value;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+			if ( this.readonly === true ) data.readonly = true;
+
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+IntNode.prototype.nodeType = 'Int';
 
 
 export { IntNode };
 export { IntNode };

+ 27 - 34
examples/jsm/nodes/inputs/Matrix3Node.js

@@ -2,69 +2,62 @@ import { Matrix3 } from '../../../../build/three.module.js';
 
 
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function Matrix3Node( matrix ) {
+class Matrix3Node extends InputNode {
 
 
-	InputNode.call( this, 'm3' );
+	constructor( matrix ) {
 
 
-	this.value = matrix || new Matrix3();
+		super( 'm3' );
 
 
-}
-
-Matrix3Node.prototype = Object.create( InputNode.prototype );
-Matrix3Node.prototype.constructor = Matrix3Node;
-Matrix3Node.prototype.nodeType = 'Matrix3';
-
-Object.defineProperties( Matrix3Node.prototype, {
+		this.value = matrix || new Matrix3();
 
 
-	elements: {
+	}
 
 
-		set: function ( val ) {
+	get elements() {
 
 
-			this.value.elements = val;
+		return this.value.elements;
 
 
-		},
+	}
 
 
-		get: function () {
+	set elements( val ) {
 
 
-			return this.value.elements;
-
-		}
+		this.value.elements = val;
 
 
 	}
 	}
 
 
-} );
+	generateReadonly( 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 );
 
 
-	return builder.format( 'mat3( ' + this.value.elements.join( ', ' ) + ' )', type, output );
+	}
 
 
-};
+	copy( source ) {
 
 
+		super.copy( source );
 
 
-Matrix3Node.prototype.copy = function ( source ) {
+		this.value.fromArray( source.elements );
 
 
-	InputNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.value.fromArray( source.elements );
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-Matrix3Node.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.elements = this.value.elements.concat();
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.elements = this.value.elements.concat();
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+Matrix3Node.prototype.nodeType = 'Matrix3';
 
 
 export { Matrix3Node };
 export { Matrix3Node };

+ 27 - 33
examples/jsm/nodes/inputs/Matrix4Node.js

@@ -2,68 +2,62 @@ import { Matrix4 } from '../../../../build/three.module.js';
 
 
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function Matrix4Node( matrix ) {
+class Matrix4Node extends InputNode {
 
 
-	InputNode.call( this, 'm4' );
+	constructor( matrix ) {
 
 
-	this.value = matrix || new Matrix4();
+		super( 'm4' );
 
 
-}
+		this.value = matrix || new Matrix4();
 
 
-Matrix4Node.prototype = Object.create( InputNode.prototype );
-Matrix4Node.prototype.constructor = Matrix4Node;
-Matrix4Node.prototype.nodeType = 'Matrix4';
+	}
 
 
-Object.defineProperties( Matrix4Node.prototype, {
+	get elements() {
 
 
-	elements: {
+		return this.value.elements;
 
 
-		set: function ( val ) {
+	}
 
 
-			this.value.elements = val;
+	set elements( val ) {
 
 
-		},
+		this.value.elements = val;
 
 
-		get: function () {
+	}
 
 
-			return this.value.elements;
+	generateReadonly( builder, output, uuid, type /*, ns, needsUpdate */ ) {
 
 
-		}
+		return builder.format( 'mat4( ' + this.value.elements.join( ', ' ) + ' )', type, output );
 
 
 	}
 	}
 
 
-} );
+	copy( source ) {
 
 
-Matrix4Node.prototype.generateReadonly = function ( builder, output, uuid, type /*, ns, needsUpdate */ ) {
+		super.copy( source );
 
 
-	return builder.format( 'mat4( ' + this.value.elements.join( ', ' ) + ' )', type, output );
+		this.scope.value.fromArray( source.elements );
 
 
-};
+		return this;
 
 
-Matrix4Node.prototype.copy = function ( source ) {
-
-	InputNode.prototype.copy.call( this, source );
-
-	this.scope.value.fromArray( source.elements );
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-Matrix4Node.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.elements = this.value.elements.concat();
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.elements = this.value.elements.concat();
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+Matrix4Node.prototype.nodeType = 'Matrix4';
 
 
 export { Matrix4Node };
 export { Matrix4Node };

+ 22 - 28
examples/jsm/nodes/inputs/PropertyNode.js

@@ -1,53 +1,47 @@
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 
 
-function PropertyNode( object, property, type ) {
+class PropertyNode extends InputNode {
 
 
-	InputNode.call( this, type );
+	constructor( object, property, type ) {
 
 
-	this.object = object;
-	this.property = property;
+		super( type );
 
 
-}
-
-PropertyNode.prototype = Object.create( InputNode.prototype );
-PropertyNode.prototype.constructor = PropertyNode;
-PropertyNode.prototype.nodeType = 'Property';
+		this.object = object;
+		this.property = property;
 
 
-Object.defineProperties( PropertyNode.prototype, {
-
-	value: {
-
-		get: function () {
+	}
 
 
-			return this.object[ this.property ];
+	get value() {
 
 
-		},
+		return this.object[ this.property ];
 
 
-		set: function ( val ) {
+	}
 
 
-			this.object[ this.property ] = val;
+	set value( val ) {
 
 
-		}
+		this.object[ this.property ] = val;
 
 
 	}
 	}
 
 
-} );
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
 
 
-PropertyNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.value = this.value;
+			data.property = this.property;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.value = this.value;
-		data.property = this.property;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+PropertyNode.prototype.nodeType = 'Property';
 
 
 export { PropertyNode };
 export { PropertyNode };

+ 80 - 77
examples/jsm/nodes/inputs/RTTNode.js

@@ -10,145 +10,148 @@ import { NodeBuilder } from '../core/NodeBuilder.js';
 import { NodeMaterial } from '../materials/NodeMaterial.js';
 import { NodeMaterial } from '../materials/NodeMaterial.js';
 import { TextureNode } from './TextureNode.js';
 import { TextureNode } from './TextureNode.js';
 
 
-function RTTNode( width, height, input, options ) {
+class RTTNode extends TextureNode {
 
 
-	options = options || {};
+	constructor( width, height, input, options = {} ) {
 
 
-	this.input = input;
+		const renderTarget = new WebGLRenderTarget( width, height, options );
 
 
-	this.clear = options.clear !== undefined ? options.clear : true;
+		super( renderTarget.texture );
 
 
-	this.renderTarget = new WebGLRenderTarget( width, height, options );
+		this.input = input;
 
 
-	this.material = new NodeMaterial();
+		this.clear = options.clear !== undefined ? options.clear : true;
 
 
-	this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene = new Scene();
+		this.renderTarget = renderTarget;
 
 
-	this.quad = new Mesh( new PlaneGeometry( 2, 2 ), this.material );
-	this.quad.frustumCulled = false; // Avoid getting clipped
-	this.scene.add( this.quad );
+		this.material = new NodeMaterial();
 
 
-	this.render = true;
+		this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+		this.scene = new Scene();
 
 
-	TextureNode.call( this, this.renderTarget.texture );
+		this.quad = new Mesh( new PlaneGeometry( 2, 2 ), this.material );
+		this.quad.frustumCulled = false; // Avoid getting clipped
+		this.scene.add( this.quad );
 
 
-}
+		this.render = true;
 
 
-RTTNode.prototype = Object.create( TextureNode.prototype );
-RTTNode.prototype.constructor = RTTNode;
-RTTNode.prototype.nodeType = 'RTT';
 
 
-RTTNode.prototype.build = function ( builder, output, uuid ) {
+	}
 
 
-	var rttBuilder = new NodeBuilder();
-	rttBuilder.nodes = builder.nodes;
-	rttBuilder.updaters = builder.updaters;
+	build( builder, output, uuid ) {
 
 
-	this.material.fragment.value = this.input;
-	this.material.build( { builder: rttBuilder } );
+		const rttBuilder = new NodeBuilder();
+		rttBuilder.nodes = builder.nodes;
+		rttBuilder.updaters = builder.updaters;
 
 
-	return TextureNode.prototype.build.call( this, builder, output, uuid );
+		this.material.fragment.value = this.input;
+		this.material.build( { builder: rttBuilder } );
 
 
-};
+		return super.build( builder, output, uuid );
 
 
-RTTNode.prototype.updateFramesaveTo = function ( frame ) {
+	}
 
 
-	this.saveTo.render = false;
+	updateFramesaveTo( frame ) {
 
 
-	if ( this.saveTo !== this.saveToCurrent ) {
+		this.saveTo.render = false;
 
 
-		if ( this.saveToMaterial ) this.saveToMaterial.dispose();
+		if ( this.saveTo !== this.saveToCurrent ) {
 
 
-		var material = new NodeMaterial();
-		material.fragment.value = this;
-		material.build();
+			if ( this.saveToMaterial ) this.saveToMaterial.dispose();
 
 
-		var scene = new Scene();
+			const material = new NodeMaterial();
+			material.fragment.value = this;
+			material.build();
 
 
-		var quad = new Mesh( new PlaneGeometry( 2, 2 ), material );
-		quad.frustumCulled = false; // Avoid getting clipped
-		scene.add( quad );
+			const scene = new Scene();
 
 
-		this.saveToScene = scene;
-		this.saveToMaterial = material;
+			const quad = new Mesh( new PlaneGeometry( 2, 2 ), material );
+			quad.frustumCulled = false; // Avoid getting clipped
+			scene.add( quad );
 
 
-	}
+			this.saveToScene = scene;
+			this.saveToMaterial = material;
 
 
-	this.saveToCurrent = this.saveTo;
+		}
 
 
-	frame.renderer.setRenderTarget( this.saveTo.renderTarget );
-	if ( this.saveTo.clear ) frame.renderer.clear();
-	frame.renderer.render( this.saveToScene, this.camera );
+		this.saveToCurrent = this.saveTo;
 
 
-};
+		frame.renderer.setRenderTarget( this.saveTo.renderTarget );
+		if ( this.saveTo.clear ) frame.renderer.clear();
+		frame.renderer.render( this.saveToScene, this.camera );
 
 
-RTTNode.prototype.updateFrame = function ( frame ) {
+	}
 
 
-	if ( frame.renderer ) {
+	updateFrame( frame ) {
 
 
-		// from the second frame
+		if ( frame.renderer ) {
 
 
-		if ( this.saveTo && this.saveTo.render === false ) {
+			// from the second frame
 
 
-			this.updateFramesaveTo( frame );
+			if ( this.saveTo && this.saveTo.render === false ) {
 
 
-		}
+				this.updateFramesaveTo( frame );
 
 
-		if ( this.render ) {
+			}
 
 
-			if ( this.material.uniforms.renderTexture ) {
+			if ( this.render ) {
 
 
-				this.material.uniforms.renderTexture.value = frame.renderTexture;
+				if ( this.material.uniforms.renderTexture ) {
 
 
-			}
+					this.material.uniforms.renderTexture.value = frame.renderTexture;
 
 
-			frame.renderer.setRenderTarget( this.renderTarget );
-			if ( this.clear ) frame.renderer.clear();
-			frame.renderer.render( this.scene, this.camera );
+				}
 
 
-		}
+				frame.renderer.setRenderTarget( this.renderTarget );
+				if ( this.clear ) frame.renderer.clear();
+				frame.renderer.render( this.scene, this.camera );
 
 
-		// first frame
+			}
 
 
-		if ( this.saveTo && this.saveTo.render === true ) {
+			// first frame
 
 
-			this.updateFramesaveTo( frame );
+			if ( this.saveTo && this.saveTo.render === true ) {
 
 
-		}
+				this.updateFramesaveTo( frame );
+
+			}
+
+		} else {
 
 
-	} else {
+			console.warn( 'RTTNode need a renderer in NodeFrame' );
 
 
-		console.warn( 'RTTNode need a renderer in NodeFrame' );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-RTTNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	TextureNode.prototype.copy.call( this, source );
+		this.saveTo = source.saveTo;
 
 
-	this.saveTo = source.saveTo;
+		return this;
 
 
-	return this;
+	}
+
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-RTTNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = super.toJSON( meta );
 
 
-	if ( ! data ) {
+			if ( this.saveTo ) data.saveTo = this.saveTo.toJSON( meta ).uuid;
 
 
-		data = TextureNode.prototype.toJSON.call( this, meta );
+		}
 
 
-		if ( this.saveTo ) data.saveTo = this.saveTo.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+RTTNode.prototype.nodeType = 'RTT';
 
 
 export { RTTNode };
 export { RTTNode };

+ 42 - 40
examples/jsm/nodes/inputs/ReflectorNode.js

@@ -5,84 +5,86 @@ import { OperatorNode } from '../math/OperatorNode.js';
 import { TextureNode } from './TextureNode.js';
 import { TextureNode } from './TextureNode.js';
 import { Matrix4Node } from './Matrix4Node.js';
 import { Matrix4Node } from './Matrix4Node.js';
 
 
-function ReflectorNode( mirror ) {
+class ReflectorNode extends TempNode {
 
 
-	TempNode.call( this, 'v4' );
+	constructor( mirror ) {
 
 
-	if ( mirror ) this.setMirror( mirror );
+		super( 'v4' );
 
 
-}
+		if ( mirror ) this.setMirror( mirror );
 
 
-ReflectorNode.prototype = Object.create( TempNode.prototype );
-ReflectorNode.prototype.constructor = ReflectorNode;
-ReflectorNode.prototype.nodeType = 'Reflector';
+	}
 
 
-ReflectorNode.prototype.setMirror = function ( mirror ) {
+	setMirror( mirror ) {
 
 
-	this.mirror = mirror;
+		this.mirror = mirror;
 
 
-	this.textureMatrix = new Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
+		this.textureMatrix = new Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
 
 
-	this.localPosition = new PositionNode( PositionNode.LOCAL );
+		this.localPosition = new PositionNode( PositionNode.LOCAL );
 
 
-	this.uv = new OperatorNode( this.textureMatrix, this.localPosition, OperatorNode.MUL );
-	this.uvResult = new OperatorNode( null, this.uv, OperatorNode.ADD );
+		this.uv = new OperatorNode( this.textureMatrix, this.localPosition, OperatorNode.MUL );
+		this.uvResult = new OperatorNode( null, this.uv, OperatorNode.ADD );
 
 
-	this.texture = new TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.uv, null, true );
+		this.texture = new TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.uv, null, true );
 
 
-};
+	}
 
 
-ReflectorNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-		this.uvResult.a = this.offset;
-		this.texture.uv = this.offset ? this.uvResult : this.uv;
+			this.uvResult.a = this.offset;
+			this.texture.uv = this.offset ? this.uvResult : this.uv;
 
 
-		if ( output === 'sampler2D' ) {
+			if ( output === 'sampler2D' ) {
 
 
-			return this.texture.build( builder, output );
+				return this.texture.build( builder, output );
 
 
-		}
+			}
+
+			return builder.format( this.texture.build( builder, this.type ), this.type, output );
 
 
-		return builder.format( this.texture.build( builder, this.type ), this.type, output );
+		} else {
 
 
-	} else {
+			console.warn( 'THREE.ReflectorNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-		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 );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
+
+		InputNode.prototype.copy.call( this, source );
 
 
-ReflectorNode.prototype.copy = function ( source ) {
+		this.scope.mirror = source.mirror;
 
 
-	InputNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.scope.mirror = source.mirror;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-ReflectorNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.mirror = this.mirror.uuid;
 
 
-		data = this.createJSONNode( meta );
+			if ( this.offset ) data.offset = this.offset.toJSON( meta ).uuid;
 
 
-		data.mirror = this.mirror.uuid;
+		}
 
 
-		if ( this.offset ) data.offset = this.offset.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+ReflectorNode.prototype.nodeType = 'Reflector';
 
 
 export { ReflectorNode };
 export { ReflectorNode };

+ 14 - 12
examples/jsm/nodes/inputs/ScreenNode.js

@@ -1,26 +1,28 @@
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 import { TextureNode } from './TextureNode.js';
 import { TextureNode } from './TextureNode.js';
 
 
-function ScreenNode( uv ) {
+class ScreenNode extends TextureNode {
 
 
-	TextureNode.call( this, undefined, uv );
+	constructor( uv ) {
 
 
-}
+		super( undefined, uv );
 
 
-ScreenNode.prototype = Object.create( TextureNode.prototype );
-ScreenNode.prototype.constructor = ScreenNode;
-ScreenNode.prototype.nodeType = 'Screen';
+	}
+
+	getUnique() {
 
 
-ScreenNode.prototype.getUnique = function () {
+		return true;
 
 
-	return true;
+	}
 
 
-};
+	getTexture( builder, output ) {
 
 
-ScreenNode.prototype.getTexture = function ( builder, output ) {
+		return InputNode.prototype.generate.call( this, builder, output, this.getUuid(), 't', 'renderTexture' );
 
 
-	return InputNode.prototype.generate.call( this, builder, output, this.getUuid(), 't', 'renderTexture' );
+	}
 
 
-};
+}
+
+ScreenNode.prototype.nodeType = 'Screen';
 
 
 export { ScreenNode };
 export { ScreenNode };

+ 65 - 62
examples/jsm/nodes/inputs/TextureNode.js

@@ -3,111 +3,114 @@ import { UVNode } from '../accessors/UVNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 
 
-function TextureNode( value, uv, bias, project ) {
+class TextureNode extends InputNode {
 
 
-	InputNode.call( this, 'v4', { shared: true } );
+	constructor( value, uv, bias, project ) {
 
 
-	this.value = value;
-	this.uv = uv || new UVNode();
-	this.bias = bias;
-	this.project = project !== undefined ? project : false;
+		super( 'v4', { shared: true } );
 
 
-}
+		this.value = value;
+		this.uv = uv || new UVNode();
+		this.bias = bias;
+		this.project = project !== undefined ? project : false;
 
 
-TextureNode.prototype = Object.create( InputNode.prototype );
-TextureNode.prototype.constructor = TextureNode;
-TextureNode.prototype.nodeType = 'Texture';
+	}
 
 
-TextureNode.prototype.getTexture = function ( builder, output ) {
+	getTexture( builder, output ) {
 
 
-	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
+		return super.generate( builder, output, this.value.uuid, 't' );
 
 
-};
+	}
 
 
-TextureNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	if ( output === 'sampler2D' ) {
+		if ( output === 'sampler2D' ) {
 
 
-		return this.getTexture( builder, output );
+			return this.getTexture( builder, output );
 
 
-	}
+		}
 
 
-	var tex = this.getTexture( builder, output ),
-		uv = this.uv.build( builder, this.project ? 'v4' : 'v2' ),
-		bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
+		const tex = this.getTexture( builder, output ),
+			uv = this.uv.build( builder, this.project ? 'v4' : 'v2' );
 
 
-	if ( bias === undefined && builder.context.bias ) {
+		let bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
 
-		bias = builder.context.bias.setTexture( this ).build( builder, 'f' );
+		if ( bias === undefined && builder.context.bias ) {
 
 
-	}
+			bias = builder.context.bias.setTexture( this ).build( builder, 'f' );
 
 
-	var method, code;
+		}
 
 
-	if ( this.project ) method = 'texture2DProj';
-	else method = bias ? 'tex2DBias' : 'tex2D';
+		let method, code;
 
 
-	if ( bias ) code = method + '( ' + tex + ', ' + uv + ', ' + bias + ' )';
-	else code = method + '( ' + tex + ', ' + uv + ' )';
+		if ( this.project ) method = 'texture2DProj';
+		else method = bias ? 'tex2DBias' : 'tex2D';
 
 
-	// add a custom context for fix incompatibility with the core
-	// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
-	// this should be removed in the future
-	// context.include is used to include or not functions if used FunctionNode
-	// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
-	var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
-	var outputType = this.getType( builder );
+		if ( bias ) code = method + '( ' + tex + ', ' + uv + ', ' + bias + ' )';
+		else code = method + '( ' + tex + ', ' + uv + ' )';
 
 
-	builder.addContext( context );
+		// add a custom context for fix incompatibility with the core
+		// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
+		// this should be removed in the future
+		// context.include is used to include or not functions if used FunctionNode
+		// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
+		const context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
+		const outputType = this.getType( builder );
 
 
-	this.colorSpace = this.colorSpace || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
-	this.colorSpace.fromDecoding( builder.getTextureEncodingFromMap( this.value ) );
-	this.colorSpace.input.parse( code );
+		builder.addContext( context );
 
 
-	code = this.colorSpace.build( builder, outputType );
+		this.colorSpace = this.colorSpace || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
+		this.colorSpace.fromDecoding( builder.getTextureEncodingFromMap( this.value ) );
+		this.colorSpace.input.parse( code );
 
 
-	// end custom context
+		code = this.colorSpace.build( builder, outputType );
 
 
-	builder.removeContext();
+		// end custom context
 
 
-	return builder.format( code, outputType, output );
+		builder.removeContext();
 
 
-};
+		return builder.format( code, outputType, output );
 
 
-TextureNode.prototype.copy = function ( source ) {
+	}
 
 
-	InputNode.prototype.copy.call( this, source );
+	copy( source ) {
 
 
-	if ( source.value ) this.value = source.value;
+		super.copy( source );
 
 
-	this.uv = source.uv;
+		if ( source.value ) this.value = source.value;
 
 
-	if ( source.bias ) this.bias = source.bias;
-	if ( source.project !== undefined ) this.project = source.project;
+		this.uv = source.uv;
 
 
-	return this;
+		if ( source.bias ) this.bias = source.bias;
+		if ( source.project !== undefined ) this.project = source.project;
 
 
-};
+		return this;
 
 
-TextureNode.prototype.toJSON = function ( meta ) {
+	}
+
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			if ( this.value ) data.value = this.value.uuid;
 
 
-		if ( this.value ) data.value = this.value.uuid;
+			data.uv = this.uv.toJSON( meta ).uuid;
+			data.project = this.project;
 
 
-		data.uv = this.uv.toJSON( meta ).uuid;
-		data.project = this.project;
+			if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
 
 
-		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+TextureNode.prototype.nodeType = 'Texture';
 
 
 export { TextureNode };
 export { TextureNode };

+ 27 - 25
examples/jsm/nodes/inputs/Vector2Node.js

@@ -3,53 +3,55 @@ import { Vector2 } from '../../../../build/three.module.js';
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 
 
-function Vector2Node( x, y ) {
+class Vector2Node extends InputNode {
 
 
-	InputNode.call( this, 'v2' );
+	constructor( x, y ) {
 
 
-	this.value = x instanceof Vector2 ? x : new Vector2( x, y );
+		super( 'v2' );
 
 
-}
+		this.value = x instanceof Vector2 ? x : new Vector2( x, y );
 
 
-Vector2Node.prototype = Object.create( InputNode.prototype );
-Vector2Node.prototype.constructor = Vector2Node;
-Vector2Node.prototype.nodeType = 'Vector2';
+	}
 
 
-NodeUtils.addShortcuts( Vector2Node.prototype, 'value', [ 'x', 'y' ] );
+	generateReadonly( 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 );
 
 
-	return builder.format( 'vec2( ' + this.x + ', ' + this.y + ' )', type, output );
+	}
 
 
-};
+	copy( source ) {
 
 
-Vector2Node.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	InputNode.prototype.copy.call( this, source );
+		this.value.copy( source );
 
 
-	this.value.copy( source );
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-Vector2Node.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.x = this.x;
+			data.y = this.y;
 
 
-		data.x = this.x;
-		data.y = this.y;
+			if ( this.readonly === true ) data.readonly = true;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+Vector2Node.prototype.nodeType = 'Vector2';
+
+NodeUtils.addShortcuts( Vector2Node.prototype, 'value', [ 'x', 'y' ] );
 
 
 export { Vector2Node };
 export { Vector2Node };

+ 28 - 26
examples/jsm/nodes/inputs/Vector3Node.js

@@ -3,54 +3,56 @@ import { Vector3 } from '../../../../build/three.module.js';
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 
 
-function Vector3Node( x, y, z ) {
+class Vector3Node extends InputNode {
 
 
-	InputNode.call( this, 'v3' );
+	constructor( x, y, z ) {
 
 
-	this.value = x instanceof Vector3 ? x : new Vector3( x, y, z );
+		super( 'v3' );
 
 
-}
+		this.value = x instanceof Vector3 ? x : new Vector3( x, y, z );
 
 
-Vector3Node.prototype = Object.create( InputNode.prototype );
-Vector3Node.prototype.constructor = Vector3Node;
-Vector3Node.prototype.nodeType = 'Vector3';
+	}
 
 
-NodeUtils.addShortcuts( Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
+	generateReadonly( 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 );
 
 
-	return builder.format( 'vec3( ' + this.x + ', ' + this.y + ', ' + this.z + ' )', type, output );
+	}
 
 
-};
+	copy( source ) {
 
 
-Vector3Node.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	InputNode.prototype.copy.call( this, source );
+		this.value.copy( source );
 
 
-	this.value.copy( source );
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-Vector3Node.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.x = this.x;
+			data.y = this.y;
+			data.z = this.z;
 
 
-		data.x = this.x;
-		data.y = this.y;
-		data.z = this.z;
+			if ( this.readonly === true ) data.readonly = true;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+Vector3Node.prototype.nodeType = 'Vector3';
+
+NodeUtils.addShortcuts( Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
 
 
 export { Vector3Node };
 export { Vector3Node };

+ 29 - 27
examples/jsm/nodes/inputs/Vector4Node.js

@@ -3,55 +3,57 @@ import { Vector4 } from '../../../../build/three.module.js';
 import { InputNode } from '../core/InputNode.js';
 import { InputNode } from '../core/InputNode.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 
 
-function Vector4Node( x, y, z, w ) {
+class Vector4Node extends InputNode {
 
 
-	InputNode.call( this, 'v4' );
+	constructor( x, y, z, w ) {
 
 
-	this.value = x instanceof Vector4 ? x : new Vector4( x, y, z, w );
+		super( 'v4' );
 
 
-}
+		this.value = x instanceof Vector4 ? x : new Vector4( x, y, z, w );
 
 
-Vector4Node.prototype = Object.create( InputNode.prototype );
-Vector4Node.prototype.constructor = Vector4Node;
-Vector4Node.prototype.nodeType = 'Vector4';
+	}
 
 
-NodeUtils.addShortcuts( Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
+	generateReadonly( 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 );
 
 
-	return builder.format( 'vec4( ' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ' )', type, output );
+	}
 
 
-};
+	copy( source ) {
 
 
-Vector4Node.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	InputNode.prototype.copy.call( this, source );
+		this.value.copy( source );
 
 
-	this.value.copy( source );
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-Vector4Node.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.x = this.x;
+			data.y = this.y;
+			data.z = this.z;
+			data.w = this.w;
 
 
-		data.x = this.x;
-		data.y = this.y;
-		data.z = this.z;
-		data.w = this.w;
+			if ( this.readonly === true ) data.readonly = true;
 
 
-		if ( this.readonly === true ) data.readonly = true;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+Vector4Node.prototype.nodeType = 'Vector4';
+
+NodeUtils.addShortcuts( Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
 
 
 export { Vector4Node };
 export { Vector4Node };

+ 104 - 102
examples/jsm/nodes/materials/nodes/BasicNode.js

@@ -1,178 +1,180 @@
 import { Node } from '../../core/Node.js';
 import { Node } from '../../core/Node.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 
 
-function BasicNode() {
+class BasicNode extends Node {
 
 
-	Node.call( this );
+	constructor() {
 
 
-	this.color = new ColorNode( 0xFFFFFF );
+		super();
 
 
-}
+		this.color = new ColorNode( 0xFFFFFF );
 
 
-BasicNode.prototype = Object.create( Node.prototype );
-BasicNode.prototype.constructor = BasicNode;
-BasicNode.prototype.nodeType = 'Basic';
+	}
+
+	generate( builder ) {
+
+		let code;
 
 
-BasicNode.prototype.generate = function ( builder ) {
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-	var code;
+			const position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+			builder.addParsCode( [
+				'varying vec3 vViewPosition;',
 
 
-		var position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
+				'#ifndef FLAT_SHADED',
 
 
-		builder.addParsCode( [
-			'varying vec3 vViewPosition;',
+				' varying vec3 vNormal;',
 
 
-			'#ifndef FLAT_SHADED',
+				'#endif',
+			].join( '\n' ) );
 
 
-			' varying vec3 vNormal;',
+			const output = [
+				'#include <beginnormal_vertex>',
+				'#include <defaultnormal_vertex>',
 
 
-			'#endif',
-		].join( '\n' ) );
+				'#ifndef FLAT_SHADED', // Normal computed with derivatives when FLAT_SHADED
 
 
-		var output = [
-			'#include <beginnormal_vertex>',
-			'#include <defaultnormal_vertex>',
+				' vNormal = normalize( transformedNormal );',
 
 
-			'#ifndef FLAT_SHADED', // Normal computed with derivatives when FLAT_SHADED
+				'#endif',
 
 
-			' vNormal = normalize( transformedNormal );',
+				'#include <begin_vertex>',
+			];
 
 
-			'#endif',
+			if ( position ) {
 
 
-			'#include <begin_vertex>',
-		];
+				output.push(
+					position.code,
+					position.result ? 'transformed = ' + position.result + ';' : ''
+				);
 
 
-		if ( position ) {
+			}
 
 
 			output.push(
 			output.push(
-				position.code,
-				position.result ? 'transformed = ' + position.result + ';' : ''
-			);
+				'#include <morphtarget_vertex>',
+				'#include <skinning_vertex>',
+				'#include <project_vertex>',
+				'#include <fog_vertex>',
+				'#include <logdepthbuf_vertex>',
+				'#include <clipping_planes_vertex>',
 
 
-		}
+				'	vViewPosition = - mvPosition.xyz;',
 
 
-		output.push(
-			'#include <morphtarget_vertex>',
-			'#include <skinning_vertex>',
-			'#include <project_vertex>',
-			'#include <fog_vertex>',
-			'#include <logdepthbuf_vertex>',
-			'#include <clipping_planes_vertex>',
+				'#include <worldpos_vertex>',
+				'#include <shadowmap_vertex>'
+			);
 
 
-			'	vViewPosition = - mvPosition.xyz;',
+			code = output.join( '\n' );
 
 
-			'#include <worldpos_vertex>',
-			'#include <shadowmap_vertex>'
-		);
+		} else {
 
 
-		code = output.join( '\n' );
+			// Analyze all nodes to reuse generate codes
+			this.color.analyze( builder, { slot: 'color' } );
 
 
-	} else {
+			if ( this.alpha ) this.alpha.analyze( builder );
+			if ( this.mask ) this.mask.analyze( builder );
 
 
-		// Analyze all nodes to reuse generate codes
-		this.color.analyze( builder, { slot: 'color' } );
+			// Build code
+			const color = this.color.flow( builder, 'c', { slot: 'color' } );
+			const alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
+			const mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
 
 
-		if ( this.alpha ) this.alpha.analyze( builder );
-		if ( this.mask ) this.mask.analyze( builder );
+			builder.requires.transparent = alpha !== undefined;
 
 
-		// Build code
-		var color = this.color.flow( builder, 'c', { slot: 'color' } );
-		var alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
-		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
+			builder.addParsCode( [
+				'varying vec3 vViewPosition;',
 
 
-		builder.requires.transparent = alpha !== undefined;
+				'#ifndef FLAT_SHADED',
 
 
-		builder.addParsCode( [
-			'varying vec3 vViewPosition;',
+				' varying vec3 vNormal;',
 
 
-			'#ifndef FLAT_SHADED',
+				'#endif',
+			].join( '\n' ) );
 
 
-			' varying vec3 vNormal;',
+			const output = [
+				// add before: prevent undeclared normal
+				'#include <normal_fragment_begin>',
 
 
-			'#endif',
-		].join( '\n' ) );
+				color.code,
+			];
 
 
-		var output = [
-			// add before: prevent undeclared normal
-			'#include <normal_fragment_begin>',
+			if ( mask ) {
 
 
-			color.code,
-		];
+				output.push(
+					mask.code,
+					'if ( ! ' + mask.result + ' ) discard;'
+				);
 
 
-		if ( mask ) {
+			}
 
 
-			output.push(
-				mask.code,
-				'if ( ! ' + mask.result + ' ) discard;'
-			);
+			if ( alpha ) {
 
 
-		}
+				output.push(
+					alpha.code,
+					'#ifdef ALPHATEST',
 
 
-		if ( alpha ) {
+					' if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
 
 
-			output.push(
-				alpha.code,
-				'#ifdef ALPHATEST',
+					'#endif'
+				);
 
 
-				' if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
+			}
 
 
-				'#endif'
-			);
+			if ( alpha ) {
 
 
-		}
+				output.push( 'gl_FragColor = vec4(' + color.result + ', ' + alpha.result + ' );' );
 
 
-		if ( alpha ) {
+			} else {
 
 
-			output.push( 'gl_FragColor = vec4(' + color.result + ', ' + alpha.result + ' );' );
+				output.push( 'gl_FragColor = vec4(' + color.result + ', 1.0 );' );
 
 
-		} else {
+			}
 
 
-			output.push( 'gl_FragColor = vec4(' + color.result + ', 1.0 );' );
+			code = output.join( '\n' );
 
 
 		}
 		}
 
 
-		code = output.join( '\n' );
+		return code;
 
 
 	}
 	}
 
 
-	return code;
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-BasicNode.prototype.copy = function ( source ) {
+		this.color = source.color;
 
 
-	Node.prototype.copy.call( this, source );
+		if ( source.position ) this.position = source.position;
+		if ( source.alpha ) this.alpha = source.alpha;
+		if ( source.mask ) this.mask = source.mask;
 
 
-	this.color = source.color;
+		return this;
 
 
-	if ( source.position ) this.position = source.position;
-	if ( source.alpha ) this.alpha = source.alpha;
-	if ( source.mask ) this.mask = source.mask;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-BasicNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.color = this.color.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+			if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
+			if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+			if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
 
 
-		data.color = this.color.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
-		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
-		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+BasicNode.prototype.nodeType = 'Basic';
 
 
 export { BasicNode };
 export { BasicNode };

+ 64 - 62
examples/jsm/nodes/materials/nodes/MeshStandardNode.js

@@ -9,106 +9,108 @@ import { OperatorNode } from '../../math/OperatorNode.js';
 import { SwitchNode } from '../../utils/SwitchNode.js';
 import { SwitchNode } from '../../utils/SwitchNode.js';
 import { NormalMapNode } from '../../misc/NormalMapNode.js';
 import { NormalMapNode } from '../../misc/NormalMapNode.js';
 
 
-function MeshStandardNode() {
+class MeshStandardNode extends StandardNode {
 
 
-	StandardNode.call( this );
+	constructor() {
 
 
-	this.properties = {
-		color: new Color( 0xffffff ),
-		roughness: 0.5,
-		metalness: 0.5,
-		normalScale: new Vector2( 1, 1 )
-	};
+		super();
 
 
-	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' )
-	};
+		this.properties = {
+			color: new Color( 0xffffff ),
+			roughness: 0.5,
+			metalness: 0.5,
+			normalScale: new 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';
+	}
+
+	build( builder ) {
+
+		const props = this.properties,
+			inputs = this.inputs;
 
 
-MeshStandardNode.prototype.build = function ( builder ) {
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-	var props = this.properties,
-		inputs = this.inputs;
+			// slots
+			// * color
+			// * map
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+			const color = builder.findNode( props.color, inputs.color ),
+				map = builder.resolve( props.map );
 
 
-		// slots
-		// * color
-		// * map
+			this.color = map ? new OperatorNode( color, map, OperatorNode.MUL ) : color;
 
 
-		var color = builder.findNode( props.color, inputs.color ),
-			map = builder.resolve( props.map );
+			// slots
+			// * roughness
+			// * roughnessMap
 
 
-		this.color = map ? new OperatorNode( color, map, OperatorNode.MUL ) : color;
+			const roughness = builder.findNode( props.roughness, inputs.roughness ),
+				roughnessMap = builder.resolve( props.roughnessMap );
 
 
-		// slots
-		// * roughness
-		// * roughnessMap
+			this.roughness = roughnessMap ? new OperatorNode( roughness, new SwitchNode( roughnessMap, 'g' ), OperatorNode.MUL ) : roughness;
 
 
-		var roughness = builder.findNode( props.roughness, inputs.roughness ),
-			roughnessMap = builder.resolve( props.roughnessMap );
+			// slots
+			// * metalness
+			// * metalnessMap
 
 
-		this.roughness = roughnessMap ? new OperatorNode( roughness, new SwitchNode( roughnessMap, 'g' ), OperatorNode.MUL ) : roughness;
+			const metalness = builder.findNode( props.metalness, inputs.metalness ),
+				metalnessMap = builder.resolve( props.metalnessMap );
 
 
-		// slots
-		// * metalness
-		// * metalnessMap
+			this.metalness = metalnessMap ? new OperatorNode( metalness, new SwitchNode( metalnessMap, 'b' ), OperatorNode.MUL ) : metalness;
 
 
-		var metalness = builder.findNode( props.metalness, inputs.metalness ),
-			metalnessMap = builder.resolve( props.metalnessMap );
+			// slots
+			// * normalMap
+			// * normalScale
 
 
-		this.metalness = metalnessMap ? new OperatorNode( metalness, new SwitchNode( metalnessMap, 'b' ), OperatorNode.MUL ) : metalness;
+			if ( props.normalMap ) {
 
 
-		// slots
-		// * normalMap
-		// * normalScale
+				this.normal = new NormalMapNode( builder.resolve( props.normalMap ) );
+				this.normal.scale = builder.findNode( props.normalScale, inputs.normalScale );
 
 
-		if ( props.normalMap ) {
+			} else {
 
 
-			this.normal = new NormalMapNode( builder.resolve( props.normalMap ) );
-			this.normal.scale = builder.findNode( props.normalScale, inputs.normalScale );
+				this.normal = undefined;
 
 
-		} else {
+			}
 
 
-			this.normal = undefined;
+			// slots
+			// * envMap
+
+			this.environment = builder.resolve( props.envMap );
 
 
 		}
 		}
 
 
-		// slots
-		// * envMap
+		// build code
 
 
-		this.environment = builder.resolve( props.envMap );
+		return super.build( builder );
 
 
 	}
 	}
 
 
-	// build code
-
-	return StandardNode.prototype.build.call( this, builder );
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-MeshStandardNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			console.warn( '.toJSON not implemented in', this );
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		console.warn( '.toJSON not implemented in', this );
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+MeshStandardNode.prototype.nodeType = 'MeshStandard';
 
 
 export { MeshStandardNode };
 export { MeshStandardNode };

+ 259 - 257
examples/jsm/nodes/materials/nodes/PhongNode.js

@@ -7,410 +7,412 @@ import { Node } from '../../core/Node.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 import { FloatNode } from '../../inputs/FloatNode.js';
 import { FloatNode } from '../../inputs/FloatNode.js';
 
 
-function PhongNode() {
+class PhongNode extends Node {
 
 
-	Node.call( this );
+	constructor() {
 
 
-	this.color = new ColorNode( 0xEEEEEE );
-	this.specular = new ColorNode( 0x111111 );
-	this.shininess = new FloatNode( 30 );
+		super();
 
 
-}
+		this.color = new ColorNode( 0xEEEEEE );
+		this.specular = new ColorNode( 0x111111 );
+		this.shininess = new FloatNode( 30 );
 
 
-PhongNode.prototype = Object.create( Node.prototype );
-PhongNode.prototype.constructor = PhongNode;
-PhongNode.prototype.nodeType = 'Phong';
+	}
 
 
-PhongNode.prototype.build = function ( builder ) {
+	build( builder ) {
 
 
-	var code;
+		let code;
 
 
-	builder.define( 'PHONG' );
+		builder.define( 'PHONG' );
 
 
-	builder.requires.lights = true;
+		builder.requires.lights = true;
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-		var position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
+			const position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
 
 
-		builder.mergeUniform( UniformsUtils.merge( [
+			builder.mergeUniform( UniformsUtils.merge( [
 
 
-			UniformsLib.fog,
-			UniformsLib.lights
+				UniformsLib.fog,
+				UniformsLib.lights
 
 
-		] ) );
+			] ) );
 
 
-		builder.addParsCode( [
-			'varying vec3 vViewPosition;',
+			builder.addParsCode( [
+				'varying vec3 vViewPosition;',
 
 
-			'#ifndef FLAT_SHADED',
+				'#ifndef FLAT_SHADED',
 
 
-			'	varying vec3 vNormal;',
+				'	varying vec3 vNormal;',
 
 
-			'#endif',
+				'#endif',
 
 
-			//"#include <encodings_pars_fragment>", // encoding functions
-			'#include <fog_pars_vertex>',
-			'#include <morphtarget_pars_vertex>',
-			'#include <skinning_pars_vertex>',
-			'#include <shadowmap_pars_vertex>',
-			'#include <logdepthbuf_pars_vertex>',
-			'#include <clipping_planes_pars_vertex>'
-		].join( '\n' ) );
+				//"#include <encodings_pars_fragment>", // encoding functions
+				'#include <fog_pars_vertex>',
+				'#include <morphtarget_pars_vertex>',
+				'#include <skinning_pars_vertex>',
+				'#include <shadowmap_pars_vertex>',
+				'#include <logdepthbuf_pars_vertex>',
+				'#include <clipping_planes_pars_vertex>'
+			].join( '\n' ) );
 
 
-		var output = [
-			'#include <beginnormal_vertex>',
-			'#include <morphnormal_vertex>',
-			'#include <skinbase_vertex>',
-			'#include <skinnormal_vertex>',
-			'#include <defaultnormal_vertex>',
+			const output = [
+				'#include <beginnormal_vertex>',
+				'#include <morphnormal_vertex>',
+				'#include <skinbase_vertex>',
+				'#include <skinnormal_vertex>',
+				'#include <defaultnormal_vertex>',
 
 
-			'#ifndef FLAT_SHADED', // normal computed with derivatives when FLAT_SHADED
+				'#ifndef FLAT_SHADED', // normal computed with derivatives when FLAT_SHADED
 
 
-			'	vNormal = normalize( transformedNormal );',
+				'	vNormal = normalize( transformedNormal );',
 
 
-			'#endif',
+				'#endif',
 
 
-			'#include <begin_vertex>'
-		];
+				'#include <begin_vertex>'
+			];
 
 
-		if ( position ) {
+			if ( position ) {
+
+				output.push(
+					position.code,
+					position.result ? 'transformed = ' + position.result + ';' : ''
+				);
+
+			}
 
 
 			output.push(
 			output.push(
-				position.code,
-				position.result ? 'transformed = ' + position.result + ';' : ''
+				'	#include <morphtarget_vertex>',
+				'	#include <skinning_vertex>',
+				'	#include <project_vertex>',
+				'	#include <fog_vertex>',
+				'	#include <logdepthbuf_vertex>',
+				'	#include <clipping_planes_vertex>',
+
+				'	vViewPosition = - mvPosition.xyz;',
+
+				'	#include <worldpos_vertex>',
+				'	#include <shadowmap_vertex>',
+				'	#include <fog_vertex>'
 			);
 			);
 
 
-		}
+			code = output.join( '\n' );
 
 
-		output.push(
-			'	#include <morphtarget_vertex>',
-			'	#include <skinning_vertex>',
-			'	#include <project_vertex>',
-			'	#include <fog_vertex>',
-			'	#include <logdepthbuf_vertex>',
-			'	#include <clipping_planes_vertex>',
+		} else {
 
 
-			'	vViewPosition = - mvPosition.xyz;',
+			// analyze all nodes to reuse generate codes
 
 
-			'	#include <worldpos_vertex>',
-			'	#include <shadowmap_vertex>',
-			'	#include <fog_vertex>'
-		);
+			if ( this.mask ) this.mask.analyze( builder );
 
 
-		code = output.join( '\n' );
+			this.color.analyze( builder, { slot: 'color' } );
+			this.specular.analyze( builder );
+			this.shininess.analyze( builder );
 
 
-	} else {
+			if ( this.alpha ) this.alpha.analyze( builder );
 
 
-		// analyze all nodes to reuse generate codes
+			if ( this.normal ) this.normal.analyze( builder );
 
 
-		if ( this.mask ) this.mask.analyze( builder );
+			if ( this.light ) this.light.analyze( builder, { cache: 'light' } );
 
 
-		this.color.analyze( builder, { slot: 'color' } );
-		this.specular.analyze( builder );
-		this.shininess.analyze( builder );
+			if ( this.ao ) this.ao.analyze( builder );
+			if ( this.ambient ) this.ambient.analyze( builder );
+			if ( this.shadow ) this.shadow.analyze( builder );
+			if ( this.emissive ) this.emissive.analyze( builder, { slot: 'emissive' } );
 
 
-		if ( this.alpha ) this.alpha.analyze( builder );
+			if ( this.environment ) this.environment.analyze( builder, { slot: 'environment' } );
+			if ( this.environmentAlpha && this.environment ) this.environmentAlpha.analyze( builder );
 
 
-		if ( this.normal ) this.normal.analyze( builder );
+			// build code
 
 
-		if ( this.light ) this.light.analyze( builder, { cache: 'light' } );
+			const mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
 
 
-		if ( this.ao ) this.ao.analyze( builder );
-		if ( this.ambient ) this.ambient.analyze( builder );
-		if ( this.shadow ) this.shadow.analyze( builder );
-		if ( this.emissive ) this.emissive.analyze( builder, { slot: 'emissive' } );
+			const color = this.color.flow( builder, 'c', { slot: 'color' } );
+			const specular = this.specular.flow( builder, 'c' );
+			const shininess = this.shininess.flow( builder, 'f' );
 
 
-		if ( this.environment ) this.environment.analyze( builder, { slot: 'environment' } );
-		if ( this.environmentAlpha && this.environment ) this.environmentAlpha.analyze( builder );
+			const alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
 
 
-		// build code
+			const normal = this.normal ? this.normal.flow( builder, 'v3' ) : undefined;
 
 
-		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
+			const light = this.light ? this.light.flow( builder, 'v3', { cache: 'light' } ) : undefined;
 
 
-		var color = this.color.flow( builder, 'c', { slot: 'color' } );
-		var specular = this.specular.flow( builder, 'c' );
-		var shininess = this.shininess.flow( builder, 'f' );
+			const ao = this.ao ? this.ao.flow( builder, 'f' ) : undefined;
+			const ambient = this.ambient ? this.ambient.flow( builder, 'c' ) : undefined;
+			const shadow = this.shadow ? this.shadow.flow( builder, 'c' ) : undefined;
+			const emissive = this.emissive ? this.emissive.flow( builder, 'c', { slot: 'emissive' } ) : undefined;
 
 
-		var alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
+			const environment = this.environment ? this.environment.flow( builder, 'c', { slot: 'environment' } ) : undefined;
+			const environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.flow( builder, 'f' ) : undefined;
 
 
-		var normal = this.normal ? this.normal.flow( builder, 'v3' ) : undefined;
+			builder.requires.transparent = alpha !== undefined;
 
 
-		var light = this.light ? this.light.flow( builder, 'v3', { cache: 'light' } ) : undefined;
+			builder.addParsCode( [
+				'#include <fog_pars_fragment>',
+				'#include <bsdfs>',
+				'#include <lights_pars_begin>',
+				'#include <lights_phong_pars_fragment>',
+				'#include <shadowmap_pars_fragment>',
+				'#include <logdepthbuf_pars_fragment>'
+			].join( '\n' ) );
 
 
-		var ao = this.ao ? this.ao.flow( builder, 'f' ) : undefined;
-		var ambient = this.ambient ? this.ambient.flow( builder, 'c' ) : undefined;
-		var shadow = this.shadow ? this.shadow.flow( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.flow( builder, 'c', { slot: 'emissive' } ) : undefined;
+			const output = [
+				// prevent undeclared normal
+				'#include <normal_fragment_begin>',
 
 
-		var environment = this.environment ? this.environment.flow( builder, 'c', { slot: 'environment' } ) : undefined;
-		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.flow( builder, 'f' ) : undefined;
+				// prevent undeclared material
+				'	BlinnPhongMaterial material;'
+			];
 
 
-		builder.requires.transparent = alpha !== undefined;
+			if ( mask ) {
 
 
-		builder.addParsCode( [
-			'#include <fog_pars_fragment>',
-			'#include <bsdfs>',
-			'#include <lights_pars_begin>',
-			'#include <lights_phong_pars_fragment>',
-			'#include <shadowmap_pars_fragment>',
-			'#include <logdepthbuf_pars_fragment>'
-		].join( '\n' ) );
+				output.push(
+					mask.code,
+					'if ( ! ' + mask.result + ' ) discard;'
+				);
 
 
-		var output = [
-			// prevent undeclared normal
-			'#include <normal_fragment_begin>',
+			}
 
 
-			// prevent undeclared material
-			'	BlinnPhongMaterial material;'
-		];
+			output.push(
+				color.code,
+				'	vec3 diffuseColor = ' + color.result + ';',
+				'	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );',
 
 
-		if ( mask ) {
+				'#include <logdepthbuf_fragment>',
 
 
-			output.push(
-				mask.code,
-				'if ( ! ' + mask.result + ' ) discard;'
-			);
+				specular.code,
+				'	vec3 specular = ' + specular.result + ';',
 
 
-		}
+				shininess.code,
+				'	float shininess = max( 0.0001, ' + shininess.result + ' );',
 
 
-		output.push(
-			color.code,
-			'	vec3 diffuseColor = ' + color.result + ';',
-			'	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );',
+				'	float specularStrength = 1.0;' // Ignored in MaterialNode ( replace to specular )
+			);
 
 
-			'#include <logdepthbuf_fragment>',
+			if ( alpha ) {
 
 
-			specular.code,
-			'	vec3 specular = ' + specular.result + ';',
+				output.push(
+					alpha.code,
+					'#ifdef ALPHATEST',
 
 
-			shininess.code,
-			'	float shininess = max( 0.0001, ' + shininess.result + ' );',
+					'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
 
 
-			'	float specularStrength = 1.0;' // Ignored in MaterialNode ( replace to specular )
-		);
+					'#endif'
+				);
 
 
-		if ( alpha ) {
+			}
 
 
-			output.push(
-				alpha.code,
-				'#ifdef ALPHATEST',
+			if ( normal ) {
 
 
-				'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
+				output.push(
+					normal.code,
+					'normal = ' + normal.result + ';'
+				);
 
 
-				'#endif'
-			);
+			}
 
 
-		}
+			// optimization for now
 
 
-		if ( normal ) {
+			output.push( 'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor' ) + ';' );
 
 
 			output.push(
 			output.push(
-				normal.code,
-				'normal = ' + normal.result + ';'
-			);
+				// accumulation
+				'material.specularColor = specular;',
+				'material.specularShininess = shininess;',
+				'material.specularStrength = specularStrength;',
 
 
-		}
-
-		// optimization for now
+				'#include <lights_fragment_begin>',
+				'#include <lights_fragment_end>'
+			);
 
 
-		output.push( 'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor' ) + ';' );
+			if ( light ) {
 
 
-		output.push(
-			// accumulation
-			'material.specularColor = specular;',
-			'material.specularShininess = shininess;',
-			'material.specularStrength = specularStrength;',
+				output.push(
+					light.code,
+					'reflectedLight.directDiffuse = ' + light.result + ';'
+				);
 
 
-			'#include <lights_fragment_begin>',
-			'#include <lights_fragment_end>'
-		);
+				// apply color
 
 
-		if ( light ) {
+				output.push(
+					'reflectedLight.directDiffuse *= diffuseColor;',
+					'reflectedLight.indirectDiffuse *= diffuseColor;'
+				);
 
 
-			output.push(
-				light.code,
-				'reflectedLight.directDiffuse = ' + light.result + ';'
-			);
+			}
 
 
-			// apply color
+			if ( ao ) {
 
 
-			output.push(
-				'reflectedLight.directDiffuse *= diffuseColor;',
-				'reflectedLight.indirectDiffuse *= diffuseColor;'
-			);
+				output.push(
+					ao.code,
+					'reflectedLight.indirectDiffuse *= ' + ao.result + ';'
+				);
 
 
-		}
+			}
 
 
-		if ( ao ) {
+			if ( ambient ) {
 
 
-			output.push(
-				ao.code,
-				'reflectedLight.indirectDiffuse *= ' + ao.result + ';'
-			);
+				output.push(
+					ambient.code,
+					'reflectedLight.indirectDiffuse += ' + ambient.result + ';'
+				);
 
 
-		}
+			}
 
 
-		if ( ambient ) {
+			if ( shadow ) {
 
 
-			output.push(
-				ambient.code,
-				'reflectedLight.indirectDiffuse += ' + ambient.result + ';'
-			);
+				output.push(
+					shadow.code,
+					'reflectedLight.directDiffuse *= ' + shadow.result + ';',
+					'reflectedLight.directSpecular *= ' + shadow.result + ';'
+				);
 
 
-		}
+			}
 
 
-		if ( shadow ) {
+			if ( emissive ) {
 
 
-			output.push(
-				shadow.code,
-				'reflectedLight.directDiffuse *= ' + shadow.result + ';',
-				'reflectedLight.directSpecular *= ' + shadow.result + ';'
-			);
+				output.push(
+					emissive.code,
+					'reflectedLight.directDiffuse += ' + emissive.result + ';'
+				);
 
 
-		}
+			}
 
 
-		if ( emissive ) {
+			output.push( 'vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular;' );
 
 
-			output.push(
-				emissive.code,
-				'reflectedLight.directDiffuse += ' + emissive.result + ';'
-			);
+			if ( environment ) {
 
 
-		}
+				output.push( environment.code );
 
 
-		output.push( 'vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular;' );
+				if ( environmentAlpha ) {
 
 
-		if ( environment ) {
+					output.push(
+						environmentAlpha.code,
+						'outgoingLight = mix( outgoingLight, ' + environment.result + ', ' + environmentAlpha.result + ' );'
+					);
 
 
-			output.push( environment.code );
+				} else {
 
 
-			if ( environmentAlpha ) {
+					output.push( 'outgoingLight = ' + environment.result + ';' );
 
 
-				output.push(
-					environmentAlpha.code,
-					'outgoingLight = mix( outgoingLight, ' + environment.result + ', ' + environmentAlpha.result + ' );'
-				);
+				}
 
 
-			} else {
+			}
+			/*
+			switch( builder.material.combine ) {
 
 
-				output.push( 'outgoingLight = ' + environment.result + ';' );
+				case ENVMAP_BLENDING_MULTIPLY:
 
 
-			}
+					//output.push( "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;" );
+					//outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );
 
 
-		}
-		/*
-		switch( builder.material.combine ) {
+					break;
 
 
-			case 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 + ' );' );
 
 
-		}
-	*/
+			} else {
 
 
-		if ( alpha ) {
+				output.push( 'gl_FragColor = vec4( outgoingLight, 1.0 );' );
 
 
-			output.push( 'gl_FragColor = vec4( outgoingLight, ' + alpha.result + ' );' );
+			}
 
 
-		} else {
+			output.push(
+				'#include <tonemapping_fragment>',
+				'#include <encodings_fragment>',
+				'#include <fog_fragment>',
+				'#include <premultiplied_alpha_fragment>'
+			);
 
 
-			output.push( 'gl_FragColor = vec4( outgoingLight, 1.0 );' );
+			code = output.join( '\n' );
 
 
 		}
 		}
 
 
-		output.push(
-			'#include <tonemapping_fragment>',
-			'#include <encodings_fragment>',
-			'#include <fog_fragment>',
-			'#include <premultiplied_alpha_fragment>'
-		);
-
-		code = output.join( '\n' );
+		return code;
 
 
 	}
 	}
 
 
-	return code;
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-PhongNode.prototype.copy = function ( source ) {
+		// vertex
 
 
-	Node.prototype.copy.call( this, source );
+		if ( source.position ) this.position = source.position;
 
 
-	// vertex
+		// fragment
 
 
-	if ( source.position ) this.position = source.position;
+		this.color = source.color;
+		this.specular = source.specular;
+		this.shininess = source.shininess;
 
 
-	// fragment
+		if ( source.mask ) this.mask = source.mask;
 
 
-	this.color = source.color;
-	this.specular = source.specular;
-	this.shininess = source.shininess;
+		if ( source.alpha ) this.alpha = source.alpha;
 
 
-	if ( source.mask ) this.mask = source.mask;
+		if ( source.normal ) this.normal = source.normal;
 
 
-	if ( source.alpha ) this.alpha = source.alpha;
+		if ( source.light ) this.light = source.light;
+		if ( source.shadow ) this.shadow = source.shadow;
 
 
-	if ( source.normal ) this.normal = source.normal;
+		if ( source.ao ) this.ao = source.ao;
 
 
-	if ( source.light ) this.light = source.light;
-	if ( source.shadow ) this.shadow = source.shadow;
+		if ( source.emissive ) this.emissive = source.emissive;
+		if ( source.ambient ) this.ambient = source.ambient;
 
 
-	if ( source.ao ) this.ao = source.ao;
+		if ( source.environment ) this.environment = source.environment;
+		if ( source.environmentAlpha ) this.environmentAlpha = source.environmentAlpha;
 
 
-	if ( source.emissive ) this.emissive = source.emissive;
-	if ( source.ambient ) this.ambient = source.ambient;
+		return this;
 
 
-	if ( source.environment ) this.environment = source.environment;
-	if ( source.environmentAlpha ) this.environmentAlpha = source.environmentAlpha;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-PhongNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			// vertex
 
 
-		data = this.createJSONNode( meta );
+			if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
 
 
-		// vertex
+			// fragment
 
 
-		if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
+			data.color = this.color.toJSON( meta ).uuid;
+			data.specular = this.specular.toJSON( meta ).uuid;
+			data.shininess = this.shininess.toJSON( meta ).uuid;
 
 
-		// fragment
+			if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
 
 
-		data.color = this.color.toJSON( meta ).uuid;
-		data.specular = this.specular.toJSON( meta ).uuid;
-		data.shininess = this.shininess.toJSON( meta ).uuid;
+			if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
-		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+			if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
 
 
-		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+			if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
 
 
-		if ( this.normal ) data.normal = this.normal.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.light ) data.light = this.light.toJSON( meta ).uuid;
+			if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
+			if ( this.environmentAlpha ) data.environmentAlpha = this.environmentAlpha.toJSON( meta ).uuid;
 
 
-		if ( this.ao ) data.ao = this.ao.toJSON( meta ).uuid;
-		if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
-		if ( this.shadow ) data.shadow = this.shadow.toJSON( meta ).uuid;
-		if ( this.emissive ) data.emissive = this.emissive.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
-		if ( this.environmentAlpha ) data.environmentAlpha = this.environmentAlpha.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+PhongNode.prototype.nodeType = 'Phong';
 
 
 export { PhongNode };
 export { PhongNode };

+ 30 - 28
examples/jsm/nodes/materials/nodes/RawNode.js

@@ -1,60 +1,62 @@
 import { Node } from '../../core/Node.js';
 import { Node } from '../../core/Node.js';
 
 
-function RawNode( value ) {
+class RawNode extends Node {
 
 
-	Node.call( this, 'v4' );
+	constructor( value ) {
 
 
-	this.value = value;
+		super( 'v4' );
 
 
-}
+		this.value = value;
 
 
-RawNode.prototype = Object.create( Node.prototype );
-RawNode.prototype.constructor = RawNode;
-RawNode.prototype.nodeType = 'Raw';
+	}
+
+	generate( builder ) {
 
 
-RawNode.prototype.generate = function ( builder ) {
+		const data = this.value.analyzeAndFlow( builder, this.type );
+		let code = data.code + '\n';
 
 
-	var data = this.value.analyzeAndFlow( builder, this.type ),
-		code = data.code + '\n';
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+			code += 'gl_Position = ' + data.result + ';';
 
 
-		code += 'gl_Position = ' + data.result + ';';
+		} else {
 
 
-	} else {
+			code += 'gl_FragColor = ' + data.result + ';';
 
 
-		code += 'gl_FragColor = ' + data.result + ';';
+		}
+
+		return code;
 
 
 	}
 	}
 
 
-	return code;
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-RawNode.prototype.copy = function ( source ) {
+		this.value = source.value;
 
 
-	Node.prototype.copy.call( this, source );
+		return this;
 
 
-	this.value = source.value;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-RawNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.value = this.value.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.value = this.value.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+RawNode.prototype.nodeType = 'Raw';
 
 
 export { RawNode };
 export { RawNode };

+ 140 - 137
examples/jsm/nodes/materials/nodes/SpriteNode.js

@@ -6,228 +6,231 @@ import {
 import { Node } from '../../core/Node.js';
 import { Node } from '../../core/Node.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 
 
-function SpriteNode() {
+class SpriteNode extends Node {
 
 
-	Node.call( this );
+	constructor() {
 
 
-	this.color = new ColorNode( 0xEEEEEE );
-	this.spherical = true;
+		super();
 
 
-}
+		this.color = new ColorNode( 0xEEEEEE );
+		this.spherical = true;
 
 
-SpriteNode.prototype = Object.create( Node.prototype );
-SpriteNode.prototype.constructor = SpriteNode;
-SpriteNode.prototype.nodeType = 'Sprite';
+	}
+
+	build( builder ) {
 
 
-SpriteNode.prototype.build = function ( builder ) {
+		let output;
 
 
-	var output;
+		builder.define( 'SPRITE' );
 
 
-	builder.define( 'SPRITE' );
+		builder.requires.lights = false;
+		builder.requires.transparent = this.alpha !== undefined;
 
 
-	builder.requires.lights = false;
-	builder.requires.transparent = this.alpha !== undefined;
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+			const position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
 
 
-		var position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
+			builder.mergeUniform( UniformsUtils.merge( [
+				UniformsLib.fog
+			] ) );
 
 
-		builder.mergeUniform( UniformsUtils.merge( [
-			UniformsLib.fog
-		] ) );
+			builder.addParsCode( [
+				'#include <fog_pars_vertex>',
+				'#include <logdepthbuf_pars_vertex>',
+				'#include <clipping_planes_pars_vertex>'
+			].join( '\n' ) );
 
 
-		builder.addParsCode( [
-			'#include <fog_pars_vertex>',
-			'#include <logdepthbuf_pars_vertex>',
-			'#include <clipping_planes_pars_vertex>'
-		].join( '\n' ) );
+			output = [
+				'#include <clipping_planes_fragment>',
+				'#include <begin_vertex>'
+			];
 
 
-		output = [
-			'#include <clipping_planes_fragment>',
-			'#include <begin_vertex>'
-		];
+			if ( position ) {
 
 
-		if ( position ) {
+				output.push(
+					position.code,
+					position.result ? 'transformed = ' + position.result + ';' : ''
+				);
+
+			}
 
 
 			output.push(
 			output.push(
-				position.code,
-				position.result ? 'transformed = ' + position.result + ';' : ''
-			);
+				'#include <project_vertex>',
+				'#include <fog_vertex>',
 
 
-		}
+				'mat4 modelViewMtx = modelViewMatrix;',
+				'mat4 modelMtx = modelMatrix;',
 
 
-		output.push(
-			'#include <project_vertex>',
-			'#include <fog_vertex>',
+				// ignore position from modelMatrix (use vary position)
+				'modelMtx[3][0] = 0.0;',
+				'modelMtx[3][1] = 0.0;',
+				'modelMtx[3][2] = 0.0;'
+			);
 
 
-			'mat4 modelViewMtx = modelViewMatrix;',
-			'mat4 modelMtx = modelMatrix;',
+			if ( ! this.spherical ) {
 
 
-			// ignore position from modelMatrix (use vary position)
-			'modelMtx[3][0] = 0.0;',
-			'modelMtx[3][1] = 0.0;',
-			'modelMtx[3][2] = 0.0;'
-		);
+				output.push(
+					'modelMtx[1][1] = 1.0;'
+				);
 
 
-		if ( ! this.spherical ) {
+			}
 
 
 			output.push(
 			output.push(
-				'modelMtx[1][1] = 1.0;'
+				// http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
+				// First colunm.
+				'modelViewMtx[0][0] = 1.0;',
+				'modelViewMtx[0][1] = 0.0;',
+				'modelViewMtx[0][2] = 0.0;'
 			);
 			);
 
 
-		}
+			if ( this.spherical ) {
 
 
-		output.push(
-			// http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
-			// First colunm.
-			'modelViewMtx[0][0] = 1.0;',
-			'modelViewMtx[0][1] = 0.0;',
-			'modelViewMtx[0][2] = 0.0;'
-		);
+				output.push(
+					// Second colunm.
+					'modelViewMtx[1][0] = 0.0;',
+					'modelViewMtx[1][1] = 1.0;',
+					'modelViewMtx[1][2] = 0.0;'
+				);
 
 
-		if ( this.spherical ) {
+			}
 
 
 			output.push(
 			output.push(
-				// Second colunm.
-				'modelViewMtx[1][0] = 0.0;',
-				'modelViewMtx[1][1] = 1.0;',
-				'modelViewMtx[1][2] = 0.0;'
-			);
-
-		}
+				// Thrid colunm.
+				'modelViewMtx[2][0] = 0.0;',
+				'modelViewMtx[2][1] = 0.0;',
+				'modelViewMtx[2][2] = 1.0;',
 
 
-		output.push(
-			// Thrid colunm.
-			'modelViewMtx[2][0] = 0.0;',
-			'modelViewMtx[2][1] = 0.0;',
-			'modelViewMtx[2][2] = 1.0;',
+				'gl_Position = projectionMatrix * modelViewMtx * modelMtx * vec4( transformed, 1.0 );',
 
 
-			'gl_Position = projectionMatrix * modelViewMtx * modelMtx * vec4( transformed, 1.0 );',
+				'#include <logdepthbuf_vertex>',
+				'#include <clipping_planes_vertex>',
+				'#include <fog_vertex>'
+			);
 
 
-			'#include <logdepthbuf_vertex>',
-			'#include <clipping_planes_vertex>',
-			'#include <fog_vertex>'
-		);
+		} else {
 
 
-	} else {
+			builder.addParsCode( [
+				'#include <fog_pars_fragment>',
+				'#include <logdepthbuf_pars_fragment>',
+				'#include <clipping_planes_pars_fragment>'
+			].join( '\n' ) );
 
 
-		builder.addParsCode( [
-			'#include <fog_pars_fragment>',
-			'#include <logdepthbuf_pars_fragment>',
-			'#include <clipping_planes_pars_fragment>'
-		].join( '\n' ) );
+			builder.addCode( [
+				'#include <clipping_planes_fragment>',
+				'#include <logdepthbuf_fragment>'
+			].join( '\n' ) );
 
 
-		builder.addCode( [
-			'#include <clipping_planes_fragment>',
-			'#include <logdepthbuf_fragment>'
-		].join( '\n' ) );
+			// analyze all nodes to reuse generate codes
 
 
-		// analyze all nodes to reuse generate codes
+			if ( this.mask ) this.mask.analyze( builder );
 
 
-		if ( this.mask ) this.mask.analyze( builder );
+			if ( this.alpha ) this.alpha.analyze( builder );
 
 
-		if ( this.alpha ) this.alpha.analyze( builder );
+			this.color.analyze( builder, { slot: 'color' } );
 
 
-		this.color.analyze( builder, { slot: 'color' } );
+			// build code
 
 
-		// build code
+			const mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined,
+				alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined,
+				color = this.color.flow( builder, 'c', { slot: 'color' } );
 
 
-		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined,
-			alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined,
-			color = this.color.flow( builder, 'c', { slot: 'color' } ),
 			output = [];
 			output = [];
 
 
-		if ( mask ) {
+			if ( mask ) {
 
 
-			output.push(
-				mask.code,
-				'if ( ! ' + mask.result + ' ) discard;'
-			);
+				output.push(
+					mask.code,
+					'if ( ! ' + mask.result + ' ) discard;'
+				);
 
 
-		}
+			}
 
 
-		if ( alpha ) {
+			if ( alpha ) {
 
 
-			output.push(
-				alpha.code,
-				'#ifdef ALPHATEST',
+				output.push(
+					alpha.code,
+					'#ifdef ALPHATEST',
 
 
-				'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
+					'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
 
 
-				'#endif',
-				color.code,
-				'gl_FragColor = vec4( ' + color.result + ', ' + alpha.result + ' );'
-			);
+					'#endif',
+					color.code,
+					'gl_FragColor = vec4( ' + color.result + ', ' + alpha.result + ' );'
+				);
 
 
-		} else {
+			} else {
+
+				output.push(
+					color.code,
+					'gl_FragColor = vec4( ' + color.result + ', 1.0 );'
+				);
+
+			}
 
 
 			output.push(
 			output.push(
-				color.code,
-				'gl_FragColor = vec4( ' + color.result + ', 1.0 );'
+				'#include <tonemapping_fragment>',
+				'#include <encodings_fragment>',
+				'#include <fog_fragment>'
 			);
 			);
 
 
 		}
 		}
 
 
-		output.push(
-			'#include <tonemapping_fragment>',
-			'#include <encodings_fragment>',
-			'#include <fog_fragment>'
-		);
+		return output.join( '\n' );
 
 
 	}
 	}
 
 
-	return output.join( '\n' );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-SpriteNode.prototype.copy = function ( source ) {
+		// vertex
 
 
-	Node.prototype.copy.call( this, source );
+		if ( source.position ) this.position = source.position;
 
 
-	// vertex
+		// fragment
 
 
-	if ( source.position ) this.position = source.position;
+		this.color = source.color;
 
 
-	// fragment
+		if ( source.spherical !== undefined ) this.spherical = source.spherical;
 
 
-	this.color = source.color;
+		if ( source.mask ) this.mask = source.mask;
 
 
-	if ( source.spherical !== undefined ) this.spherical = source.spherical;
+		if ( source.alpha ) this.alpha = source.alpha;
 
 
-	if ( source.mask ) this.mask = source.mask;
+		return this;
 
 
-	if ( source.alpha ) this.alpha = source.alpha;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-SpriteNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			// vertex
 
 
-		data = this.createJSONNode( meta );
+			if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
 
 
-		// vertex
+			// fragment
 
 
-		if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
+			data.color = this.color.toJSON( meta ).uuid;
 
 
-		// fragment
+			if ( this.spherical === false ) data.spherical = false;
 
 
-		data.color = this.color.toJSON( meta ).uuid;
+			if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
 
 
-		if ( this.spherical === false ) data.spherical = false;
+			if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
-		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+SpriteNode.prototype.nodeType = 'Sprite';
 
 
 export { SpriteNode };
 export { SpriteNode };

+ 370 - 368
examples/jsm/nodes/materials/nodes/StandardNode.js

@@ -9,595 +9,597 @@ import { ColorNode } from '../../inputs/ColorNode.js';
 import { FloatNode } from '../../inputs/FloatNode.js';
 import { FloatNode } from '../../inputs/FloatNode.js';
 import { SpecularMIPLevelNode } from '../../utils/SpecularMIPLevelNode.js';
 import { SpecularMIPLevelNode } from '../../utils/SpecularMIPLevelNode.js';
 
 
-function StandardNode() {
+class StandardNode extends Node {
 
 
-	Node.call( this );
+	constructor() {
 
 
-	this.color = new ColorNode( 0xFFFFFF );
-	this.roughness = new FloatNode( 1 );
-	this.metalness = new FloatNode( 0 );
+		super();
 
 
-}
+		this.color = new ColorNode( 0xFFFFFF );
+		this.roughness = new FloatNode( 1 );
+		this.metalness = new FloatNode( 0 );
 
 
-StandardNode.prototype = Object.create( Node.prototype );
-StandardNode.prototype.constructor = StandardNode;
-StandardNode.prototype.nodeType = 'Standard';
+	}
 
 
-StandardNode.prototype.build = function ( builder ) {
+	build( builder ) {
 
 
-	var code;
+		let code;
 
 
-	builder.define( 'STANDARD' );
+		builder.define( 'STANDARD' );
 
 
-	var useClearcoat = this.clearcoat || this.clearcoatRoughness || this.clearCoatNormal;
+		const useClearcoat = this.clearcoat || this.clearcoatRoughness || this.clearCoatNormal;
 
 
-	if ( useClearcoat ) {
+		if ( useClearcoat ) {
 
 
-		builder.define( 'CLEARCOAT' );
+			builder.define( 'CLEARCOAT' );
 
 
-	}
+		}
 
 
-	builder.requires.lights = true;
+		builder.requires.lights = true;
 
 
-	builder.extensions.derivatives = true;
-	builder.extensions.shaderTextureLOD = true;
+		builder.extensions.derivatives = true;
+		builder.extensions.shaderTextureLOD = true;
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-		var position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
+			const position = this.position ? this.position.analyzeAndFlow( builder, 'v3', { cache: 'position' } ) : undefined;
 
 
-		builder.mergeUniform( UniformsUtils.merge( [
+			builder.mergeUniform( UniformsUtils.merge( [
 
 
-			UniformsLib.fog,
-			UniformsLib.lights
+				UniformsLib.fog,
+				UniformsLib.lights
 
 
-		] ) );
+			] ) );
 
 
-		if ( UniformsLib.LTC_1 ) {
+			if ( UniformsLib.LTC_1 ) {
 
 
-			// add ltc data textures to material uniforms
+				// add ltc data textures to material uniforms
 
 
-			builder.uniforms.ltc_1 = { value: undefined };
-			builder.uniforms.ltc_2 = { value: undefined };
+				builder.uniforms.ltc_1 = { value: undefined };
+				builder.uniforms.ltc_2 = { value: undefined };
 
 
-		}
+			}
 
 
-		builder.addParsCode( [
-			'varying vec3 vViewPosition;',
+			builder.addParsCode( [
+				'varying vec3 vViewPosition;',
 
 
-			'#ifndef FLAT_SHADED',
+				'#ifndef FLAT_SHADED',
 
 
-			'	varying vec3 vNormal;',
+				'	varying vec3 vNormal;',
 
 
-			'#endif',
+				'#endif',
 
 
-			//"#include <encodings_pars_fragment>", // encoding functions
-			'#include <fog_pars_vertex>',
-			'#include <morphtarget_pars_vertex>',
-			'#include <skinning_pars_vertex>',
-			'#include <shadowmap_pars_vertex>',
-			'#include <logdepthbuf_pars_vertex>',
-			'#include <clipping_planes_pars_vertex>'
+				//"#include <encodings_pars_fragment>", // encoding functions
+				'#include <fog_pars_vertex>',
+				'#include <morphtarget_pars_vertex>',
+				'#include <skinning_pars_vertex>',
+				'#include <shadowmap_pars_vertex>',
+				'#include <logdepthbuf_pars_vertex>',
+				'#include <clipping_planes_pars_vertex>'
 
 
-		].join( '\n' ) );
+			].join( '\n' ) );
 
 
-		var output = [
-			'#include <beginnormal_vertex>',
-			'#include <morphnormal_vertex>',
-			'#include <skinbase_vertex>',
-			'#include <skinnormal_vertex>',
-			'#include <defaultnormal_vertex>',
+			const output = [
+				'#include <beginnormal_vertex>',
+				'#include <morphnormal_vertex>',
+				'#include <skinbase_vertex>',
+				'#include <skinnormal_vertex>',
+				'#include <defaultnormal_vertex>',
 
 
-			'#ifndef FLAT_SHADED', // Normal computed with derivatives when FLAT_SHADED
+				'#ifndef FLAT_SHADED', // Normal computed with derivatives when FLAT_SHADED
 
 
-			'	vNormal = normalize( transformedNormal );',
+				'	vNormal = normalize( transformedNormal );',
 
 
-			'#endif',
+				'#endif',
 
 
-			'#include <begin_vertex>'
-		];
+				'#include <begin_vertex>'
+			];
 
 
-		if ( position ) {
+			if ( position ) {
 
 
-			output.push(
-				position.code,
-				position.result ? 'transformed = ' + position.result + ';' : ''
-			);
+				output.push(
+					position.code,
+					position.result ? 'transformed = ' + position.result + ';' : ''
+				);
 
 
-		}
+			}
 
 
-		output.push(
-			'#include <morphtarget_vertex>',
-			'#include <skinning_vertex>',
-			'#include <project_vertex>',
-			'#include <fog_vertex>',
-			'#include <logdepthbuf_vertex>',
-			'#include <clipping_planes_vertex>',
+			output.push(
+				'#include <morphtarget_vertex>',
+				'#include <skinning_vertex>',
+				'#include <project_vertex>',
+				'#include <fog_vertex>',
+				'#include <logdepthbuf_vertex>',
+				'#include <clipping_planes_vertex>',
 
 
-			'	vViewPosition = - mvPosition.xyz;',
+				'	vViewPosition = - mvPosition.xyz;',
 
 
-			'#include <worldpos_vertex>',
-			'#include <shadowmap_vertex>'
-		);
+				'#include <worldpos_vertex>',
+				'#include <shadowmap_vertex>'
+			);
 
 
-		code = output.join( '\n' );
+			code = output.join( '\n' );
 
 
-	} else {
+		} else {
 
 
-		var specularRoughness = new ExpressionNode( 'material.specularRoughness', 'f' );
-		var clearcoatRoughness = new ExpressionNode( 'material.clearcoatRoughness', 'f' );
+			const specularRoughnessNode = new ExpressionNode( 'material.specularRoughness', 'f' );
+			const clearcoatRoughnessNode = new ExpressionNode( 'material.clearcoatRoughness', 'f' );
 
 
-		var contextEnvironment = {
-			roughness: specularRoughness,
-			bias: new SpecularMIPLevelNode( specularRoughness ),
-			viewNormal: new ExpressionNode( 'normal', 'v3' ),
-			worldNormal: new ExpressionNode( 'inverseTransformDirection( geometry.normal, viewMatrix )', 'v3' ),
-			gamma: true
-		};
+			const contextEnvironment = {
+				roughness: specularRoughnessNode,
+				bias: new SpecularMIPLevelNode( specularRoughnessNode ),
+				viewNormal: new ExpressionNode( 'normal', 'v3' ),
+				worldNormal: new ExpressionNode( 'inverseTransformDirection( geometry.normal, viewMatrix )', 'v3' ),
+				gamma: true
+			};
 
 
-		var contextGammaOnly = {
-			gamma: true
-		};
+			const contextGammaOnly = {
+				gamma: true
+			};
+
+			const contextClearcoatEnvironment = {
+				roughness: clearcoatRoughnessNode,
+				bias: new SpecularMIPLevelNode( clearcoatRoughnessNode ),
+				viewNormal: new ExpressionNode( 'clearcoatNormal', 'v3' ),
+				worldNormal: new ExpressionNode( 'inverseTransformDirection( geometry.clearcoatNormal, viewMatrix )', 'v3' ),
+				gamma: true
+			};
 
 
-		var contextClearcoatEnvironment = {
-			roughness: clearcoatRoughness,
-			bias: new SpecularMIPLevelNode( clearcoatRoughness ),
-			viewNormal: new ExpressionNode( 'clearcoatNormal', 'v3' ),
-			worldNormal: new ExpressionNode( 'inverseTransformDirection( geometry.clearcoatNormal, viewMatrix )', 'v3' ),
-			gamma: true
-		};
+			// analyze all nodes to reuse generate codes
 
 
-		// analyze all nodes to reuse generate codes
+			if ( this.mask ) this.mask.analyze( builder );
 
 
-		if ( this.mask ) this.mask.analyze( builder );
+			this.color.analyze( builder, { slot: 'color', context: contextGammaOnly } );
+			this.roughness.analyze( builder );
+			this.metalness.analyze( builder );
 
 
-		this.color.analyze( builder, { slot: 'color', context: contextGammaOnly } );
-		this.roughness.analyze( builder );
-		this.metalness.analyze( builder );
+			if ( this.alpha ) this.alpha.analyze( builder );
 
 
-		if ( this.alpha ) this.alpha.analyze( builder );
+			if ( this.normal ) this.normal.analyze( builder );
 
 
-		if ( this.normal ) this.normal.analyze( builder );
+			if ( this.clearcoat ) this.clearcoat.analyze( builder );
+			if ( this.clearcoatRoughness ) this.clearcoatRoughness.analyze( builder );
+			if ( this.clearcoatNormal ) this.clearcoatNormal.analyze( builder );
 
 
-		if ( this.clearcoat ) this.clearcoat.analyze( builder );
-		if ( this.clearcoatRoughness ) this.clearcoatRoughness.analyze( builder );
-		if ( this.clearcoatNormal ) this.clearcoatNormal.analyze( builder );
+			if ( this.reflectivity ) this.reflectivity.analyze( builder );
 
 
-		if ( this.reflectivity ) this.reflectivity.analyze( builder );
+			if ( this.light ) this.light.analyze( builder, { cache: 'light' } );
 
 
-		if ( this.light ) this.light.analyze( builder, { cache: 'light' } );
+			if ( this.ao ) this.ao.analyze( builder );
+			if ( this.ambient ) this.ambient.analyze( builder );
+			if ( this.shadow ) this.shadow.analyze( builder );
+			if ( this.emissive ) this.emissive.analyze( builder, { slot: 'emissive' } );
 
 
-		if ( this.ao ) this.ao.analyze( builder );
-		if ( this.ambient ) this.ambient.analyze( builder );
-		if ( this.shadow ) this.shadow.analyze( builder );
-		if ( this.emissive ) this.emissive.analyze( builder, { slot: 'emissive' } );
+			if ( this.environment ) {
 
 
-		if ( this.environment ) {
+				// isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+				// environment.analyze will detect if there is a need of calculate irradiance
 
 
-			// isolate environment from others inputs ( see TextureNode, CubeTextureNode )
-			// environment.analyze will detect if there is a need of calculate irradiance
+				this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } );
 
 
-			this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } );
+				if ( builder.requires.irradiance ) {
 
 
-			if ( builder.requires.irradiance ) {
+					this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
 
 
-				this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
+				}
 
 
 			}
 			}
 
 
-		}
+			if ( this.sheen ) this.sheen.analyze( builder );
 
 
-		if ( this.sheen ) this.sheen.analyze( builder );
+			// build code
 
 
-		// build code
+			const mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
 
 
-		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
+			const color = this.color.flow( builder, 'c', { slot: 'color', context: contextGammaOnly } );
+			const roughness = this.roughness.flow( builder, 'f' );
+			const metalness = this.metalness.flow( builder, 'f' );
 
 
-		var color = this.color.flow( builder, 'c', { slot: 'color', context: contextGammaOnly } );
-		var roughness = this.roughness.flow( builder, 'f' );
-		var metalness = this.metalness.flow( builder, 'f' );
+			const alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
 
 
-		var alpha = this.alpha ? this.alpha.flow( builder, 'f' ) : undefined;
+			const normal = this.normal ? this.normal.flow( builder, 'v3' ) : undefined;
 
 
-		var normal = this.normal ? this.normal.flow( builder, 'v3' ) : undefined;
+			const clearcoat = this.clearcoat ? this.clearcoat.flow( builder, 'f' ) : undefined;
+			const clearcoatRoughness = this.clearcoatRoughness ? this.clearcoatRoughness.flow( builder, 'f' ) : undefined;
+			const clearcoatNormal = this.clearcoatNormal ? this.clearcoatNormal.flow( builder, 'v3' ) : undefined;
 
 
-		var clearcoat = this.clearcoat ? this.clearcoat.flow( builder, 'f' ) : undefined;
-		var clearcoatRoughness = this.clearcoatRoughness ? this.clearcoatRoughness.flow( builder, 'f' ) : undefined;
-		var clearcoatNormal = this.clearcoatNormal ? this.clearcoatNormal.flow( builder, 'v3' ) : undefined;
+			const reflectivity = this.reflectivity ? this.reflectivity.flow( builder, 'f' ) : undefined;
 
 
-		var reflectivity = this.reflectivity ? this.reflectivity.flow( builder, 'f' ) : undefined;
+			const light = this.light ? this.light.flow( builder, 'v3', { cache: 'light' } ) : undefined;
 
 
-		var light = this.light ? this.light.flow( builder, 'v3', { cache: 'light' } ) : undefined;
+			const ao = this.ao ? this.ao.flow( builder, 'f' ) : undefined;
+			const ambient = this.ambient ? this.ambient.flow( builder, 'c' ) : undefined;
+			const shadow = this.shadow ? this.shadow.flow( builder, 'c' ) : undefined;
+			const emissive = this.emissive ? this.emissive.flow( builder, 'c', { slot: 'emissive' } ) : undefined;
 
 
-		var ao = this.ao ? this.ao.flow( builder, 'f' ) : undefined;
-		var ambient = this.ambient ? this.ambient.flow( builder, 'c' ) : undefined;
-		var shadow = this.shadow ? this.shadow.flow( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.flow( builder, 'c', { slot: 'emissive' } ) : undefined;
+			let environment;
 
 
-		var environment;
+			if ( this.environment ) {
 
 
-		if ( this.environment ) {
+				environment = {
+					radiance: this.environment.flow( builder, 'c', { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } )
+				};
 
 
-			environment = {
-				radiance: this.environment.flow( builder, 'c', { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } )
-			};
+				if ( builder.requires.irradiance ) {
 
 
-			if ( builder.requires.irradiance ) {
+					environment.irradiance = this.environment.flow( builder, 'c', { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
 
 
-				environment.irradiance = this.environment.flow( builder, 'c', { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
+				}
 
 
 			}
 			}
 
 
-		}
+			const clearcoatEnv = useClearcoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearcoat', context: contextClearcoatEnvironment, slot: 'environment' } ) : undefined;
 
 
-		var clearcoatEnv = useClearcoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearcoat', context: contextClearcoatEnvironment, slot: 'environment' } ) : undefined;
+			const sheen = this.sheen ? this.sheen.flow( builder, 'c' ) : undefined;
 
 
-		var sheen = this.sheen ? this.sheen.flow( builder, 'c' ) : undefined;
+			builder.requires.transparent = alpha !== undefined;
 
 
-		builder.requires.transparent = alpha !== undefined;
+			builder.addParsCode( [
+				'varying vec3 vViewPosition;',
 
 
-		builder.addParsCode( [
-			'varying vec3 vViewPosition;',
+				'#ifndef FLAT_SHADED',
 
 
-			'#ifndef FLAT_SHADED',
+				'	varying vec3 vNormal;',
 
 
-			'	varying vec3 vNormal;',
+				'#endif',
 
 
-			'#endif',
+				'#include <dithering_pars_fragment>',
+				'#include <fog_pars_fragment>',
+				'#include <bsdfs>',
+				'#include <lights_pars_begin>',
+				'#include <lights_physical_pars_fragment>',
+				'#include <shadowmap_pars_fragment>',
+				'#include <logdepthbuf_pars_fragment>'
+			].join( '\n' ) );
 
 
-			'#include <dithering_pars_fragment>',
-			'#include <fog_pars_fragment>',
-			'#include <bsdfs>',
-			'#include <lights_pars_begin>',
-			'#include <lights_physical_pars_fragment>',
-			'#include <shadowmap_pars_fragment>',
-			'#include <logdepthbuf_pars_fragment>'
-		].join( '\n' ) );
+			const output = [
+				'#include <clipping_planes_fragment>',
 
 
-		var output = [
-			'#include <clipping_planes_fragment>',
+				// add before: prevent undeclared normal
+				'	#include <normal_fragment_begin>',
+				'	#include <clearcoat_normal_fragment_begin>',
 
 
-			// add before: prevent undeclared normal
-			'	#include <normal_fragment_begin>',
-			'	#include <clearcoat_normal_fragment_begin>',
+				// add before: prevent undeclared material
+				'	PhysicalMaterial material;',
+				'	material.diffuseColor = vec3( 1.0 );'
+			];
 
 
-			// add before: prevent undeclared material
-			'	PhysicalMaterial material;',
-			'	material.diffuseColor = vec3( 1.0 );'
-		];
+			if ( mask ) {
+
+				output.push(
+					mask.code,
+					'if ( ! ' + mask.result + ' ) discard;'
+				);
 
 
-		if ( mask ) {
+			}
 
 
 			output.push(
 			output.push(
-				mask.code,
-				'if ( ! ' + mask.result + ' ) discard;'
-			);
+				color.code,
+				'	vec3 diffuseColor = ' + color.result + ';',
+				'	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );',
 
 
-		}
+				'#include <logdepthbuf_fragment>',
 
 
-		output.push(
-			color.code,
-			'	vec3 diffuseColor = ' + color.result + ';',
-			'	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );',
+				roughness.code,
+				'	float roughnessFactor = ' + roughness.result + ';',
 
 
-			'#include <logdepthbuf_fragment>',
+				metalness.code,
+				'	float metalnessFactor = ' + metalness.result + ';'
+			);
 
 
-			roughness.code,
-			'	float roughnessFactor = ' + roughness.result + ';',
+			if ( alpha ) {
 
 
-			metalness.code,
-			'	float metalnessFactor = ' + metalness.result + ';'
-		);
+				output.push(
+					alpha.code,
+					'#ifdef ALPHATEST',
 
 
-		if ( alpha ) {
+					'	if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
 
 
-			output.push(
-				alpha.code,
-				'#ifdef ALPHATEST',
+					'#endif'
+				);
 
 
-				'	if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
+			}
 
 
-				'#endif'
-			);
+			if ( normal ) {
 
 
-		}
+				output.push(
+					normal.code,
+					'normal = ' + normal.result + ';'
+				);
 
 
-		if ( normal ) {
+			}
 
 
-			output.push(
-				normal.code,
-				'normal = ' + normal.result + ';'
-			);
+			if ( clearcoatNormal ) {
 
 
-		}
+				output.push(
+					clearcoatNormal.code,
+					'clearcoatNormal = ' + clearcoatNormal.result + ';'
+				);
+
+			}
 
 
-		if ( clearcoatNormal ) {
+			// anti-aliasing code by @elalish
 
 
 			output.push(
 			output.push(
-				clearcoatNormal.code,
-				'clearcoatNormal = ' + clearcoatNormal.result + ';'
+				'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
+				'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',
 			);
 			);
 
 
-		}
-
-		// anti-aliasing code by @elalish
+			// optimization for now
 
 
-		output.push(
-			'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
-			'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',
-		);
+			output.push(
+				'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * ( 1.0 - metalnessFactor )' ) + ';',
 
 
-		// optimization for now
+				'material.specularRoughness = max( roughnessFactor, 0.0525 );',
+				'material.specularRoughness += geometryRoughness;',
+				'material.specularRoughness = min( material.specularRoughness, 1.0 );',
 
 
-		output.push(
-			'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * ( 1.0 - metalnessFactor )' ) + ';',
+				'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );'
+			);
 
 
-			'material.specularRoughness = max( roughnessFactor, 0.0525 );',
-			'material.specularRoughness += geometryRoughness;',
-			'material.specularRoughness = min( material.specularRoughness, 1.0 );',
+			if ( clearcoat ) {
 
 
-			'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );'
-		);
+				output.push(
+					clearcoat.code,
+					'material.clearcoat = saturate( ' + clearcoat.result + ' );' // Burley clearcoat model
+				);
 
 
-		if ( clearcoat ) {
+			} else if ( useClearcoat ) {
 
 
-			output.push(
-				clearcoat.code,
-				'material.clearcoat = saturate( ' + clearcoat.result + ' );' // Burley clearcoat model
-			);
+				output.push( 'material.clearcoat = 0.0;' );
 
 
-		} else if ( useClearcoat ) {
+			}
 
 
-			output.push( 'material.clearcoat = 0.0;' );
+			if ( clearcoatRoughness ) {
 
 
-		}
+				output.push(
+					clearcoatRoughness.code,
+					'material.clearcoatRoughness = max( ' + clearcoatRoughness.result + ', 0.0525 );',
+					'material.clearcoatRoughness += geometryRoughness;',
+					'material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );'
+				);
 
 
-		if ( clearcoatRoughness ) {
+			} else if ( useClearcoat ) {
 
 
-			output.push(
-				clearcoatRoughness.code,
-				'material.clearcoatRoughness = max( ' + clearcoatRoughness.result + ', 0.0525 );',
-				'material.clearcoatRoughness += geometryRoughness;',
-				'material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );'
-			);
+				output.push( 'material.clearcoatRoughness = 0.0;' );
 
 
-		} else if ( useClearcoat ) {
+			}
 
 
-			output.push( 'material.clearcoatRoughness = 0.0;' );
+			if ( sheen ) {
 
 
-		}
+				output.push( 'material.sheenColor = ' + sheen.result + ';' );
 
 
-		if ( sheen ) {
+			}
 
 
-			output.push( 'material.sheenColor = ' + sheen.result + ';' );
+			if ( reflectivity ) {
 
 
-		}
+				output.push(
+					reflectivity.code,
+					'material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( ' + reflectivity.result + ' ) ), diffuseColor, metalnessFactor );'
+				);
 
 
-		if ( reflectivity ) {
+			} else {
 
 
-			output.push(
-				reflectivity.code,
-				'material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( ' + reflectivity.result + ' ) ), diffuseColor, metalnessFactor );'
-			);
+				output.push(
+					'material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor, metalnessFactor );'
+				);
 
 
-		} else {
+			}
 
 
 			output.push(
 			output.push(
-				'material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor, metalnessFactor );'
+				'#include <lights_fragment_begin>'
 			);
 			);
 
 
-		}
-
-		output.push(
-			'#include <lights_fragment_begin>'
-		);
+			if ( light ) {
 
 
-		if ( light ) {
+				output.push(
+					light.code,
+					'reflectedLight.directDiffuse = ' + light.result + ';'
+				);
 
 
-			output.push(
-				light.code,
-				'reflectedLight.directDiffuse = ' + light.result + ';'
-			);
+				// apply color
 
 
-			// apply color
+				output.push(
+					'diffuseColor *= 1.0 - metalnessFactor;',
 
 
-			output.push(
-				'diffuseColor *= 1.0 - metalnessFactor;',
+					'reflectedLight.directDiffuse *= diffuseColor;',
+					'reflectedLight.indirectDiffuse *= diffuseColor;'
+				);
 
 
-				'reflectedLight.directDiffuse *= diffuseColor;',
-				'reflectedLight.indirectDiffuse *= diffuseColor;'
-			);
+			}
 
 
-		}
+			if ( ao ) {
 
 
-		if ( ao ) {
+				output.push(
+					ao.code,
+					'reflectedLight.indirectDiffuse *= ' + ao.result + ';',
+					'float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );',
+					'reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ' + ao.result + ', material.specularRoughness );'
+				);
 
 
-			output.push(
-				ao.code,
-				'reflectedLight.indirectDiffuse *= ' + ao.result + ';',
-				'float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );',
-				'reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ' + ao.result + ', material.specularRoughness );'
-			);
+			}
 
 
-		}
+			if ( ambient ) {
 
 
-		if ( ambient ) {
+				output.push(
+					ambient.code,
+					'reflectedLight.indirectDiffuse += ' + ambient.result + ';'
+				);
 
 
-			output.push(
-				ambient.code,
-				'reflectedLight.indirectDiffuse += ' + ambient.result + ';'
-			);
+			}
 
 
-		}
+			if ( shadow ) {
 
 
-		if ( shadow ) {
+				output.push(
+					shadow.code,
+					'reflectedLight.directDiffuse *= ' + shadow.result + ';',
+					'reflectedLight.directSpecular *= ' + shadow.result + ';'
+				);
 
 
-			output.push(
-				shadow.code,
-				'reflectedLight.directDiffuse *= ' + shadow.result + ';',
-				'reflectedLight.directSpecular *= ' + shadow.result + ';'
-			);
+			}
 
 
-		}
+			if ( emissive ) {
 
 
-		if ( emissive ) {
+				output.push(
+					emissive.code,
+					'reflectedLight.directDiffuse += ' + emissive.result + ';'
+				);
 
 
-			output.push(
-				emissive.code,
-				'reflectedLight.directDiffuse += ' + emissive.result + ';'
-			);
+			}
 
 
-		}
+			if ( environment ) {
 
 
-		if ( environment ) {
+				output.push( environment.radiance.code );
 
 
-			output.push( environment.radiance.code );
+				if ( builder.requires.irradiance ) {
 
 
-			if ( builder.requires.irradiance ) {
+					output.push( environment.irradiance.code );
 
 
-				output.push( environment.irradiance.code );
+				}
 
 
-			}
+				if ( clearcoatEnv ) {
 
 
-			if ( clearcoatEnv ) {
+					output.push(
+						clearcoatEnv.code,
+						'clearcoatRadiance += ' + clearcoatEnv.result + ';'
+					);
 
 
-				output.push(
-					clearcoatEnv.code,
-					'clearcoatRadiance += ' + clearcoatEnv.result + ';'
-				);
+				}
 
 
-			}
+				output.push( 'radiance += ' + environment.radiance.result + ';' );
 
 
-			output.push( 'radiance += ' + environment.radiance.result + ';' );
+				if ( builder.requires.irradiance ) {
 
 
-			if ( builder.requires.irradiance ) {
+					output.push( 'iblIrradiance += PI * ' + environment.irradiance.result + ';' );
 
 
-				output.push( 'iblIrradiance += PI * ' + environment.irradiance.result + ';' );
+				}
 
 
 			}
 			}
 
 
-		}
+			output.push(
+				'#include <lights_fragment_end>'
+			);
 
 
-		output.push(
-			'#include <lights_fragment_end>'
-		);
+			output.push( 'vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;' );
 
 
-		output.push( 'vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;' );
+			if ( alpha ) {
 
 
-		if ( alpha ) {
+				output.push( 'gl_FragColor = vec4( outgoingLight, ' + alpha.result + ' );' );
 
 
-			output.push( 'gl_FragColor = vec4( outgoingLight, ' + alpha.result + ' );' );
+			} else {
 
 
-		} else {
+				output.push( 'gl_FragColor = vec4( outgoingLight, 1.0 );' );
 
 
-			output.push( 'gl_FragColor = vec4( outgoingLight, 1.0 );' );
+			}
 
 
-		}
+			output.push(
+				'#include <tonemapping_fragment>',
+				'#include <encodings_fragment>',
+				'#include <fog_fragment>',
+				'#include <premultiplied_alpha_fragment>',
+				'#include <dithering_fragment>'
+			);
 
 
-		output.push(
-			'#include <tonemapping_fragment>',
-			'#include <encodings_fragment>',
-			'#include <fog_fragment>',
-			'#include <premultiplied_alpha_fragment>',
-			'#include <dithering_fragment>'
-		);
+			code = output.join( '\n' );
+
+		}
 
 
-		code = output.join( '\n' );
+		return code;
 
 
 	}
 	}
 
 
-	return code;
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-StandardNode.prototype.copy = function ( source ) {
+		// vertex
 
 
-	Node.prototype.copy.call( this, source );
+		if ( source.position ) this.position = source.position;
 
 
-	// vertex
+		// fragment
 
 
-	if ( source.position ) this.position = source.position;
+		this.color = source.color;
+		this.roughness = source.roughness;
+		this.metalness = source.metalness;
 
 
-	// fragment
+		if ( source.mask ) this.mask = source.mask;
 
 
-	this.color = source.color;
-	this.roughness = source.roughness;
-	this.metalness = source.metalness;
+		if ( source.alpha ) this.alpha = source.alpha;
 
 
-	if ( source.mask ) this.mask = source.mask;
+		if ( source.normal ) this.normal = source.normal;
 
 
-	if ( source.alpha ) this.alpha = source.alpha;
+		if ( source.clearcoat ) this.clearcoat = source.clearcoat;
+		if ( source.clearcoatRoughness ) this.clearcoatRoughness = source.clearcoatRoughness;
+		if ( source.clearcoatNormal ) this.clearcoatNormal = source.clearcoatNormal;
 
 
-	if ( source.normal ) this.normal = source.normal;
+		if ( source.reflectivity ) this.reflectivity = source.reflectivity;
 
 
-	if ( source.clearcoat ) this.clearcoat = source.clearcoat;
-	if ( source.clearcoatRoughness ) this.clearcoatRoughness = source.clearcoatRoughness;
-	if ( source.clearcoatNormal ) this.clearcoatNormal = source.clearcoatNormal;
+		if ( source.light ) this.light = source.light;
+		if ( source.shadow ) this.shadow = source.shadow;
 
 
-	if ( source.reflectivity ) this.reflectivity = source.reflectivity;
+		if ( source.ao ) this.ao = source.ao;
 
 
-	if ( source.light ) this.light = source.light;
-	if ( source.shadow ) this.shadow = source.shadow;
+		if ( source.emissive ) this.emissive = source.emissive;
+		if ( source.ambient ) this.ambient = source.ambient;
 
 
-	if ( source.ao ) this.ao = source.ao;
+		if ( source.environment ) this.environment = source.environment;
 
 
-	if ( source.emissive ) this.emissive = source.emissive;
-	if ( source.ambient ) this.ambient = source.ambient;
+		if ( source.sheen ) this.sheen = source.sheen;
 
 
-	if ( source.environment ) this.environment = source.environment;
+		return this;
 
 
-	if ( source.sheen ) this.sheen = source.sheen;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-StandardNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			// vertex
 
 
-		data = this.createJSONNode( meta );
+			if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
 
 
-		// vertex
+			// fragment
 
 
-		if ( this.position ) data.position = this.position.toJSON( meta ).uuid;
+			data.color = this.color.toJSON( meta ).uuid;
+			data.roughness = this.roughness.toJSON( meta ).uuid;
+			data.metalness = this.metalness.toJSON( meta ).uuid;
 
 
-		// fragment
+			if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
 
 
-		data.color = this.color.toJSON( meta ).uuid;
-		data.roughness = this.roughness.toJSON( meta ).uuid;
-		data.metalness = this.metalness.toJSON( meta ).uuid;
+			if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
-		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+			if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
 
 
-		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
+			if ( this.clearcoat ) data.clearcoat = this.clearcoat.toJSON( meta ).uuid;
+			if ( this.clearcoatRoughness ) data.clearcoatRoughness = this.clearcoatRoughness.toJSON( meta ).uuid;
+			if ( this.clearcoatNormal ) data.clearcoatNormal = this.clearcoatNormal.toJSON( meta ).uuid;
 
 
-		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
+			if ( this.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
 
 
-		if ( this.clearcoat ) data.clearcoat = this.clearcoat.toJSON( meta ).uuid;
-		if ( this.clearcoatRoughness ) data.clearcoatRoughness = this.clearcoatRoughness.toJSON( meta ).uuid;
-		if ( this.clearcoatNormal ) data.clearcoatNormal = this.clearcoatNormal.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.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
+			if ( this.ao ) data.ao = this.ao.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.emissive ) data.emissive = this.emissive.toJSON( meta ).uuid;
+			if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
 
 
-		if ( this.ao ) data.ao = this.ao.toJSON( meta ).uuid;
+			if ( this.environment ) data.environment = this.environment.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.sheen ) data.sheen = this.sheen.toJSON( meta ).uuid;
 
 
-		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.sheen ) data.sheen = this.sheen.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+StandardNode.prototype.nodeType = 'Standard';
 
 
 export { StandardNode };
 export { StandardNode };

+ 70 - 67
examples/jsm/nodes/math/CondNode.js

@@ -1,126 +1,129 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function CondNode( a, b, op, ifNode, elseNode ) {
+class CondNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( a, b, op, ifNode, elseNode ) {
 
 
-	this.a = a;
-	this.b = b;
+		super();
 
 
-	this.op = op;
+		this.a = a;
+		this.b = b;
 
 
-	this.ifNode = ifNode;
-	this.elseNode = elseNode;
+		this.op = op;
 
 
-}
+		this.ifNode = ifNode;
+		this.elseNode = elseNode;
 
 
-CondNode.EQUAL = '==';
-CondNode.NOT_EQUAL = '!=';
-CondNode.GREATER = '>';
-CondNode.GREATER_EQUAL = '>=';
-CondNode.LESS = '<';
-CondNode.LESS_EQUAL = '<=';
-CondNode.AND = '&&';
-CondNode.OR = '||';
+	}
 
 
-CondNode.prototype = Object.create( TempNode.prototype );
-CondNode.prototype.constructor = CondNode;
-CondNode.prototype.nodeType = 'Cond';
+	getType( builder ) {
 
 
-CondNode.prototype.getType = function ( builder ) {
+		if ( this.ifNode ) {
 
 
-	if ( this.ifNode ) {
+			const ifType = this.ifNode.getType( builder );
+			const elseType = this.elseNode.getType( builder );
 
 
-		var ifType = this.ifNode.getType( builder );
-		var elseType = this.elseNode.getType( builder );
+			if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) {
 
 
-		if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) {
+				return elseType;
 
 
-			return elseType;
+			}
+
+			return ifType;
 
 
 		}
 		}
 
 
-		return ifType;
+		return 'b';
 
 
 	}
 	}
 
 
-	return 'b';
+	getCondType( builder ) {
 
 
-};
+		if ( builder.getTypeLength( this.b.getType( builder ) ) > builder.getTypeLength( this.a.getType( builder ) ) ) {
 
 
-CondNode.prototype.getCondType = function ( builder ) {
+			return this.b.getType( builder );
 
 
-	if ( builder.getTypeLength( this.b.getType( builder ) ) > builder.getTypeLength( this.a.getType( builder ) ) ) {
+		}
 
 
-		return this.b.getType( builder );
+		return this.a.getType( builder );
 
 
 	}
 	}
 
 
-	return this.a.getType( builder );
+	generate( builder, output ) {
+
+		const type = this.getType( builder ),
+			condType = this.getCondType( builder ),
+			a = this.a.build( builder, condType ),
+			b = this.b.build( builder, condType );
 
 
-};
+		let code;
 
 
-CondNode.prototype.generate = function ( builder, output ) {
+		if ( this.ifNode ) {
 
 
-	var type = this.getType( builder ),
-		condType = this.getCondType( builder ),
-		a = this.a.build( builder, condType ),
-		b = this.b.build( builder, condType ),
-		code;
+			const ifCode = this.ifNode.build( builder, type ),
+				elseCode = this.elseNode.build( builder, type );
 
 
-	if ( this.ifNode ) {
+			code = '( ' + [ a, this.op, b, '?', ifCode, ':', elseCode ].join( ' ' ) + ' )';
 
 
-		var ifCode = this.ifNode.build( builder, type ),
-			elseCode = this.elseNode.build( builder, type );
+		} else {
 
 
-		code = '( ' + [ a, this.op, b, '?', ifCode, ':', elseCode ].join( ' ' ) + ' )';
+			code = '( ' + a + ' ' + this.op + ' ' + b + ' )';
 
 
-	} else {
+		}
 
 
-		code = '( ' + a + ' ' + this.op + ' ' + b + ' )';
+		return builder.format( code, this.getType( builder ), output );
 
 
 	}
 	}
 
 
-	return builder.format( code, this.getType( builder ), output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-CondNode.prototype.copy = function ( source ) {
+		this.a = source.a;
+		this.b = source.b;
 
 
-	TempNode.prototype.copy.call( this, source );
+		this.op = source.op;
 
 
-	this.a = source.a;
-	this.b = source.b;
+		this.ifNode = source.ifNode;
+		this.elseNode = source.elseNode;
 
 
-	this.op = source.op;
+		return this;
 
 
-	this.ifNode = source.ifNode;
-	this.elseNode = source.elseNode;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-CondNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.a = this.a.toJSON( meta ).uuid;
+			data.b = this.b.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+			data.op = this.op;
 
 
-		data.a = this.a.toJSON( meta ).uuid;
-		data.b = this.b.toJSON( meta ).uuid;
+			if ( data.ifNode ) data.ifNode = this.ifNode.toJSON( meta ).uuid;
+			if ( data.elseNode ) data.elseNode = this.elseNode.toJSON( meta ).uuid;
 
 
-		data.op = this.op;
+		}
 
 
-		if ( data.ifNode ) data.ifNode = this.ifNode.toJSON( meta ).uuid;
-		if ( data.elseNode ) data.elseNode = this.elseNode.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
+
+CondNode.EQUAL = '==';
+CondNode.NOT_EQUAL = '!=';
+CondNode.GREATER = '>';
+CondNode.GREATER_EQUAL = '>=';
+CondNode.LESS = '<';
+CondNode.LESS_EQUAL = '<=';
+CondNode.AND = '&&';
+CondNode.OR = '||';
 
 
-};
+CondNode.prototype.nodeType = 'Cond';
 
 
 export { CondNode };
 export { CondNode };

+ 173 - 171
examples/jsm/nodes/math/MathNode.js

@@ -1,267 +1,269 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function MathNode( a, bOrMethod, cOrMethod, method ) {
+class MathNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( a, bOrMethod, cOrMethod, method ) {
 
 
-	this.a = a;
-	typeof bOrMethod !== 'string' ? this.b = bOrMethod : method = bOrMethod;
-	typeof cOrMethod !== 'string' ? this.c = cOrMethod : method = cOrMethod;
+		super();
 
 
-	this.method = method;
+		this.a = a;
+		typeof bOrMethod !== 'string' ? this.b = bOrMethod : method = bOrMethod;
+		typeof cOrMethod !== 'string' ? this.c = cOrMethod : method = cOrMethod;
 
 
-}
+		this.method = method;
 
 
-// 1 input
+	}
 
 
-MathNode.RAD = 'radians';
-MathNode.DEG = 'degrees';
-MathNode.EXP = 'exp';
-MathNode.EXP2 = 'exp2';
-MathNode.LOG = 'log';
-MathNode.LOG2 = 'log2';
-MathNode.SQRT = 'sqrt';
-MathNode.INV_SQRT = 'inversesqrt';
-MathNode.FLOOR = 'floor';
-MathNode.CEIL = 'ceil';
-MathNode.NORMALIZE = 'normalize';
-MathNode.FRACT = 'fract';
-MathNode.SATURATE = 'saturate';
-MathNode.SIN = 'sin';
-MathNode.COS = 'cos';
-MathNode.TAN = 'tan';
-MathNode.ASIN = 'asin';
-MathNode.ACOS = 'acos';
-MathNode.ARCTAN = 'atan';
-MathNode.ABS = 'abs';
-MathNode.SIGN = 'sign';
-MathNode.LENGTH = 'length';
-MathNode.NEGATE = 'negate';
-MathNode.INVERT = 'invert';
+	getNumInputs( /*builder*/ ) {
 
 
-// 2 inputs
+		switch ( this.method ) {
 
 
-MathNode.MIN = 'min';
-MathNode.MAX = 'max';
-MathNode.MOD = 'mod';
-MathNode.STEP = 'step';
-MathNode.REFLECT = 'reflect';
-MathNode.DISTANCE = 'distance';
-MathNode.DOT = 'dot';
-MathNode.CROSS = 'cross';
-MathNode.POW = 'pow';
+			case MathNode.MIX:
+			case MathNode.CLAMP:
+			case MathNode.REFRACT:
+			case MathNode.SMOOTHSTEP:
+			case MathNode.FACEFORWARD:
 
 
-// 3 inputs
+				return 3;
 
 
-MathNode.MIX = 'mix';
-MathNode.CLAMP = 'clamp';
-MathNode.REFRACT = 'refract';
-MathNode.SMOOTHSTEP = 'smoothstep';
-MathNode.FACEFORWARD = 'faceforward';
+			case MathNode.MIN:
+			case MathNode.MAX:
+			case MathNode.MOD:
+			case MathNode.STEP:
+			case MathNode.REFLECT:
+			case MathNode.DISTANCE:
+			case MathNode.DOT:
+			case MathNode.CROSS:
+			case MathNode.POW:
 
 
-MathNode.prototype = Object.create( TempNode.prototype );
-MathNode.prototype.constructor = MathNode;
-MathNode.prototype.nodeType = 'Math';
-MathNode.prototype.hashProperties = [ 'method' ];
+				return 2;
 
 
-MathNode.prototype.getNumInputs = function ( /*builder*/ ) {
+			default:
 
 
-	switch ( this.method ) {
+				return 1;
 
 
-		case MathNode.MIX:
-		case MathNode.CLAMP:
-		case MathNode.REFRACT:
-		case MathNode.SMOOTHSTEP:
-		case MathNode.FACEFORWARD:
+		}
 
 
-			return 3;
+	}
 
 
-		case MathNode.MIN:
-		case MathNode.MAX:
-		case MathNode.MOD:
-		case MathNode.STEP:
-		case MathNode.REFLECT:
-		case MathNode.DISTANCE:
-		case MathNode.DOT:
-		case MathNode.CROSS:
-		case MathNode.POW:
+	getInputType( builder ) {
 
 
-			return 2;
+		const a = builder.getTypeLength( this.a.getType( builder ) );
+		const b = this.b ? builder.getTypeLength( this.b.getType( builder ) ) : 0;
+		const c = this.c ? builder.getTypeLength( this.c.getType( builder ) ) : 0;
 
 
-		default:
+		if ( a > b && a > c ) {
 
 
-			return 1;
+			return this.a.getType( builder );
 
 
-	}
+		} else if ( b > c ) {
 
 
-};
+			return this.b.getType( builder );
 
 
-MathNode.prototype.getInputType = function ( builder ) {
+		}
 
 
-	var a = builder.getTypeLength( this.a.getType( builder ) );
-	var b = this.b ? builder.getTypeLength( this.b.getType( builder ) ) : 0;
-	var c = this.c ? builder.getTypeLength( this.c.getType( builder ) ) : 0;
+		return this.c.getType( builder );
 
 
-	if ( a > b && a > c ) {
+	}
 
 
-		return this.a.getType( builder );
+	getType( builder ) {
 
 
-	} else if ( b > c ) {
+		switch ( this.method ) {
 
 
-		return this.b.getType( builder );
+			case MathNode.LENGTH:
+			case MathNode.DISTANCE:
+			case MathNode.DOT:
 
 
-	}
+				return 'f';
 
 
-	return this.c.getType( builder );
+			case MathNode.CROSS:
 
 
-};
+				return 'v3';
 
 
-MathNode.prototype.getType = function ( builder ) {
+		}
 
 
-	switch ( this.method ) {
+		return this.getInputType( builder );
 
 
-		case MathNode.LENGTH:
-		case MathNode.DISTANCE:
-		case MathNode.DOT:
+	}
 
 
-			return 'f';
+	generate( builder, output ) {
 
 
-		case MathNode.CROSS:
+		let a, b, c;
+		const al = this.a ? builder.getTypeLength( this.a.getType( builder ) ) : 0,
+			bl = this.b ? builder.getTypeLength( this.b.getType( builder ) ) : 0,
+			cl = this.c ? builder.getTypeLength( this.c.getType( builder ) ) : 0,
+			inputType = this.getInputType( builder ),
+			nodeType = this.getType( builder );
 
 
-			return 'v3';
+		switch ( this.method ) {
 
 
-	}
+			// 1 input
 
 
-	return this.getInputType( builder );
+			case MathNode.NEGATE:
 
 
-};
+				return builder.format( '( -' + this.a.build( builder, inputType ) + ' )', inputType, output );
 
 
-MathNode.prototype.generate = function ( builder, output ) {
+			case MathNode.INVERT:
 
 
-	var a, b, c,
-		al = this.a ? builder.getTypeLength( this.a.getType( builder ) ) : 0,
-		bl = this.b ? builder.getTypeLength( this.b.getType( builder ) ) : 0,
-		cl = this.c ? builder.getTypeLength( this.c.getType( builder ) ) : 0,
-		inputType = this.getInputType( builder ),
-		nodeType = this.getType( builder );
+				return builder.format( '( 1.0 - ' + this.a.build( builder, inputType ) + ' )', inputType, output );
 
 
-	switch ( this.method ) {
+				// 2 inputs
 
 
-		// 1 input
+			case MathNode.CROSS:
 
 
-		case MathNode.NEGATE:
+				a = this.a.build( builder, 'v3' );
+				b = this.b.build( builder, 'v3' );
 
 
-			return builder.format( '( -' + this.a.build( builder, inputType ) + ' )', inputType, output );
+				break;
 
 
-		case MathNode.INVERT:
+			case MathNode.STEP:
 
 
-			return builder.format( '( 1.0 - ' + this.a.build( builder, inputType ) + ' )', inputType, output );
+				a = this.a.build( builder, al === 1 ? 'f' : inputType );
+				b = this.b.build( builder, inputType );
 
 
-			// 2 inputs
+				break;
 
 
-		case MathNode.CROSS:
+			case MathNode.MIN:
+			case MathNode.MAX:
+			case MathNode.MOD:
 
 
-			a = this.a.build( builder, 'v3' );
-			b = this.b.build( builder, 'v3' );
+				a = this.a.build( builder, inputType );
+				b = this.b.build( builder, bl === 1 ? 'f' : inputType );
 
 
-			break;
+				break;
 
 
-		case MathNode.STEP:
+				// 3 inputs
 
 
-			a = this.a.build( builder, al === 1 ? 'f' : inputType );
-			b = this.b.build( builder, inputType );
+			case MathNode.REFRACT:
 
 
-			break;
+				a = this.a.build( builder, inputType );
+				b = this.b.build( builder, inputType );
+				c = this.c.build( builder, 'f' );
 
 
-		case MathNode.MIN:
-		case MathNode.MAX:
-		case MathNode.MOD:
+				break;
 
 
-			a = this.a.build( builder, inputType );
-			b = this.b.build( builder, bl === 1 ? 'f' : inputType );
+			case MathNode.MIX:
 
 
-			break;
+				a = this.a.build( builder, inputType );
+				b = this.b.build( builder, inputType );
+				c = this.c.build( builder, cl === 1 ? 'f' : inputType );
 
 
-			// 3 inputs
+				break;
 
 
-		case MathNode.REFRACT:
+				// default
 
 
-			a = this.a.build( builder, inputType );
-			b = this.b.build( builder, inputType );
-			c = this.c.build( builder, 'f' );
+			default:
 
 
-			break;
+				a = this.a.build( builder, inputType );
+				if ( this.b ) b = this.b.build( builder, inputType );
+				if ( this.c ) c = this.c.build( builder, inputType );
 
 
-		case MathNode.MIX:
+				break;
 
 
-			a = this.a.build( builder, inputType );
-			b = this.b.build( builder, inputType );
-			c = this.c.build( builder, cl === 1 ? 'f' : inputType );
+		}
 
 
-			break;
+		// build function call
 
 
-			// default
+		const params = [];
+		params.push( a );
+		if ( b ) params.push( b );
+		if ( c ) params.push( c );
 
 
-		default:
+		const numInputs = this.getNumInputs( builder );
 
 
-			a = this.a.build( builder, inputType );
-			if ( this.b ) b = this.b.build( builder, inputType );
-			if ( this.c ) c = this.c.build( builder, inputType );
+		if ( params.length !== numInputs ) {
 
 
-			break;
+			throw Error( `Arguments not match used in "${this.method}". Require ${numInputs}, currently ${params.length}.` );
 
 
-	}
+		}
+
+		return builder.format( this.method + '( ' + params.join( ', ' ) + ' )', nodeType, output );
 
 
-	// build function call
+	}
 
 
-	var params = [];
-	params.push( a );
-	if ( b ) params.push( b );
-	if ( c ) params.push( c );
+	copy( source ) {
 
 
-	var numInputs = this.getNumInputs( builder );
+		super.copy( source );
 
 
-	if ( params.length !== numInputs ) {
+		this.a = source.a;
+		this.b = source.b;
+		this.c = source.c;
+		this.method = source.method;
 
 
-		throw Error( `Arguments not match used in "${this.method}". Require ${numInputs}, currently ${params.length}.` );
+		return this;
 
 
 	}
 	}
 
 
-	return builder.format( this.method + '( ' + params.join( ', ' ) + ' )', nodeType, output );
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-MathNode.prototype.copy = function ( source ) {
+		if ( ! data ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+			data = this.createJSONNode( meta );
 
 
-	this.a = source.a;
-	this.b = source.b;
-	this.c = source.c;
-	this.method = source.method;
+			data.a = this.a.toJSON( meta ).uuid;
+			if ( this.b ) data.b = this.b.toJSON( meta ).uuid;
+			if ( this.c ) data.c = this.c.toJSON( meta ).uuid;
 
 
-	return this;
+			data.method = this.method;
 
 
-};
+		}
 
 
-MathNode.prototype.toJSON = function ( meta ) {
+		return data;
 
 
-	var data = this.getJSONNode( meta );
+	}
 
 
-	if ( ! data ) {
+}
+
+// 1 input
 
 
-		data = this.createJSONNode( meta );
+MathNode.RAD = 'radians';
+MathNode.DEG = 'degrees';
+MathNode.EXP = 'exp';
+MathNode.EXP2 = 'exp2';
+MathNode.LOG = 'log';
+MathNode.LOG2 = 'log2';
+MathNode.SQRT = 'sqrt';
+MathNode.INV_SQRT = 'inversesqrt';
+MathNode.FLOOR = 'floor';
+MathNode.CEIL = 'ceil';
+MathNode.NORMALIZE = 'normalize';
+MathNode.FRACT = 'fract';
+MathNode.SATURATE = 'saturate';
+MathNode.SIN = 'sin';
+MathNode.COS = 'cos';
+MathNode.TAN = 'tan';
+MathNode.ASIN = 'asin';
+MathNode.ACOS = 'acos';
+MathNode.ARCTAN = 'atan';
+MathNode.ABS = 'abs';
+MathNode.SIGN = 'sign';
+MathNode.LENGTH = 'length';
+MathNode.NEGATE = 'negate';
+MathNode.INVERT = 'invert';
 
 
-		data.a = this.a.toJSON( meta ).uuid;
-		if ( this.b ) data.b = this.b.toJSON( meta ).uuid;
-		if ( this.c ) data.c = this.c.toJSON( meta ).uuid;
+// 2 inputs
 
 
-		data.method = this.method;
+MathNode.MIN = 'min';
+MathNode.MAX = 'max';
+MathNode.MOD = 'mod';
+MathNode.STEP = 'step';
+MathNode.REFLECT = 'reflect';
+MathNode.DISTANCE = 'distance';
+MathNode.DOT = 'dot';
+MathNode.CROSS = 'cross';
+MathNode.POW = 'pow';
 
 
-	}
+// 3 inputs
 
 
-	return data;
+MathNode.MIX = 'mix';
+MathNode.CLAMP = 'clamp';
+MathNode.REFRACT = 'refract';
+MathNode.SMOOTHSTEP = 'smoothstep';
+MathNode.FACEFORWARD = 'faceforward';
 
 
-};
+MathNode.prototype.nodeType = 'Math';
+MathNode.prototype.hashProperties = [ 'method' ];
 
 
 export { MathNode };
 export { MathNode };

+ 47 - 45
examples/jsm/nodes/math/OperatorNode.js

@@ -1,84 +1,86 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function OperatorNode( a, b, op ) {
+class OperatorNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( a, b, op ) {
 
 
-	this.a = a;
-	this.b = b;
-	this.op = op;
+		super();
 
 
-}
+		this.a = a;
+		this.b = b;
+		this.op = op;
 
 
-OperatorNode.ADD = '+';
-OperatorNode.SUB = '-';
-OperatorNode.MUL = '*';
-OperatorNode.DIV = '/';
+	}
 
 
-OperatorNode.prototype = Object.create( TempNode.prototype );
-OperatorNode.prototype.constructor = OperatorNode;
-OperatorNode.prototype.nodeType = 'Operator';
+	getType( builder ) {
 
 
-OperatorNode.prototype.getType = function ( builder ) {
+		const a = this.a.getType( builder ),
+			b = this.b.getType( builder );
 
 
-	var a = this.a.getType( builder ),
-		b = this.b.getType( builder );
+		if ( builder.isTypeMatrix( a ) ) {
 
 
-	if ( builder.isTypeMatrix( a ) ) {
+			return 'v4';
 
 
-		return 'v4';
+		} else if ( builder.getTypeLength( b ) > builder.getTypeLength( a ) ) {
 
 
-	} else if ( builder.getTypeLength( b ) > builder.getTypeLength( a ) ) {
+			// use the greater length vector
 
 
-		// use the greater length vector
+			return b;
 
 
-		return b;
+		}
+
+		return a;
 
 
 	}
 	}
 
 
-	return a;
+	generate( builder, output ) {
 
 
-};
+		const type = this.getType( builder );
 
 
-OperatorNode.prototype.generate = function ( builder, output ) {
+		const a = this.a.build( builder, type ),
+			b = this.b.build( builder, type );
 
 
-	var type = this.getType( builder );
+		return builder.format( '( ' + a + ' ' + this.op + ' ' + b + ' )', type, output );
 
 
-	var a = this.a.build( builder, type ),
-		b = this.b.build( builder, type );
+	}
 
 
-	return builder.format( '( ' + a + ' ' + this.op + ' ' + b + ' )', type, output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-OperatorNode.prototype.copy = function ( source ) {
+		this.a = source.a;
+		this.b = source.b;
+		this.op = source.op;
 
 
-	TempNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.a = source.a;
-	this.b = source.b;
-	this.op = source.op;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-OperatorNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.a = this.a.toJSON( meta ).uuid;
+			data.b = this.b.toJSON( meta ).uuid;
+			data.op = this.op;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.a = this.a.toJSON( meta ).uuid;
-		data.b = this.b.toJSON( meta ).uuid;
-		data.op = this.op;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
+
+OperatorNode.ADD = '+';
+OperatorNode.SUB = '-';
+OperatorNode.MUL = '*';
+OperatorNode.DIV = '/';
 
 
-};
+OperatorNode.prototype.nodeType = 'Operator';
 
 
 export { OperatorNode };
 export { OperatorNode };

+ 80 - 78
examples/jsm/nodes/misc/BumpMapNode.js

@@ -4,20 +4,92 @@ import { FunctionNode } from '../core/FunctionNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 
 
-function BumpMapNode( value, scale ) {
+class BumpMapNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( value, scale ) {
 
 
-	this.value = value;
-	this.scale = scale || new FloatNode( 1 );
+		super( 'v3' );
 
 
-	this.toNormalMap = false;
+		this.value = value;
+		this.scale = scale || new FloatNode( 1 );
+
+		this.toNormalMap = false;
+
+	}
+
+	generate( builder, output ) {
+
+		if ( builder.isShader( 'fragment' ) ) {
+
+			if ( this.toNormalMap ) {
+
+				const 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 {
+
+				const derivativeHeight = builder.include( BumpMapNode.Nodes.dHdxy_fwd ),
+					perturbNormalArb = builder.include( BumpMapNode.Nodes.perturbNormalArb );
+
+				this.normal = this.normal || new NormalNode();
+				this.position = this.position || new PositionNode( PositionNode.VIEW );
+
+				const 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 );
+
+		}
+
+	}
+
+	copy( source ) {
+
+		super.copy( source );
+
+		this.value = source.value;
+		this.scale = source.scale;
+
+		return this;
+
+	}
+
+	toJSON( meta ) {
+
+		let 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;
+
+	}
 
 
 }
 }
 
 
 BumpMapNode.Nodes = ( function () {
 BumpMapNode.Nodes = ( function () {
 
 
-	var dHdxy_fwd = new FunctionNode( [
+	const dHdxy_fwd = new FunctionNode( [
 
 
 		// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
 		// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
 		// http://api.unrealengine.com/attachments/Engine/Rendering/LightingAndShadows/BumpMappingWithoutTangentSpace/mm_sfgrad_bump.pdf
 		// http://api.unrealengine.com/attachments/Engine/Rendering/LightingAndShadows/BumpMappingWithoutTangentSpace/mm_sfgrad_bump.pdf
@@ -41,7 +113,7 @@ BumpMapNode.Nodes = ( function () {
 
 
 	].join( '\n' ), null, { derivatives: true } );
 	].join( '\n' ), null, { derivatives: true } );
 
 
-	var perturbNormalArb = new FunctionNode( [
+	const perturbNormalArb = new FunctionNode( [
 
 
 		'vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {',
 		'vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {',
 
 
@@ -66,7 +138,7 @@ BumpMapNode.Nodes = ( function () {
 
 
 	].join( '\n' ), [ dHdxy_fwd ], { derivatives: true } );
 	].join( '\n' ), [ dHdxy_fwd ], { derivatives: true } );
 
 
-	var bumpToNormal = new FunctionNode( [
+	const bumpToNormal = new FunctionNode( [
 		'vec3 bumpToNormal( sampler2D bumpMap, vec2 uv, float scale ) {',
 		'vec3 bumpToNormal( sampler2D bumpMap, vec2 uv, float scale ) {',
 
 
 		'	vec2 dSTdx = dFdx( uv );',
 		'	vec2 dSTdx = dFdx( uv );',
@@ -89,77 +161,7 @@ BumpMapNode.Nodes = ( function () {
 
 
 } )();
 } )();
 
 
-BumpMapNode.prototype = Object.create( TempNode.prototype );
-BumpMapNode.prototype.constructor = BumpMapNode;
 BumpMapNode.prototype.nodeType = 'BumpMap';
 BumpMapNode.prototype.nodeType = 'BumpMap';
 BumpMapNode.prototype.hashProperties = [ 'toNormalMap' ];
 BumpMapNode.prototype.hashProperties = [ 'toNormalMap' ];
 
 
-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();
-			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;
-
-	return this;
-
-};
-
-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 };
 export { BumpMapNode };

+ 71 - 69
examples/jsm/nodes/misc/NormalMapNode.js

@@ -9,18 +9,84 @@ import { UVNode } from '../accessors/UVNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 import { PositionNode } from '../accessors/PositionNode.js';
 
 
-function NormalMapNode( value, scale ) {
+class NormalMapNode extends TempNode {
 
 
-	TempNode.call( this, 'v3' );
+	constructor( value, scale ) {
 
 
-	this.value = value;
-	this.scale = scale || new Vector2Node( 1, 1 );
+		super( 'v3' );
+
+		this.value = value;
+		this.scale = scale || new Vector2Node( 1, 1 );
+
+	}
+
+	generate( builder, output ) {
+
+		if ( builder.isShader( 'fragment' ) ) {
+
+			const perturbNormal2Arb = builder.include( NormalMapNode.Nodes.perturbNormal2Arb );
+
+			this.normal = this.normal || new NormalNode();
+			this.position = this.position || new PositionNode( PositionNode.VIEW );
+			this.uv = this.uv || new UVNode();
+
+			let scale = this.scale.build( builder, 'v2' );
+
+			if ( builder.material.side === BackSide ) {
+
+				scale = '-' + scale;
+
+			}
+
+			return builder.format( perturbNormal2Arb + '( -' + this.position.build( builder, 'v3' ) + ', ' +
+				this.normal.build( builder, 'v3' ) + ', ' +
+				this.value.build( builder, 'v3' ) + ', ' +
+				this.uv.build( builder, 'v2' ) + ', ' +
+				scale + ' )', 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 );
+
+		}
+
+	}
+
+	copy( source ) {
+
+		super.copy( source );
+
+		this.value = source.value;
+		this.scale = source.scale;
+
+		return this;
+
+	}
+
+	toJSON( meta ) {
+
+		let 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;
+
+	}
 
 
 }
 }
 
 
 NormalMapNode.Nodes = ( function () {
 NormalMapNode.Nodes = ( function () {
 
 
-	var perturbNormal2Arb = new FunctionNode(
+	const perturbNormal2Arb = new FunctionNode(
 
 
 		// Per-Pixel Tangent Space Normal Mapping
 		// Per-Pixel Tangent Space Normal Mapping
 		// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
 		// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
@@ -67,70 +133,6 @@ NormalMapNode.Nodes = ( function () {
 
 
 } )();
 } )();
 
 
-NormalMapNode.prototype = Object.create( TempNode.prototype );
-NormalMapNode.prototype.constructor = NormalMapNode;
 NormalMapNode.prototype.nodeType = 'NormalMap';
 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();
-		this.position = this.position || new PositionNode( PositionNode.VIEW );
-		this.uv = this.uv || new UVNode();
-
-		var scale = this.scale.build( builder, 'v2' );
-
-		if ( builder.material.side === BackSide ) {
-
-			scale = '-' + scale;
-
-		}
-
-		return builder.format( perturbNormal2Arb + '( -' + this.position.build( builder, 'v3' ) + ', ' +
-			this.normal.build( builder, 'v3' ) + ', ' +
-			this.value.build( builder, 'v3' ) + ', ' +
-			this.uv.build( builder, 'v2' ) + ', ' +
-			scale + ' )', 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;
-
-	return this;
-
-};
-
-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 };
 export { NormalMapNode };

+ 44 - 42
examples/jsm/nodes/misc/TextureCubeNode.js

@@ -4,81 +4,83 @@ import { TextureCubeUVNode } from './TextureCubeUVNode.js';
 import { ReflectNode } from '../accessors/ReflectNode.js';
 import { ReflectNode } from '../accessors/ReflectNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
 
 
-function TextureCubeNode( value, uv, bias ) {
+class TextureCubeNode extends TempNode {
 
 
-	TempNode.call( this, 'v4' );
+	constructor( value, uv, bias ) {
 
 
-	this.value = value;
+		super( 'v4' );
 
 
-	this.radianceNode = new TextureCubeUVNode(
-		this.value,
-		uv || new ReflectNode( ReflectNode.VECTOR ),
-		// bias should be replaced in builder.context in build process
-		bias
-	);
+		this.value = value;
 
 
-	this.irradianceNode = new TextureCubeUVNode(
-		this.value,
-		new NormalNode( NormalNode.WORLD ),
-		new FloatNode( 1 ).setReadonly( true )
-	);
+		this.radianceNode = new TextureCubeUVNode(
+			this.value,
+			uv || new ReflectNode( ReflectNode.VECTOR ),
+			// bias should be replaced in builder.context in build process
+			bias
+		);
 
 
-}
+		this.irradianceNode = new TextureCubeUVNode(
+			this.value,
+			new NormalNode( NormalNode.WORLD ),
+			new FloatNode( 1 ).setReadonly( true )
+		);
 
 
-TextureCubeNode.prototype = Object.create( TempNode.prototype );
-TextureCubeNode.prototype.constructor = TextureCubeNode;
-TextureCubeNode.prototype.nodeType = 'TextureCube';
+	}
 
 
-TextureCubeNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-		builder.require( 'irradiance' );
+			builder.require( 'irradiance' );
 
 
-		if ( builder.context.bias ) {
+			if ( builder.context.bias ) {
 
 
-			builder.context.bias.setTexture( this.value );
+				builder.context.bias.setTexture( this.value );
 
 
-		}
+			}
+
+			const scopeNode = builder.slot === 'irradiance' ? this.irradianceNode : this.radianceNode;
 
 
-		var scopeNode = builder.slot === 'irradiance' ? this.irradianceNode : this.radianceNode;
+			return scopeNode.build( builder, output );
 
 
-		return scopeNode.build( builder, output );
+		} else {
 
 
-	} else {
+			console.warn( 'THREE.TextureCubeNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-		console.warn( 'THREE.TextureCubeNode is not compatible with ' + builder.shader + ' shader.' );
+			return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
 
 
-		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-TextureCubeNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	TempNode.prototype.copy.call( this, source );
+		this.value = source.value;
 
 
-	this.value = source.value;
+		return this;
 
 
-	return this;
+	}
+
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-TextureCubeNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.value = this.value.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.value = this.value.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+TextureCubeNode.prototype.nodeType = 'TextureCube';
 
 
 export { TextureCubeNode };
 export { TextureCubeNode };

+ 149 - 147
examples/jsm/nodes/misc/TextureCubeUVNode.js

@@ -9,19 +9,136 @@ import { OperatorNode } from '../math/OperatorNode.js';
 import { MathNode } from '../math/MathNode.js';
 import { MathNode } from '../math/MathNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 
 
-function TextureCubeUVNode( value, uv, bias ) {
+class TextureCubeUVNode extends TempNode {
 
 
-	TempNode.call( this, 'v4' );
+	constructor( value, uv, bias ) {
 
 
-	this.value = value,
-	this.uv = uv;
-	this.bias = bias;
+		super( 'v4' );
+
+		this.value = value,
+		this.uv = uv;
+		this.bias = bias;
+
+	}
+
+	bilinearCubeUV( builder, texture, uv, mipInt ) {
+
+		const bilinearCubeUV = new FunctionCallNode( TextureCubeUVNode.Nodes.bilinearCubeUV, [ texture, uv, mipInt ] );
+
+		this.colorSpaceTL = this.colorSpaceTL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+		this.colorSpaceTL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+		this.colorSpaceTL.input.parse( bilinearCubeUV.build( builder ) + '.tl' );
+
+		this.colorSpaceTR = this.colorSpaceTR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+		this.colorSpaceTR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+		this.colorSpaceTR.input.parse( bilinearCubeUV.build( builder ) + '.tr' );
+
+		this.colorSpaceBL = this.colorSpaceBL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+		this.colorSpaceBL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+		this.colorSpaceBL.input.parse( bilinearCubeUV.build( builder ) + '.bl' );
+
+		this.colorSpaceBR = this.colorSpaceBR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+		this.colorSpaceBR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+		this.colorSpaceBR.input.parse( bilinearCubeUV.build( builder ) + '.br' );
+
+		// add a custom context for fix incompatibility with the core
+		// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
+		// this should be removed in the future
+		// context.include =: is used to include or not functions if used FunctionNode
+		// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
+		const context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
+
+		builder.addContext( context );
+
+		this.colorSpaceTLExp = new ExpressionNode( this.colorSpaceTL.build( builder, 'v4' ), 'v4' );
+		this.colorSpaceTRExp = new ExpressionNode( this.colorSpaceTR.build( builder, 'v4' ), 'v4' );
+		this.colorSpaceBLExp = new ExpressionNode( this.colorSpaceBL.build( builder, 'v4' ), 'v4' );
+		this.colorSpaceBRExp = new ExpressionNode( this.colorSpaceBR.build( builder, 'v4' ), 'v4' );
+
+		// end custom context
+
+		builder.removeContext();
+
+		// --
+
+		const output = new ExpressionNode( 'mix( mix( cubeUV_TL, cubeUV_TR, cubeUV.f.x ), mix( cubeUV_BL, cubeUV_BR, cubeUV.f.x ), cubeUV.f.y )', 'v4' );
+		output.keywords[ 'cubeUV_TL' ] = this.colorSpaceTLExp;
+		output.keywords[ 'cubeUV_TR' ] = this.colorSpaceTRExp;
+		output.keywords[ 'cubeUV_BL' ] = this.colorSpaceBLExp;
+		output.keywords[ 'cubeUV_BR' ] = this.colorSpaceBRExp;
+		output.keywords[ 'cubeUV' ] = bilinearCubeUV;
+
+		return output;
+
+	}
+
+	generate( builder, output ) {
+
+		if ( builder.isShader( 'fragment' ) ) {
+
+			const uv = this.uv;
+			const bias = this.bias || builder.context.roughness;
+
+			const mipV = new FunctionCallNode( TextureCubeUVNode.Nodes.roughnessToMip, [ bias ] );
+			const mip = new MathNode( mipV, TextureCubeUVNode.Nodes.m0, TextureCubeUVNode.Nodes.cubeUV_maxMipLevel, MathNode.CLAMP );
+			const mipInt	= new MathNode( mip, MathNode.FLOOR );
+			const mipF	= new MathNode( mip, MathNode.FRACT );
+
+			const color0 = this.bilinearCubeUV( builder, this.value, uv, mipInt );
+			const color1 = this.bilinearCubeUV( builder, this.value, uv, new OperatorNode(
+				mipInt,
+				new FloatNode( 1 ).setReadonly( true ),
+				OperatorNode.ADD
+			) );
+
+			const color1Mix = new MathNode( color0, color1, mipF, MathNode.MIX );
+
+			/*
+			// TODO: Optimize this in the future
+			let cond = new CondNode(
+				mipF,
+				new FloatNode( 0 ).setReadonly( true ),
+				CondNode.EQUAL,
+				color0, // if
+				color1Mix	// else
+			);
+			*/
+
+			return builder.format( color1Mix.build( builder ), 'v4', output );
+
+		} else {
+
+			console.warn( 'THREE.TextureCubeUVNode is not compatible with ' + builder.shader + ' shader.' );
+
+			return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+
+		}
+
+	}
+
+	toJSON( meta ) {
+
+		let 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.bias = this.bias.toJSON( meta ).uuid;
+
+		}
+
+		return data;
+
+	}
 
 
 }
 }
 
 
 TextureCubeUVNode.Nodes = ( function () {
 TextureCubeUVNode.Nodes = ( function () {
 
 
-	var TextureCubeUVData = new StructNode(
+	const TextureCubeUVData = new StructNode(
 		`struct TextureCubeUVData {
 		`struct TextureCubeUVData {
 			vec4 tl;
 			vec4 tl;
 			vec4 tr;
 			vec4 tr;
@@ -30,16 +147,16 @@ TextureCubeUVNode.Nodes = ( function () {
 			vec2 f;
 			vec2 f;
 		}` );
 		}` );
 
 
-	var cubeUV_maxMipLevel = new ConstNode( 'float cubeUV_maxMipLevel 8.0', true );
-	var cubeUV_minMipLevel = new ConstNode( 'float cubeUV_minMipLevel 4.0', true );
-	var cubeUV_maxTileSize = new ConstNode( 'float cubeUV_maxTileSize 256.0', true );
-	var cubeUV_minTileSize = new ConstNode( 'float cubeUV_minTileSize 16.0', true );
+	const cubeUV_maxMipLevel = new ConstNode( 'float cubeUV_maxMipLevel 8.0', true );
+	const cubeUV_minMipLevel = new ConstNode( 'float cubeUV_minMipLevel 4.0', true );
+	const cubeUV_maxTileSize = new ConstNode( 'float cubeUV_maxTileSize 256.0', true );
+	const cubeUV_minTileSize = new ConstNode( 'float cubeUV_minTileSize 16.0', true );
 
 
 	// These shader functions convert between the UV coordinates of a single face of
 	// These shader functions convert between the UV coordinates of a single face of
 	// a cubemap, the 0-5 integer index of a cube face, and the direction vector for
 	// a cubemap, the 0-5 integer index of a cube face, and the direction vector for
 	// sampling a textureCube (not generally normalized).
 	// sampling a textureCube (not generally normalized).
 
 
-	var getFace = new FunctionNode(
+	const getFace = new FunctionNode(
 		`float getFace(vec3 direction) {
 		`float getFace(vec3 direction) {
 				vec3 absDirection = abs(direction);
 				vec3 absDirection = abs(direction);
 				float face = -1.0;
 				float face = -1.0;
@@ -58,7 +175,7 @@ TextureCubeUVNode.Nodes = ( function () {
 		}` );
 		}` );
 	getFace.useKeywords = false;
 	getFace.useKeywords = false;
 
 
-	var getUV = new FunctionNode(
+	const getUV = new FunctionNode(
 		`vec2 getUV(vec3 direction, float face) {
 		`vec2 getUV(vec3 direction, float face) {
 				vec2 uv;
 				vec2 uv;
 				if (face == 0.0) {
 				if (face == 0.0) {
@@ -78,7 +195,7 @@ TextureCubeUVNode.Nodes = ( function () {
 		}` );
 		}` );
 	getUV.useKeywords = false;
 	getUV.useKeywords = false;
 
 
-	var bilinearCubeUV = new FunctionNode(
+	const bilinearCubeUV = new FunctionNode(
 		`TextureCubeUVData bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {
 		`TextureCubeUVData bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {
 
 
 			float face = getFace(direction);
 			float face = getFace(direction);
@@ -117,25 +234,25 @@ TextureCubeUVNode.Nodes = ( function () {
 
 
 	// These defines must match with PMREMGenerator
 	// These defines must match with PMREMGenerator
 
 
-	var r0 = new ConstNode( 'float r0 1.0', true );
-	var v0 = new ConstNode( 'float v0 0.339', true );
-	var m0 = new ConstNode( 'float m0 -2.0', true );
-	var r1 = new ConstNode( 'float r1 0.8', true );
-	var v1 = new ConstNode( 'float v1 0.276', true );
-	var m1 = new ConstNode( 'float m1 -1.0', true );
-	var r4 = new ConstNode( 'float r4 0.4', true );
-	var v4 = new ConstNode( 'float v4 0.046', true );
-	var m4 = new ConstNode( 'float m4 2.0', true );
-	var r5 = new ConstNode( 'float r5 0.305', true );
-	var v5 = new ConstNode( 'float v5 0.016', true );
-	var m5 = new ConstNode( 'float m5 3.0', true );
-	var r6 = new ConstNode( 'float r6 0.21', true );
-	var v6 = new ConstNode( 'float v6 0.0038', true );
-	var m6 = new ConstNode( 'float m6 4.0', true );
-
-	var defines = [ r0, v0, m0, r1, v1, m1, r4, v4, m4, r5, v5, m5, r6, v6, m6 ];
-
-	var roughnessToMip = new FunctionNode(
+	const r0 = new ConstNode( 'float r0 1.0', true );
+	const v0 = new ConstNode( 'float v0 0.339', true );
+	const m0 = new ConstNode( 'float m0 -2.0', true );
+	const r1 = new ConstNode( 'float r1 0.8', true );
+	const v1 = new ConstNode( 'float v1 0.276', true );
+	const m1 = new ConstNode( 'float m1 -1.0', true );
+	const r4 = new ConstNode( 'float r4 0.4', true );
+	const v4 = new ConstNode( 'float v4 0.046', true );
+	const m4 = new ConstNode( 'float m4 2.0', true );
+	const r5 = new ConstNode( 'float r5 0.305', true );
+	const v5 = new ConstNode( 'float v5 0.016', true );
+	const m5 = new ConstNode( 'float m5 3.0', true );
+	const r6 = new ConstNode( 'float r6 0.21', true );
+	const v6 = new ConstNode( 'float v6 0.0038', true );
+	const m6 = new ConstNode( 'float m6 4.0', true );
+
+	const defines = [ r0, v0, m0, r1, v1, m1, r4, v4, m4, r5, v5, m5, r6, v6, m6 ];
+
+	const roughnessToMip = new FunctionNode(
 		`float roughnessToMip(float roughness) {
 		`float roughnessToMip(float roughness) {
 			float mip = 0.0;
 			float mip = 0.0;
 			if (roughness >= r1) {
 			if (roughness >= r1) {
@@ -161,121 +278,6 @@ TextureCubeUVNode.Nodes = ( function () {
 
 
 } )();
 } )();
 
 
-TextureCubeUVNode.prototype = Object.create( TempNode.prototype );
-TextureCubeUVNode.prototype.constructor = TextureCubeUVNode;
 TextureCubeUVNode.prototype.nodeType = 'TextureCubeUV';
 TextureCubeUVNode.prototype.nodeType = 'TextureCubeUV';
 
 
-TextureCubeUVNode.prototype.bilinearCubeUV = function ( builder, texture, uv, mipInt ) {
-
-	var bilinearCubeUV = new FunctionCallNode( TextureCubeUVNode.Nodes.bilinearCubeUV, [ texture, uv, mipInt ] );
-
-	this.colorSpaceTL = this.colorSpaceTL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
-	this.colorSpaceTL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	this.colorSpaceTL.input.parse( bilinearCubeUV.build( builder ) + '.tl' );
-
-	this.colorSpaceTR = this.colorSpaceTR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
-	this.colorSpaceTR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	this.colorSpaceTR.input.parse( bilinearCubeUV.build( builder ) + '.tr' );
-
-	this.colorSpaceBL = this.colorSpaceBL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
-	this.colorSpaceBL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	this.colorSpaceBL.input.parse( bilinearCubeUV.build( builder ) + '.bl' );
-
-	this.colorSpaceBR = this.colorSpaceBR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
-	this.colorSpaceBR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	this.colorSpaceBR.input.parse( bilinearCubeUV.build( builder ) + '.br' );
-
-	// add a custom context for fix incompatibility with the core
-	// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
-	// this should be removed in the future
-	// context.include =: is used to include or not functions if used FunctionNode
-	// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
-	var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
-
-	builder.addContext( context );
-
-	this.colorSpaceTLExp = new ExpressionNode( this.colorSpaceTL.build( builder, 'v4' ), 'v4' );
-	this.colorSpaceTRExp = new ExpressionNode( this.colorSpaceTR.build( builder, 'v4' ), 'v4' );
-	this.colorSpaceBLExp = new ExpressionNode( this.colorSpaceBL.build( builder, 'v4' ), 'v4' );
-	this.colorSpaceBRExp = new ExpressionNode( this.colorSpaceBR.build( builder, 'v4' ), 'v4' );
-
-	// end custom context
-
-	builder.removeContext();
-
-	// --
-
-	var output = new ExpressionNode( 'mix( mix( cubeUV_TL, cubeUV_TR, cubeUV.f.x ), mix( cubeUV_BL, cubeUV_BR, cubeUV.f.x ), cubeUV.f.y )', 'v4' );
-	output.keywords[ 'cubeUV_TL' ] = this.colorSpaceTLExp;
-	output.keywords[ 'cubeUV_TR' ] = this.colorSpaceTRExp;
-	output.keywords[ 'cubeUV_BL' ] = this.colorSpaceBLExp;
-	output.keywords[ 'cubeUV_BR' ] = this.colorSpaceBRExp;
-	output.keywords[ 'cubeUV' ] = bilinearCubeUV;
-
-	return output;
-
-};
-
-TextureCubeUVNode.prototype.generate = function ( builder, output ) {
-
-	if ( builder.isShader( 'fragment' ) ) {
-
-		var uv = this.uv;
-		var bias = this.bias || builder.context.roughness;
-
-		var mipV = new FunctionCallNode( TextureCubeUVNode.Nodes.roughnessToMip, [ bias ] );
-		var mip = new MathNode( mipV, TextureCubeUVNode.Nodes.m0, TextureCubeUVNode.Nodes.cubeUV_maxMipLevel, MathNode.CLAMP );
-		var mipInt	= new MathNode( mip, MathNode.FLOOR );
-		var mipF	= new MathNode( mip, MathNode.FRACT );
-
-		var color0 = this.bilinearCubeUV( builder, this.value, uv, mipInt );
-		var color1 = this.bilinearCubeUV( builder, this.value, uv, new OperatorNode(
-			mipInt,
-			new FloatNode( 1 ).setReadonly( true ),
-			OperatorNode.ADD
-		) );
-
-		var color1Mix = new MathNode( color0, color1, mipF, MathNode.MIX );
-
-		/*
-		// TODO: Optimize this in the future
-		var cond = new CondNode(
-			mipF,
-			new FloatNode( 0 ).setReadonly( true ),
-			CondNode.EQUAL,
-			color0, // if
-			color1Mix	// else
-		);
-		*/
-
-		return builder.format( color1Mix.build( builder ), 'v4', 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.value = this.value.toJSON( meta ).uuid;
-		data.uv = this.uv.toJSON( meta ).uuid;
-		data.bias = this.bias.toJSON( meta ).uuid;
-
-	}
-
-	return data;
-
-};
-
 export { TextureCubeUVNode };
 export { TextureCubeUVNode };

+ 36 - 38
examples/jsm/nodes/postprocessing/NodePostProcessing.js

@@ -12,43 +12,41 @@ import {
 import { NodeMaterial } from '../materials/NodeMaterial.js';
 import { NodeMaterial } from '../materials/NodeMaterial.js';
 import { ScreenNode } from '../inputs/ScreenNode.js';
 import { ScreenNode } from '../inputs/ScreenNode.js';
 
 
-function NodePostProcessing( renderer, renderTarget ) {
+class NodePostProcessing {
 
 
-	if ( renderTarget === undefined ) {
+	constructor( renderer, renderTarget ) {
 
 
-		var parameters = {
-			minFilter: LinearFilter,
-			magFilter: LinearFilter,
-			format: RGBAFormat
-		};
+		if ( renderTarget === undefined ) {
 
 
-		var size = renderer.getDrawingBufferSize( new Vector2() );
-		renderTarget = new WebGLRenderTarget( size.width, size.height, parameters );
-
-	}
+			const parameters = {
+				minFilter: LinearFilter,
+				magFilter: LinearFilter,
+				format: RGBAFormat
+			};
 
 
-	this.renderer = renderer;
-	this.renderTarget = renderTarget;
+			const size = renderer.getDrawingBufferSize( new Vector2() );
+			renderTarget = new WebGLRenderTarget( size.width, size.height, parameters );
 
 
-	this.output = new ScreenNode();
-	this.material = new NodeMaterial();
+		}
 
 
-	this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene = new Scene();
+		this.renderer = renderer;
+		this.renderTarget = renderTarget;
 
 
-	this.quad = new Mesh( new PlaneGeometry( 2, 2 ), this.material );
-	this.quad.frustumCulled = false; // Avoid getting clipped
-	this.scene.add( this.quad );
+		this.output = new ScreenNode();
+		this.material = new NodeMaterial();
 
 
-	this.needsUpdate = true;
+		this.camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+		this.scene = new Scene();
 
 
-}
+		this.quad = new Mesh( new PlaneGeometry( 2, 2 ), this.material );
+		this.quad.frustumCulled = false; // Avoid getting clipped
+		this.scene.add( this.quad );
 
 
-NodePostProcessing.prototype = {
+		this.needsUpdate = true;
 
 
-	constructor: NodePostProcessing,
+	}
 
 
-	render: function ( scene, camera, frame ) {
+	render( scene, camera, frame ) {
 
 
 		if ( this.needsUpdate ) {
 		if ( this.needsUpdate ) {
 
 
@@ -78,39 +76,39 @@ NodePostProcessing.prototype = {
 		this.renderer.setRenderTarget( null );
 		this.renderer.setRenderTarget( null );
 		this.renderer.render( this.scene, this.camera );
 		this.renderer.render( this.scene, this.camera );
 
 
-	},
+	}
 
 
-	setPixelRatio: function ( value ) {
+	setPixelRatio( value ) {
 
 
 		this.renderer.setPixelRatio( value );
 		this.renderer.setPixelRatio( value );
 
 
-		var size = this.renderer.getSize( new Vector2() );
+		const size = this.renderer.getSize( new Vector2() );
 
 
 		this.setSize( size.width, size.height );
 		this.setSize( size.width, size.height );
 
 
-	},
+	}
 
 
-	setSize: function ( width, height ) {
+	setSize( width, height ) {
 
 
-		var pixelRatio = this.renderer.getPixelRatio();
+		const pixelRatio = this.renderer.getPixelRatio();
 
 
 		this.renderTarget.setSize( width * pixelRatio, height * pixelRatio );
 		this.renderTarget.setSize( width * pixelRatio, height * pixelRatio );
 
 
 		this.renderer.setSize( width, height );
 		this.renderer.setSize( width, height );
 
 
-	},
+	}
 
 
-	copy: function ( source ) {
+	copy( source ) {
 
 
 		this.output = source.output;
 		this.output = source.output;
 
 
 		return this;
 		return this;
 
 
-	},
+	}
 
 
-	toJSON: function ( meta ) {
+	toJSON( meta ) {
 
 
-		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+		const isRootObject = ( meta === undefined || typeof meta === 'string' );
 
 
 		if ( isRootObject ) {
 		if ( isRootObject ) {
 
 
@@ -124,7 +122,7 @@ NodePostProcessing.prototype = {
 
 
 		if ( ! meta.post[ this.uuid ] ) {
 		if ( ! meta.post[ this.uuid ] ) {
 
 
-			var data = {};
+			const data = {};
 
 
 			data.uuid = this.uuid;
 			data.uuid = this.uuid;
 			data.type = 'NodePostProcessing';
 			data.type = 'NodePostProcessing';
@@ -145,6 +143,6 @@ NodePostProcessing.prototype = {
 
 
 	}
 	}
 
 
-};
+}
 
 
 export { NodePostProcessing };
 export { NodePostProcessing };

+ 40 - 38
examples/jsm/nodes/procedural/CheckerNode.js

@@ -2,72 +2,74 @@ import { TempNode } from '../core/TempNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { UVNode } from '../accessors/UVNode.js';
 import { UVNode } from '../accessors/UVNode.js';
 
 
-function CheckerNode( uv ) {
+class CheckerNode extends TempNode {
 
 
-	TempNode.call( this, 'f' );
+	constructor( uv ) {
 
 
-	this.uv = uv || new UVNode();
+		super( 'f' );
 
 
-}
+		this.uv = uv || new UVNode();
 
 
-CheckerNode.prototype = Object.create( TempNode.prototype );
-CheckerNode.prototype.constructor = CheckerNode;
-CheckerNode.prototype.nodeType = 'Noise';
+	}
 
 
-CheckerNode.Nodes = ( function () {
+	generate( builder, output ) {
 
 
-	// https://github.com/mattdesl/glsl-checker/blob/master/index.glsl
+		const snoise = builder.include( CheckerNode.Nodes.checker );
 
 
-	var checker = new FunctionNode( [
-		'float checker( vec2 uv ) {',
+		return builder.format( snoise + '( ' + this.uv.build( builder, 'v2' ) + ' )', this.getType( builder ), output );
 
 
-		'	float cx = floor( uv.x );',
-		'	float cy = floor( uv.y ); ',
-		'	float result = mod( cx + cy, 2.0 );',
+	}
 
 
-		'	return sign( result );',
+	copy( source ) {
 
 
-		'}'
-	].join( '\n' ) );
+		super.copy( source );
 
 
-	return {
-		checker: checker
-	};
+		this.uv = source.uv;
 
 
-} )();
+		return this;
 
 
-CheckerNode.prototype.generate = function ( builder, output ) {
+	}
 
 
-	var snoise = builder.include( CheckerNode.Nodes.checker );
+	toJSON( meta ) {
 
 
-	return builder.format( snoise + '( ' + this.uv.build( builder, 'v2' ) + ' )', this.getType( builder ), output );
+		let data = this.getJSONNode( meta );
 
 
-};
+		if ( ! data ) {
 
 
-CheckerNode.prototype.copy = function ( source ) {
+			data = this.createJSONNode( meta );
 
 
-	TempNode.prototype.copy.call( this, source );
+			data.uv = this.uv.toJSON( meta ).uuid;
 
 
-	this.uv = source.uv;
+		}
 
 
-	return this;
+		return data;
 
 
-};
+	}
 
 
-CheckerNode.prototype.toJSON = function ( meta ) {
+}
 
 
-	var data = this.getJSONNode( meta );
+CheckerNode.Nodes = ( function () {
 
 
-	if ( ! data ) {
+	// https://github.com/mattdesl/glsl-checker/blob/master/index.glsl
 
 
-		data = this.createJSONNode( meta );
+	const checker = new FunctionNode( [
+		'float checker( vec2 uv ) {',
 
 
-		data.uv = this.uv.toJSON( meta ).uuid;
+		'	float cx = floor( uv.x );',
+		'	float cy = floor( uv.y ); ',
+		'	float result = mod( cx + cy, 2.0 );',
 
 
-	}
+		'	return sign( result );',
 
 
-	return data;
+		'}'
+	].join( '\n' ) );
 
 
-};
+	return {
+		checker: checker
+	};
+
+} )();
+
+CheckerNode.prototype.nodeType = 'Noise';
 
 
 export { CheckerNode };
 export { CheckerNode };

+ 36 - 34
examples/jsm/nodes/procedural/NoiseNode.js

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

+ 42 - 40
examples/jsm/nodes/utils/BypassNode.js

@@ -1,83 +1,85 @@
 import { Node } from '../core/Node.js';
 import { Node } from '../core/Node.js';
 
 
-function BypassNode( code, value ) {
+class BypassNode extends Node {
 
 
-	Node.call( this );
+	constructor( code, value ) {
 
 
-	this.code = code;
-	this.value = value;
+		super();
 
 
-}
+		this.code = code;
+		this.value = value;
 
 
-BypassNode.prototype = Object.create( Node.prototype );
-BypassNode.prototype.constructor = BypassNode;
-BypassNode.prototype.nodeType = 'Bypass';
+	}
 
 
-BypassNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	if ( this.value ) {
+		if ( this.value ) {
 
 
-		return this.value.getType( builder );
+			return this.value.getType( builder );
 
 
-	} else if ( builder.isShader( 'fragment' ) ) {
+		} else if ( builder.isShader( 'fragment' ) ) {
 
 
-		return 'f';
+			return 'f';
 
 
-	}
+		}
 
 
-	return 'void';
+		return 'void';
 
 
-};
+	}
 
 
-BypassNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	var code = this.code.build( builder, output ) + ';';
+		const code = this.code.build( builder, output ) + ';';
 
 
-	builder.addNodeCode( code );
+		builder.addNodeCode( code );
 
 
-	if ( builder.isShader( 'vertex' ) ) {
+		if ( builder.isShader( 'vertex' ) ) {
 
 
-		if ( this.value ) {
+			if ( this.value ) {
 
 
-			return this.value.build( builder, output );
+				return this.value.build( builder, output );
 
 
-		}
+			}
+
+		} else {
 
 
-	} else {
+			return this.value ? this.value.build( builder, output ) : builder.format( '0.0', 'f', output );
 
 
-		return this.value ? this.value.build( builder, output ) : builder.format( '0.0', 'f', output );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
+
+		super.copy( source );
 
 
-BypassNode.prototype.copy = function ( source ) {
+		this.code = source.code;
+		this.value = source.value;
 
 
-	Node.prototype.copy.call( this, source );
+		return this;
 
 
-	this.code = source.code;
-	this.value = source.value;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		let data = this.getJSONNode( meta );
 
 
-BypassNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.code = this.code.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+			if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
 
 
-		data.code = this.code.toJSON( meta ).uuid;
+		}
 
 
-		if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+BypassNode.prototype.nodeType = 'Bypass';
 
 
 export { BypassNode };
 export { BypassNode };

+ 99 - 97
examples/jsm/nodes/utils/ColorSpaceNode.js

@@ -14,13 +14,93 @@ import { FloatNode } from '../inputs/FloatNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 import { ExpressionNode } from '../core/ExpressionNode.js';
 
 
-function ColorSpaceNode( input, method ) {
+class ColorSpaceNode extends TempNode {
 
 
-	TempNode.call( this, 'v4' );
+	constructor( input, method ) {
 
 
-	this.input = input;
+		super( 'v4' );
 
 
-	this.method = method || ColorSpaceNode.LINEAR_TO_LINEAR;
+		this.input = input;
+
+		this.method = method || ColorSpaceNode.LINEAR_TO_LINEAR;
+
+	}
+
+	generate( builder, output ) {
+
+		const input = this.input.build( builder, 'v4' );
+		const outputType = this.getType( builder );
+
+		const methodNode = ColorSpaceNode.Nodes[ this.method ];
+		const method = builder.include( methodNode );
+
+		if ( method === ColorSpaceNode.LINEAR_TO_LINEAR ) {
+
+			return builder.format( input, outputType, output );
+
+		} else {
+
+			if ( methodNode.inputs.length === 2 ) {
+
+				const factor = this.factor.build( builder, 'f' );
+
+				return builder.format( method + '( ' + input + ', ' + factor + ' )', outputType, output );
+
+			} else {
+
+				return builder.format( method + '( ' + input + ' )', outputType, output );
+
+			}
+
+		}
+
+	}
+
+	fromEncoding( encoding ) {
+
+		const components = ColorSpaceNode.getEncodingComponents( encoding );
+
+		this.method = 'LinearTo' + components[ 0 ];
+		this.factor = components[ 1 ];
+
+	}
+
+	fromDecoding( encoding ) {
+
+		const components = ColorSpaceNode.getEncodingComponents( encoding );
+
+		this.method = components[ 0 ] + 'ToLinear';
+		this.factor = components[ 1 ];
+
+	}
+
+	copy( source ) {
+
+		super.copy( source );
+
+		this.input = source.input;
+		this.method = source.method;
+
+		return this;
+
+	}
+
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
+
+		if ( ! data ) {
+
+			data = this.createJSONNode( meta );
+
+			data.input = this.input.toJSON( meta ).uuid;
+			data.method = this.method;
+
+		}
+
+		return data;
+
+	}
 
 
 }
 }
 
 
@@ -28,7 +108,7 @@ ColorSpaceNode.Nodes = ( function () {
 
 
 	// For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/
 	// For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/
 
 
-	var LinearToLinear = new FunctionNode( [
+	const LinearToLinear = new FunctionNode( [
 		'vec4 LinearToLinear( in vec4 value ) {',
 		'vec4 LinearToLinear( in vec4 value ) {',
 
 
 		'	return value;',
 		'	return value;',
@@ -36,7 +116,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var GammaToLinear = new FunctionNode( [
+	const GammaToLinear = new FunctionNode( [
 		'vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {',
 		'vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {',
 
 
 		'	return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );',
 		'	return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );',
@@ -44,7 +124,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var LinearToGamma = new FunctionNode( [
+	const LinearToGamma = new FunctionNode( [
 		'vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {',
 		'vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {',
 
 
 		'	return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );',
 		'	return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );',
@@ -52,7 +132,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var sRGBToLinear = new FunctionNode( [
+	const sRGBToLinear = new FunctionNode( [
 		'vec4 sRGBToLinear( in vec4 value ) {',
 		'vec4 sRGBToLinear( in vec4 value ) {',
 
 
 		'	return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );',
 		'	return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );',
@@ -60,7 +140,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var LinearTosRGB = new FunctionNode( [
+	const LinearTosRGB = new FunctionNode( [
 		'vec4 LinearTosRGB( in vec4 value ) {',
 		'vec4 LinearTosRGB( in vec4 value ) {',
 
 
 		'	return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );',
 		'	return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );',
@@ -68,7 +148,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var RGBEToLinear = new FunctionNode( [
+	const RGBEToLinear = new FunctionNode( [
 		'vec4 RGBEToLinear( in vec4 value ) {',
 		'vec4 RGBEToLinear( in vec4 value ) {',
 
 
 		'	return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );',
 		'	return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );',
@@ -76,7 +156,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var LinearToRGBE = new FunctionNode( [
+	const LinearToRGBE = new FunctionNode( [
 		'vec4 LinearToRGBE( in vec4 value ) {',
 		'vec4 LinearToRGBE( in vec4 value ) {',
 
 
 		'	float maxComponent = max( max( value.r, value.g ), value.b );',
 		'	float maxComponent = max( max( value.r, value.g ), value.b );',
@@ -89,7 +169,7 @@ ColorSpaceNode.Nodes = ( function () {
 
 
 	// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
 	// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
 
 
-	var RGBMToLinear = new FunctionNode( [
+	const RGBMToLinear = new FunctionNode( [
 		'vec3 RGBMToLinear( in vec4 value, in float maxRange ) {',
 		'vec3 RGBMToLinear( in vec4 value, in float maxRange ) {',
 
 
 		'	return vec4( value.xyz * value.w * maxRange, 1.0 );',
 		'	return vec4( value.xyz * value.w * maxRange, 1.0 );',
@@ -97,7 +177,7 @@ ColorSpaceNode.Nodes = ( function () {
 		'}'
 		'}'
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
-	var LinearToRGBM = new FunctionNode( [
+	const LinearToRGBM = new FunctionNode( [
 		'vec3 LinearToRGBM( in vec4 value, in float maxRange ) {',
 		'vec3 LinearToRGBM( in vec4 value, in float maxRange ) {',
 
 
 		'	float maxRGB = max( value.x, max( value.g, value.b ) );',
 		'	float maxRGB = max( value.x, max( value.g, value.b ) );',
@@ -110,7 +190,7 @@ ColorSpaceNode.Nodes = ( function () {
 
 
 	// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
 	// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
 
 
-	var RGBDToLinear = new FunctionNode( [
+	const RGBDToLinear = new FunctionNode( [
 		'vec3 RGBDToLinear( in vec4 value, in float maxRange ) {',
 		'vec3 RGBDToLinear( in vec4 value, in float maxRange ) {',
 
 
 		'	return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );',
 		'	return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );',
@@ -119,7 +199,7 @@ ColorSpaceNode.Nodes = ( function () {
 	].join( '\n' ) );
 	].join( '\n' ) );
 
 
 
 
-	var LinearToRGBD = new FunctionNode( [
+	const LinearToRGBD = new FunctionNode( [
 		'vec3 LinearToRGBD( in vec4 value, in float maxRange ) {',
 		'vec3 LinearToRGBD( in vec4 value, in float maxRange ) {',
 
 
 		'	float maxRGB = max( value.x, max( value.g, value.b ) );',
 		'	float maxRGB = max( value.x, max( value.g, value.b ) );',
@@ -134,9 +214,9 @@ ColorSpaceNode.Nodes = ( function () {
 
 
 	// M matrix, for encoding
 	// M matrix, for encoding
 
 
-	var cLogLuvM = new ConstNode( 'const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );' );
+	const cLogLuvM = new ConstNode( 'const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );' );
 
 
-	var LinearToLogLuv = new FunctionNode( [
+	const LinearToLogLuv = new FunctionNode( [
 		'vec4 LinearToLogLuv( in vec4 value ) {',
 		'vec4 LinearToLogLuv( in vec4 value ) {',
 
 
 		'	vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;',
 		'	vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;',
@@ -153,9 +233,9 @@ ColorSpaceNode.Nodes = ( function () {
 
 
 	// Inverse M matrix, for decoding
 	// Inverse M matrix, for decoding
 
 
-	var cLogLuvInverseM = new ConstNode( 'const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );' );
+	const cLogLuvInverseM = new ConstNode( 'const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );' );
 
 
-	var LogLuvToLinear = new FunctionNode( [
+	const LogLuvToLinear = new FunctionNode( [
 		'vec4 LogLuvToLinear( in vec4 value ) {',
 		'vec4 LogLuvToLinear( in vec4 value ) {',
 
 
 		'	float Le = value.z * 255.0 + value.w;',
 		'	float Le = value.z * 255.0 + value.w;',
@@ -232,85 +312,7 @@ ColorSpaceNode.getEncodingComponents = function ( encoding ) {
 
 
 };
 };
 
 
-ColorSpaceNode.prototype = Object.create( TempNode.prototype );
-ColorSpaceNode.prototype.constructor = ColorSpaceNode;
 ColorSpaceNode.prototype.nodeType = 'ColorSpace';
 ColorSpaceNode.prototype.nodeType = 'ColorSpace';
 ColorSpaceNode.prototype.hashProperties = [ 'method' ];
 ColorSpaceNode.prototype.hashProperties = [ 'method' ];
 
 
-ColorSpaceNode.prototype.generate = function ( builder, output ) {
-
-	var input = this.input.build( builder, 'v4' );
-	var outputType = this.getType( builder );
-
-	var methodNode = ColorSpaceNode.Nodes[ this.method ];
-	var method = builder.include( methodNode );
-
-	if ( method === ColorSpaceNode.LINEAR_TO_LINEAR ) {
-
-		return builder.format( input, outputType, output );
-
-	} else {
-
-		if ( methodNode.inputs.length === 2 ) {
-
-			var factor = this.factor.build( builder, 'f' );
-
-			return builder.format( method + '( ' + input + ', ' + factor + ' )', outputType, output );
-
-		} else {
-
-			return builder.format( method + '( ' + input + ' )', outputType, output );
-
-		}
-
-	}
-
-};
-
-ColorSpaceNode.prototype.fromEncoding = function ( encoding ) {
-
-	var components = ColorSpaceNode.getEncodingComponents( encoding );
-
-	this.method = 'LinearTo' + components[ 0 ];
-	this.factor = components[ 1 ];
-
-};
-
-ColorSpaceNode.prototype.fromDecoding = function ( encoding ) {
-
-	var components = ColorSpaceNode.getEncodingComponents( encoding );
-
-	this.method = components[ 0 ] + 'ToLinear';
-	this.factor = components[ 1 ];
-
-};
-
-ColorSpaceNode.prototype.copy = function ( source ) {
-
-	TempNode.prototype.copy.call( this, source );
-
-	this.input = source.input;
-	this.method = source.method;
-
-	return this;
-
-};
-
-ColorSpaceNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		data = this.createJSONNode( meta );
-
-		data.input = this.input.toJSON( meta ).uuid;
-		data.method = this.method;
-
-	}
-
-	return data;
-
-};
-
 export { ColorSpaceNode };
 export { ColorSpaceNode };

+ 54 - 52
examples/jsm/nodes/utils/JoinNode.js

@@ -1,112 +1,114 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 import { NodeUtils } from '../core/NodeUtils.js';
 
 
-var inputs = NodeUtils.elements;
+const inputs = NodeUtils.elements;
 
 
-function JoinNode( x, y, z, w ) {
+class JoinNode extends TempNode {
 
 
-	TempNode.call( this, 'f' );
+	constructor( x, y, z, w ) {
 
 
-	this.x = x;
-	this.y = y;
-	this.z = z;
-	this.w = w;
+		super( 'f' );
 
 
-}
+		this.x = x;
+		this.y = y;
+		this.z = z;
+		this.w = w;
 
 
-JoinNode.prototype = Object.create( TempNode.prototype );
-JoinNode.prototype.constructor = JoinNode;
-JoinNode.prototype.nodeType = 'Join';
+	}
+
+	getNumElements() {
 
 
-JoinNode.prototype.getNumElements = function () {
+		let i = inputs.length;
 
 
-	var i = inputs.length;
+		while ( i -- ) {
 
 
-	while ( i -- ) {
+			if ( this[ inputs[ i ] ] !== undefined ) {
 
 
-		if ( this[ inputs[ i ] ] !== undefined ) {
+				++ i;
 
 
-			++ i;
+				break;
 
 
-			break;
+			}
 
 
 		}
 		}
 
 
+		return Math.max( i, 2 );
+
 	}
 	}
 
 
-	return Math.max( i, 2 );
+	getType( builder ) {
 
 
-};
+		return builder.getTypeFromLength( this.getNumElements() );
 
 
-JoinNode.prototype.getType = function ( builder ) {
+	}
 
 
-	return builder.getTypeFromLength( this.getNumElements() );
+	generate( builder, output ) {
 
 
-};
+		const type = this.getType( builder ),
+			length = this.getNumElements(),
+			outputs = [];
 
 
-JoinNode.prototype.generate = function ( builder, output ) {
+		for ( let i = 0; i < length; i ++ ) {
 
 
-	var type = this.getType( builder ),
-		length = this.getNumElements(),
-		outputs = [];
+			const elm = this[ inputs[ i ] ];
 
 
-	for ( var i = 0; i < length; i ++ ) {
+			outputs.push( elm ? elm.build( builder, 'f' ) : '0.0' );
 
 
-		var elm = this[ inputs[ i ] ];
+		}
 
 
-		outputs.push( elm ? elm.build( builder, 'f' ) : '0.0' );
+		const code = ( length > 1 ? builder.getConstructorFromLength( length ) : '' ) + '( ' + outputs.join( ', ' ) + ' )';
 
 
-	}
+		return builder.format( code, type, output );
 
 
-	var code = ( length > 1 ? builder.getConstructorFromLength( length ) : '' ) + '( ' + outputs.join( ', ' ) + ' )';
+	}
 
 
-	return builder.format( code, type, output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-JoinNode.prototype.copy = function ( source ) {
+		for ( const prop in source.inputs ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+			this[ prop ] = source.inputs[ prop ];
 
 
-	for ( var prop in source.inputs ) {
+		}
 
 
-		this[ prop ] = source.inputs[ prop ];
+		return this;
 
 
 	}
 	}
 
 
-	return this;
-
-};
+	toJSON( meta ) {
 
 
-JoinNode.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.inputs = {};
 
 
-		data.inputs = {};
+			const length = this.getNumElements();
 
 
-		var length = this.getNumElements();
+			for ( let i = 0; i < length; i ++ ) {
 
 
-		for ( var i = 0; i < length; i ++ ) {
+				const elm = this[ inputs[ i ] ];
 
 
-			var elm = this[ inputs[ i ] ];
+				if ( elm ) {
 
 
-			if ( elm ) {
+					data.inputs[ inputs[ i ] ] = elm.toJSON( meta ).uuid;
 
 
-				data.inputs[ inputs[ i ] ] = elm.toJSON( meta ).uuid;
+				}
 
 
 			}
 			}
 
 
+
 		}
 		}
 
 
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+JoinNode.prototype.nodeType = 'Join';
 
 
 export { JoinNode };
 export { JoinNode };

+ 25 - 28
examples/jsm/nodes/utils/MaxMIPLevelNode.js

@@ -1,59 +1,56 @@
 import { FloatNode } from '../inputs/FloatNode.js';
 import { FloatNode } from '../inputs/FloatNode.js';
 
 
-function MaxMIPLevelNode( texture ) {
+class MaxMIPLevelNode extends FloatNode {
 
 
-	FloatNode.call( this );
+	constructor( texture ) {
 
 
-	this.texture = texture;
+		super();
 
 
-	this.maxMIPLevel = 0;
+		this.texture = texture;
 
 
-}
-
-MaxMIPLevelNode.prototype = Object.create( FloatNode.prototype );
-MaxMIPLevelNode.prototype.constructor = MaxMIPLevelNode;
-MaxMIPLevelNode.prototype.nodeType = 'MaxMIPLevel';
+		this.maxMIPLevel = 0;
 
 
-Object.defineProperties( MaxMIPLevelNode.prototype, {
+	}
 
 
-	value: {
+	get value() {
 
 
-		get: function () {
+		if ( this.maxMIPLevel === 0 ) {
 
 
-			if ( this.maxMIPLevel === 0 ) {
+			var image = this.texture.value.image;
 
 
-				var image = this.texture.value.image;
+			if ( Array.isArray( image ) ) image = image[ 0 ];
 
 
-				if ( Array.isArray( image ) ) image = image[ 0 ];
+			this.maxMIPLevel = image !== undefined ? Math.log( Math.max( image.width, image.height ) ) * Math.LOG2E : 0;
 
 
-				this.maxMIPLevel = image !== undefined ? Math.log( Math.max( image.width, image.height ) ) * Math.LOG2E : 0;
+		}
 
 
-			}
+		return this.maxMIPLevel;
 
 
-			return this.maxMIPLevel;
+	}
 
 
-		},
+	set value( val ) {
 
 
-		set: function () { }
 
 
 	}
 	}
 
 
-} );
+	toJSON( meta ) {
+
+		let data = this.getJSONNode( meta );
 
 
-MaxMIPLevelNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.texture = this.texture.uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.texture = this.texture.uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+MaxMIPLevelNode.prototype.nodeType = 'MaxMIPLevel';
 
 
 export { MaxMIPLevelNode };
 export { MaxMIPLevelNode };

+ 51 - 49
examples/jsm/nodes/utils/RemapNode.js

@@ -70,84 +70,86 @@ vec4 remap( vec4 value, float inLow, float inHigh, float outLow, float outHigh )
 }
 }
 `.trim();
 `.trim();
 
 
-function RemapNode( value, inLow, inHigh, outLow, outHigh ) {
+class RemapNode extends TempNode {
 
 
-	TempNode.call( this, 'f' );
+	constructor( value, inLow, inHigh, outLow, outHigh ) {
 
 
-	this.value = value;
-	this.inLow = inLow;
-	this.inHigh = inHigh;
-	this.outLow = outLow;
-	this.outHigh = outHigh;
+		super( 'f' );
 
 
-}
+		this.value = value;
+		this.inLow = inLow;
+		this.inHigh = inHigh;
+		this.outLow = outLow;
+		this.outHigh = outHigh;
 
 
-RemapNode.prototype = Object.create( TempNode.prototype );
-RemapNode.prototype.constructor = RemapNode;
-RemapNode.prototype.nodeType = 'Remap';
+	}
 
 
-RemapNode.Nodes = (function () {
+	generate( builder, output ) {
 
 
-	return {
+		const remap = builder.include( RemapNode.Nodes.remap );
 
 
-		remap: new FunctionNode( REMAP_SRC )
+		return builder.format( remap + '( ' + [
 
 
-	};
+			this.value.build( builder ),
+			this.inLow.build( builder ),
+			this.inHigh.build( builder ),
+			this.outLow.build( builder ),
+			this.outHigh.build( builder ),
+
+		].join( ', ' ) + ' )', this.getType( builder ), output );
+
+	}
 
 
-})();
+	getType( builder ) {
 
 
-RemapNode.prototype.generate = function (builder, output) {
+		return this.value.getType( builder );
 
 
-	const remap = builder.include( RemapNode.Nodes.remap );
+	}
 
 
-	return builder.format( remap + '( ' + [
+	copy( source ) {
 
 
-		this.value.build( builder ),
-		this.inLow.build( builder ),
-		this.inHigh.build( builder ),
-		this.outLow.build( builder ),
-		this.outHigh.build( builder ),
+		super.copy( source );
 
 
-	].join( ', ' ) + ' )', this.getType( builder ), output );
+		this.value = source.value;
+		this.inLow = source.inLow;
+		this.inHigh = source.inHigh;
+		this.outLow = source.outLow;
+		this.outHigh = source.outHigh;
 
 
-};
+	}
 
 
-RemapNode.prototype.getType = function ( builder ) {
+	toJSON( meta ) {
 
 
-	return this.value.getType( builder );
+		let data = this.getJSONNode( meta );
 
 
-};
+		if ( ! data ) {
 
 
-RemapNode.prototype.copy = function ( source ) {
+			data = this.createJSONNode( meta );
 
 
-	TempNode.prototype.copy.call( this, source );
+			data.value = this.value.toJSON( meta ).uuid;
+			data.inLow = this.inLow.toJSON( meta ).uuid;
+			data.inHigh = this.inHigh.toJSON( meta ).uuid;
+			data.outLow = this.outLow.toJSON( meta ).uuid;
+			data.outHigh = this.outHigh.toJSON( meta ).uuid;
 
 
-	this.value = source.value;
-	this.inLow = source.inLow;
-	this.inHigh = source.inHigh;
-	this.outLow = source.outLow;
-	this.outHigh = source.outHigh;
+		}
 
 
-};
+		return data;
 
 
-RemapNode.prototype.toJSON = function ( meta ) {
+	}
 
 
-	let data = this.getJSONNode( meta );
+}
 
 
-	if ( ! data ) {
+RemapNode.prototype.nodeType = 'Remap';
 
 
-		data = this.createJSONNode( meta );
+RemapNode.Nodes = ( function () {
 
 
-		data.value = this.value.toJSON( meta ).uuid;
-		data.inLow = this.inLow.toJSON( meta ).uuid;
-		data.inHigh = this.inHigh.toJSON( meta ).uuid;
-		data.outLow = this.outLow.toJSON( meta ).uuid;
-		data.outHigh = this.outHigh.toJSON( meta ).uuid;
+	return {
 
 
-	}
+		remap: new FunctionNode( REMAP_SRC )
 
 
-	return data;
+	};
 
 
-};
+} )();
 
 
 export { RemapNode };
 export { RemapNode };

+ 55 - 53
examples/jsm/nodes/utils/SpecularMIPLevelNode.js

@@ -2,97 +2,99 @@ import { TempNode } from '../core/TempNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
 import { MaxMIPLevelNode } from './MaxMIPLevelNode.js';
 import { MaxMIPLevelNode } from './MaxMIPLevelNode.js';
 
 
-function SpecularMIPLevelNode( roughness, texture ) {
+class SpecularMIPLevelNode extends TempNode {
 
 
-	TempNode.call( this, 'f' );
+	constructor( roughness, texture ) {
 
 
-	this.roughness = roughness;
-	this.texture = texture;
+		super( 'f' );
 
 
-	this.maxMIPLevel = undefined;
+		this.roughness = roughness;
+		this.texture = texture;
 
 
-}
-
-SpecularMIPLevelNode.Nodes = ( function () {
+		this.maxMIPLevel = undefined;
 
 
-	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 roughness, const in float maxMIPLevelScalar ) {',
+	}
 
 
-		'	float sigma = PI * roughness * roughness / ( 1.0 + roughness );',
-		'	float desiredMIPLevel = maxMIPLevelScalar + log2( sigma );',
+	setTexture( texture ) {
 
 
-		// clamp to allowable LOD ranges.
-		'	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );',
+		this.texture = texture;
 
 
-		'}'
-	].join( '\n' ) );
+		return this;
 
 
-	return {
-		getSpecularMIPLevel: getSpecularMIPLevel
-	};
+	}
 
 
-} )();
+	generate( builder, output ) {
 
 
-SpecularMIPLevelNode.prototype = Object.create( TempNode.prototype );
-SpecularMIPLevelNode.prototype.constructor = SpecularMIPLevelNode;
-SpecularMIPLevelNode.prototype.nodeType = 'SpecularMIPLevel';
+		if ( builder.isShader( 'fragment' ) ) {
 
 
-SpecularMIPLevelNode.prototype.setTexture = function ( texture ) {
+			this.maxMIPLevel = this.maxMIPLevel || new MaxMIPLevelNode();
+			this.maxMIPLevel.texture = this.texture;
 
 
-	this.texture = texture;
+			const getSpecularMIPLevel = builder.include( SpecularMIPLevelNode.Nodes.getSpecularMIPLevel );
 
 
-	return this;
+			return builder.format( getSpecularMIPLevel + '( ' + this.roughness.build( builder, 'f' ) + ', ' + this.maxMIPLevel.build( builder, 'f' ) + ' )', this.type, output );
 
 
-};
+		} else {
 
 
-SpecularMIPLevelNode.prototype.generate = function ( builder, output ) {
+			console.warn( 'THREE.SpecularMIPLevelNode is not compatible with ' + builder.shader + ' shader.' );
 
 
-	if ( builder.isShader( 'fragment' ) ) {
+			return builder.format( '0.0', this.type, output );
 
 
-		this.maxMIPLevel = this.maxMIPLevel || new MaxMIPLevelNode();
-		this.maxMIPLevel.texture = this.texture;
+		}
 
 
-		var getSpecularMIPLevel = builder.include( SpecularMIPLevelNode.Nodes.getSpecularMIPLevel );
+	}
 
 
-		return builder.format( getSpecularMIPLevel + '( ' + this.roughness.build( builder, 'f' ) + ', ' + this.maxMIPLevel.build( builder, 'f' ) + ' )', this.type, output );
+	copy( source ) {
 
 
-	} else {
+		super.copy( source );
 
 
-		console.warn( 'THREE.SpecularMIPLevelNode is not compatible with ' + builder.shader + ' shader.' );
+		this.texture = source.texture;
+		this.roughness = source.roughness;
 
 
-		return builder.format( '0.0', this.type, output );
+		return this;
 
 
 	}
 	}
 
 
-};
+	toJSON( meta ) {
 
 
-SpecularMIPLevelNode.prototype.copy = function ( source ) {
+		let data = this.getJSONNode( meta );
 
 
-	TempNode.prototype.copy.call( this, source );
+		if ( ! data ) {
 
 
-	this.texture = source.texture;
-	this.roughness = source.roughness;
+			data = this.createJSONNode( meta );
 
 
-	return this;
+			data.texture = this.texture;
+			data.roughness = this.roughness;
 
 
-};
+		}
 
 
-SpecularMIPLevelNode.prototype.toJSON = function ( meta ) {
+		return data;
 
 
-	var data = this.getJSONNode( meta );
+	}
 
 
-	if ( ! data ) {
+}
 
 
-		data = this.createJSONNode( meta );
+SpecularMIPLevelNode.Nodes = ( function () {
 
 
-		data.texture = this.texture;
-		data.roughness = this.roughness;
+	const getSpecularMIPLevel = new FunctionNode( [
+		// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
+		'float getSpecularMIPLevel( const in float roughness, const in float maxMIPLevelScalar ) {',
 
 
-	}
+		'	float sigma = PI * roughness * roughness / ( 1.0 + roughness );',
+		'	float desiredMIPLevel = maxMIPLevelScalar + log2( sigma );',
 
 
-	return data;
+		// clamp to allowable LOD ranges.
+		'	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );',
 
 
-};
+		'}'
+	].join( '\n' ) );
+
+	return {
+		getSpecularMIPLevel: getSpecularMIPLevel
+	};
+
+} )();
+
+SpecularMIPLevelNode.prototype.nodeType = 'SpecularMIPLevel';
 
 
 export { SpecularMIPLevelNode };
 export { SpecularMIPLevelNode };

+ 35 - 33
examples/jsm/nodes/utils/SubSlotNode.js

@@ -1,75 +1,77 @@
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function SubSlotNode( slots ) {
+class SubSlotNode extends TempNode {
 
 
-	TempNode.call( this );
+	constructor( slots ) {
 
 
-	this.slots = slots || {};
+		super();
 
 
-}
+		this.slots = slots || {};
 
 
-SubSlotNode.prototype = Object.create( TempNode.prototype );
-SubSlotNode.prototype.constructor = SubSlotNode;
-SubSlotNode.prototype.nodeType = 'SubSlot';
+	}
 
 
-SubSlotNode.prototype.getType = function ( builder, output ) {
+	getType( builder, output ) {
+
+		return output;
+
+	}
 
 
-	return output;
+	generate( builder, output ) {
 
 
-};
+		if ( this.slots[ builder.slot ] ) {
 
 
-SubSlotNode.prototype.generate = function ( builder, output ) {
+			return this.slots[ builder.slot ].build( builder, output );
 
 
-	if ( this.slots[ builder.slot ] ) {
+		}
 
 
-		return this.slots[ builder.slot ].build( builder, output );
+		return builder.format( '0.0', 'f', output );
 
 
 	}
 	}
 
 
-	return builder.format( '0.0', 'f', output );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-SubSlotNode.prototype.copy = function ( source ) {
+		for ( const prop in source.slots ) {
 
 
-	TempNode.prototype.copy.call( this, source );
+			this.slots[ prop ] = source.slots[ prop ];
 
 
-	for ( var prop in source.slots ) {
+		}
 
 
-		this.slots[ prop ] = source.slots[ prop ];
+		return this;
 
 
 	}
 	}
 
 
-	return this;
-
-};
+	toJSON( meta ) {
 
 
-SubSlotNode.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.slots = {};
 
 
-		data.slots = {};
+			for ( const prop in this.slots ) {
 
 
-		for ( var prop in this.slots ) {
+				const slot = this.slots[ prop ];
 
 
-			var slot = this.slots[ prop ];
+				if ( slot ) {
 
 
-			if ( slot ) {
+					data.slots[ prop ] = slot.toJSON( meta ).uuid;
 
 
-				data.slots[ prop ] = slot.toJSON( meta ).uuid;
+				}
 
 
 			}
 			}
 
 
 		}
 		}
 
 
+		return data;
+
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+SubSlotNode.prototype.nodeType = 'SubSlot';
 
 
 export { SubSlotNode };
 export { SubSlotNode };

+ 54 - 50
examples/jsm/nodes/utils/SwitchNode.js

@@ -1,99 +1,103 @@
 import { Node } from '../core/Node.js';
 import { Node } from '../core/Node.js';
 
 
-function SwitchNode( node, components ) {
+class SwitchNode extends Node {
 
 
-	Node.call( this );
+	constructor( node, components ) {
 
 
-	this.node = node;
-	this.components = components || 'x';
+		super();
 
 
-}
+		this.node = node;
+		this.components = components || 'x';
 
 
-SwitchNode.prototype = Object.create( Node.prototype );
-SwitchNode.prototype.constructor = SwitchNode;
-SwitchNode.prototype.nodeType = 'Switch';
+	}
 
 
-SwitchNode.prototype.getType = function ( builder ) {
+	getType( builder ) {
 
 
-	return builder.getTypeFromLength( this.components.length );
+		return builder.getTypeFromLength( this.components.length );
 
 
-};
+	}
 
 
-SwitchNode.prototype.generate = function ( builder, output ) {
+	generate( builder, output ) {
 
 
-	var type = this.node.getType( builder ),
-		node = this.node.build( builder, type ),
-		inputLength = builder.getTypeLength( type ) - 1;
+		const type = this.node.getType( builder ),
+			inputLength = builder.getTypeLength( type ) - 1;
 
 
-	if ( inputLength > 0 ) {
+		let node = this.node.build( builder, type );
 
 
-		// get max length
+		if ( inputLength > 0 ) {
 
 
-		var outputLength = 0,
-			components = builder.colorToVectorProperties( this.components );
+			// get max length
 
 
-		var i, len = components.length;
+			let outputLength = 0;
+			const components = builder.colorToVectorProperties( this.components );
 
 
-		for ( i = 0; i < len; i ++ ) {
+			let i;
+			const len = components.length;
 
 
-			outputLength = Math.max( outputLength, builder.getIndexByElement( components.charAt( i ) ) );
+			for ( i = 0; i < len; i ++ ) {
 
 
-		}
+				outputLength = Math.max( outputLength, builder.getIndexByElement( components.charAt( i ) ) );
 
 
-		if ( outputLength > inputLength ) outputLength = inputLength;
+			}
 
 
-		// split
+			if ( outputLength > inputLength ) outputLength = inputLength;
 
 
-		node += '.';
+			// split
 
 
-		for ( i = 0; i < len; i ++ ) {
+			node += '.';
 
 
-			var idx = builder.getIndexByElement( components.charAt( i ) );
+			for ( i = 0; i < len; i ++ ) {
 
 
-			if ( idx > outputLength ) idx = outputLength;
+				let idx = builder.getIndexByElement( components.charAt( i ) );
 
 
-			node += builder.getElementByIndex( idx );
+				if ( idx > outputLength ) idx = outputLength;
 
 
-		}
+				node += builder.getElementByIndex( idx );
+
+			}
 
 
-		return builder.format( node, this.getType( builder ), output );
+			return builder.format( node, this.getType( builder ), output );
 
 
-	} else {
+		} else {
 
 
-		// join
+			// join
 
 
-		return builder.format( node, type, output );
+			return builder.format( node, type, output );
+
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-SwitchNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	Node.prototype.copy.call( this, source );
+		this.node = source.node;
+		this.components = source.components;
 
 
-	this.node = source.node;
-	this.components = source.components;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-SwitchNode.prototype.toJSON = function ( meta ) {
+		let data = this.getJSONNode( meta );
 
 
-	var data = this.getJSONNode( meta );
+		if ( ! data ) {
 
 
-	if ( ! data ) {
+			data = this.createJSONNode( meta );
 
 
-		data = this.createJSONNode( meta );
+			data.node = this.node.toJSON( meta ).uuid;
+			data.components = this.components;
 
 
-		data.node = this.node.toJSON( meta ).uuid;
-		data.components = this.components;
+		}
+
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+SwitchNode.prototype.nodeType = 'Switch';
 
 
 export { SwitchNode };
 export { SwitchNode };

+ 48 - 46
examples/jsm/nodes/utils/TimerNode.js

@@ -1,92 +1,94 @@
 import { FloatNode } from '../inputs/FloatNode.js';
 import { FloatNode } from '../inputs/FloatNode.js';
 import { NodeLib } from '../core/NodeLib.js';
 import { NodeLib } from '../core/NodeLib.js';
 
 
-function TimerNode( scale, scope, timeScale ) {
+class TimerNode extends FloatNode {
 
 
-	FloatNode.call( this );
+	constructor( scale, scope, timeScale ) {
 
 
-	this.scale = scale !== undefined ? scale : 1;
-	this.scope = scope || TimerNode.GLOBAL;
+		super();
 
 
-	this.timeScale = timeScale !== undefined ? timeScale : scale !== undefined;
+		this.scale = scale !== undefined ? scale : 1;
+		this.scope = scope || TimerNode.GLOBAL;
 
 
-}
+		this.timeScale = timeScale !== undefined ? timeScale : scale !== undefined;
 
 
-TimerNode.GLOBAL = 'global';
-TimerNode.LOCAL = 'local';
-TimerNode.DELTA = 'delta';
+	}
 
 
-TimerNode.prototype = Object.create( FloatNode.prototype );
-TimerNode.prototype.constructor = TimerNode;
-TimerNode.prototype.nodeType = 'Timer';
+	getReadonly() {
 
 
-TimerNode.prototype.getReadonly = function () {
+		// never use TimerNode as readonly but aways as "uniform"
 
 
-	// never use TimerNode as readonly but aways as "uniform"
+		return false;
 
 
-	return false;
+	}
 
 
-};
+	getUnique() {
 
 
-TimerNode.prototype.getUnique = function () {
+		// share TimerNode "uniform" input if is used on more time with others TimerNode
 
 
-	// share TimerNode "uniform" input if is used on more time with others TimerNode
+		return this.timeScale && ( this.scope === TimerNode.GLOBAL || this.scope === TimerNode.DELTA );
 
 
-	return this.timeScale && ( this.scope === TimerNode.GLOBAL || this.scope === TimerNode.DELTA );
+	}
 
 
-};
+	updateFrame( frame ) {
 
 
-TimerNode.prototype.updateFrame = function ( frame ) {
+		const scale = this.timeScale ? this.scale : 1;
 
 
-	var scale = this.timeScale ? this.scale : 1;
+		switch ( this.scope ) {
 
 
-	switch ( this.scope ) {
+			case TimerNode.LOCAL:
 
 
-		case TimerNode.LOCAL:
+				this.value += frame.delta * scale;
 
 
-			this.value += frame.delta * scale;
+				break;
 
 
-			break;
+			case TimerNode.DELTA:
 
 
-		case TimerNode.DELTA:
+				this.value = frame.delta * scale;
 
 
-			this.value = frame.delta * scale;
+				break;
 
 
-			break;
+			default:
 
 
-		default:
+				this.value = frame.time * scale;
 
 
-			this.value = frame.time * scale;
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
 
 
-TimerNode.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	FloatNode.prototype.copy.call( this, source );
+		this.scope = source.scope;
+		this.scale = source.scale;
 
 
-	this.scope = source.scope;
-	this.scale = source.scale;
+		this.timeScale = source.timeScale;
 
 
-	this.timeScale = source.timeScale;
+		return this;
 
 
-	return this;
+	}
 
 
-};
+	toJSON( meta ) {
 
 
-TimerNode.prototype.toJSON = function ( meta ) {
+		const data = super.toJSON( meta );
 
 
-	var data = FloatNode.prototype.toJSON.call( this, meta );
+		data.scope = this.scope;
+		data.scale = this.scale;
 
 
-	data.scope = this.scope;
-	data.scale = this.scale;
+		data.timeScale = this.timeScale;
 
 
-	data.timeScale = this.timeScale;
+		return data;
 
 
-	return data;
+	}
+
+}
+
+TimerNode.GLOBAL = 'global';
+TimerNode.LOCAL = 'local';
+TimerNode.DELTA = 'delta';
 
 
-};
+TimerNode.prototype.nodeType = 'Timer';
 
 
 NodeLib.addKeyword( 'time', function () {
 NodeLib.addKeyword( 'time', function () {
 
 

+ 34 - 32
examples/jsm/nodes/utils/UVTransformNode.js

@@ -2,63 +2,65 @@ import { ExpressionNode } from '../core/ExpressionNode.js';
 import { Matrix3Node } from '../inputs/Matrix3Node.js';
 import { Matrix3Node } from '../inputs/Matrix3Node.js';
 import { UVNode } from '../accessors/UVNode.js';
 import { UVNode } from '../accessors/UVNode.js';
 
 
-function UVTransformNode( uv, position ) {
+class UVTransformNode extends ExpressionNode {
 
 
-	ExpressionNode.call( this, '( uvTransform * vec3( uvNode, 1 ) ).xy', 'vec2' );
+	constructor( uv, position ) {
 
 
-	this.uv = uv || new UVNode();
-	this.position = position || new Matrix3Node();
+		super( '( uvTransform * vec3( uvNode, 1 ) ).xy', 'vec2' );
 
 
-}
+		this.uv = uv || new UVNode();
+		this.position = position || new Matrix3Node();
 
 
-UVTransformNode.prototype = Object.create( ExpressionNode.prototype );
-UVTransformNode.prototype.constructor = UVTransformNode;
-UVTransformNode.prototype.nodeType = 'UVTransform';
+	}
+
+	generate( builder, output ) {
+
+		this.keywords[ 'uvNode' ] = this.uv;
+		this.keywords[ 'uvTransform' ] = this.position;
 
 
-UVTransformNode.prototype.generate = function ( builder, output ) {
+		return super.generate( builder, output );
 
 
-	this.keywords[ 'uvNode' ] = this.uv;
-	this.keywords[ 'uvTransform' ] = this.position;
+	}
 
 
-	return ExpressionNode.prototype.generate.call( this, builder, output );
+	setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
 
 
-};
+		cx = cx !== undefined ? cx : .5;
+		cy = cy !== undefined ? cy : .5;
 
 
-UVTransformNode.prototype.setUvTransform = function ( tx, ty, sx, sy, rotation, cx, cy ) {
+		this.position.value.setUvTransform( tx, ty, sx, sy, rotation, cx, cy );
 
 
-	cx = cx !== undefined ? cx : .5;
-	cy = cy !== undefined ? cy : .5;
+	}
 
 
-	this.position.value.setUvTransform( tx, ty, sx, sy, rotation, cx, cy );
+	copy( source ) {
 
 
-};
+		super.copy( source );
 
 
-UVTransformNode.prototype.copy = function ( source ) {
+		this.uv = source.uv;
+		this.position = source.position;
 
 
-	ExpressionNode.prototype.copy.call( this, source );
+		return this;
 
 
-	this.uv = source.uv;
-	this.position = source.position;
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		var data = this.getJSONNode( meta );
 
 
-UVTransformNode.prototype.toJSON = function ( meta ) {
+		if ( ! data ) {
 
 
-	var data = this.getJSONNode( meta );
+			data = this.createJSONNode( meta );
 
 
-	if ( ! data ) {
+			data.uv = this.uv.toJSON( meta ).uuid;
+			data.position = this.position.toJSON( meta ).uuid;
 
 
-		data = this.createJSONNode( meta );
+		}
 
 
-		data.uv = this.uv.toJSON( meta ).uuid;
-		data.position = this.position.toJSON( meta ).uuid;
+		return data;
 
 
 	}
 	}
 
 
-	return data;
+}
 
 
-};
+UVTransformNode.prototype.nodeType = 'UVTransform';
 
 
 export { UVTransformNode };
 export { UVTransformNode };

+ 90 - 88
examples/jsm/nodes/utils/VelocityNode.js

@@ -2,167 +2,169 @@ import { Vector3 } from '../../../../build/three.module.js';
 
 
 import { Vector3Node } from '../inputs/Vector3Node.js';
 import { Vector3Node } from '../inputs/Vector3Node.js';
 
 
-function VelocityNode( target, params ) {
+class VelocityNode extends Vector3Node {
 
 
-	Vector3Node.call( this );
+	constructor( target, params ) {
 
 
-	this.params = {};
+		super();
 
 
-	this.velocity = new Vector3();
+		this.params = {};
 
 
-	this.setTarget( target );
-	this.setParams( params );
+		this.velocity = new Vector3();
 
 
-}
+		this.setTarget( target );
+		this.setParams( params );
 
 
-VelocityNode.prototype = Object.create( Vector3Node.prototype );
-VelocityNode.prototype.constructor = VelocityNode;
-VelocityNode.prototype.nodeType = 'Velocity';
+	}
 
 
-VelocityNode.prototype.getReadonly = function ( /*builder*/ ) {
+	getReadonly( /*builder*/ ) {
 
 
-	return false;
+		return false;
 
 
-};
+	}
 
 
-VelocityNode.prototype.setParams = function ( params ) {
+	setParams( params ) {
 
 
-	switch ( this.params.type ) {
+		switch ( this.params.type ) {
 
 
-		case 'elastic':
+			case 'elastic':
 
 
-			delete this.moment;
+				delete this.moment;
 
 
-			delete this.speed;
-			delete this.springVelocity;
+				delete this.speed;
+				delete this.springVelocity;
 
 
-			delete this.lastVelocity;
+				delete this.lastVelocity;
 
 
-			break;
+				break;
 
 
-	}
+		}
+
+		this.params = params || {};
 
 
-	this.params = params || {};
+		switch ( this.params.type ) {
 
 
-	switch ( this.params.type ) {
+			case 'elastic':
 
 
-		case 'elastic':
+				this.moment = new Vector3();
 
 
-			this.moment = new Vector3();
+				this.speed = new Vector3();
+				this.springVelocity = new Vector3();
 
 
-			this.speed = new Vector3();
-			this.springVelocity = new Vector3();
+				this.lastVelocity = new Vector3();
 
 
-			this.lastVelocity = new Vector3();
+				break;
 
 
-			break;
+		}
 
 
 	}
 	}
 
 
-};
+	setTarget( target ) {
 
 
-VelocityNode.prototype.setTarget = function ( target ) {
+		if ( this.target ) {
 
 
-	if ( this.target ) {
+			delete this.position;
+			delete this.oldPosition;
 
 
-		delete this.position;
-		delete this.oldPosition;
+		}
 
 
-	}
+		this.target = target;
 
 
-	this.target = target;
+		if ( target ) {
 
 
-	if ( target ) {
+			this.position = target.getWorldPosition( this.position || new Vector3() );
+			this.oldPosition = this.position.clone();
 
 
-		this.position = target.getWorldPosition( this.position || new Vector3() );
-		this.oldPosition = this.position.clone();
+		}
 
 
 	}
 	}
 
 
-};
+	updateFrameVelocity( /*frame*/ ) {
 
 
-VelocityNode.prototype.updateFrameVelocity = function ( /*frame*/ ) {
+		if ( this.target ) {
 
 
-	if ( this.target ) {
+			this.position = this.target.getWorldPosition( this.position || new Vector3() );
+			this.velocity.subVectors( this.position, this.oldPosition );
+			this.oldPosition.copy( this.position );
 
 
-		this.position = this.target.getWorldPosition( this.position || new Vector3() );
-		this.velocity.subVectors( this.position, this.oldPosition );
-		this.oldPosition.copy( this.position );
+		}
 
 
 	}
 	}
 
 
-};
+	updateFrame( frame ) {
 
 
-VelocityNode.prototype.updateFrame = function ( frame ) {
+		this.updateFrameVelocity( frame );
 
 
-	this.updateFrameVelocity( frame );
+		switch ( this.params.type ) {
 
 
-	switch ( this.params.type ) {
+			case 'elastic':
 
 
-		case 'elastic':
+				// convert to real scale: 0 at 1 values
+				const deltaFps = frame.delta * ( this.params.fps || 60 );
 
 
-			// convert to real scale: 0 at 1 values
-			var deltaFps = frame.delta * ( this.params.fps || 60 );
+				const spring = Math.pow( this.params.spring, deltaFps ),
+					damping = Math.pow( this.params.damping, deltaFps );
 
 
-			var spring = Math.pow( this.params.spring, deltaFps ),
-				damping = Math.pow( this.params.damping, deltaFps );
+				// fix relative frame-rate
+				this.velocity.multiplyScalar( Math.exp( - this.params.damping * deltaFps ) );
 
 
-			// fix relative frame-rate
-			this.velocity.multiplyScalar( Math.exp( - this.params.damping * deltaFps ) );
+				// elastic
+				this.velocity.add( this.springVelocity );
+				this.velocity.add( this.speed.multiplyScalar( damping ).multiplyScalar( 1 - spring ) );
 
 
-			// elastic
-			this.velocity.add( this.springVelocity );
-			this.velocity.add( this.speed.multiplyScalar( damping ).multiplyScalar( 1 - spring ) );
+				// speed
+				this.speed.subVectors( this.velocity, this.lastVelocity );
 
 
-			// speed
-			this.speed.subVectors( this.velocity, this.lastVelocity );
+				// spring velocity
+				this.springVelocity.add( this.speed );
+				this.springVelocity.multiplyScalar( spring );
 
 
-			// spring velocity
-			this.springVelocity.add( this.speed );
-			this.springVelocity.multiplyScalar( spring );
+				// moment
+				this.moment.add( this.springVelocity );
 
 
-			// moment
-			this.moment.add( this.springVelocity );
+				// damping
+				this.moment.multiplyScalar( damping );
 
 
-			// damping
-			this.moment.multiplyScalar( damping );
+				this.lastVelocity.copy( this.velocity );
+				this.value.copy( this.moment );
 
 
-			this.lastVelocity.copy( this.velocity );
-			this.value.copy( this.moment );
+				break;
 
 
-			break;
+			default:
 
 
-		default:
+				this.value.copy( this.velocity );
 
 
-			this.value.copy( this.velocity );
+		}
 
 
 	}
 	}
 
 
-};
+	copy( source ) {
+
+		super.copy( source );
 
 
-VelocityNode.prototype.copy = function ( source ) {
+		if ( source.target ) this.setTarget( source.target );
 
 
-	Vector3Node.prototype.copy.call( this, source );
+		this.setParams( source.params );
 
 
-	if ( source.target ) this.setTarget( source.target );
+		return this;
 
 
-	this.setParams( source.params );
+	}
 
 
-	return this;
+	toJSON( meta ) {
 
 
-};
+		const data = super.toJSON( meta );
 
 
-VelocityNode.prototype.toJSON = function ( meta ) {
+		if ( this.target ) data.target = this.target.uuid;
 
 
-	var data = Vector3Node.prototype.toJSON.call( this, meta );
+		// clone params
+		data.params = JSON.parse( JSON.stringify( this.params ) );
 
 
-	if ( this.target ) data.target = this.target.uuid;
+		return data;
 
 
-	// clone params
-	data.params = JSON.parse( JSON.stringify( this.params ) );
+	}
 
 
-	return data;
+}
 
 
-};
+VelocityNode.prototype.nodeType = 'Velocity';
 
 
 export { VelocityNode };
 export { VelocityNode };