Browse Source

NodeMaterial: updates (#23600)

* cleanup vec3 conversion

* fix PreviewEditor using WebGL in WebGPU

* uses .lightNode only in MeshStandardNodeMaterial

* cleanup

* use class declaration based

* cleanup

* share texture uniform when sampling texture multiple times
sunag 3 years ago
parent
commit
62c6fabc5e

+ 100 - 100
examples/jsm/nodes/ShaderNode.js

@@ -34,7 +34,7 @@ const NodeHandler = {
 
 		const inputs = params.shift();
 
-		return NodeClosure( ShaderNodeObjects( inputs ), ...params );
+		return NodeClosure( new ShaderNodeObjects( inputs ), ...params );
 
 	},
 
@@ -52,13 +52,13 @@ const NodeHandler = {
 					.replace( /b|p/g, 'z' )
 					.replace( /a|q/g, 'w' );
 
-				return ShaderNodeObject( new SplitNode( node, prop ) );
+				return new ShaderNodeObject( new SplitNode( node, prop ) );
 
 			} else if ( /^\d+$/.test( prop ) === true ) {
 
 				// accessing array
 
-				return ShaderNodeObject( new ArrayElementNode( node, new FloatNode( Number( prop ) ).setConst( true ) ) );
+				return new ShaderNodeObject( new ArrayElementNode( node, new FloatNode( Number( prop ) ).setConst( true ) ) );
 
 			}
 
@@ -72,13 +72,13 @@ const NodeHandler = {
 
 const nodeObjects = new WeakMap();
 
-const ShaderNodeObject = ( obj ) => {
+const ShaderNodeObject = function( obj ) {
 
 	const type = typeof obj;
 
 	if ( type === 'number' ) {
 
-		return ShaderNodeObject( new FloatNode( obj ).setConst( true ) );
+		return new ShaderNodeObject( new FloatNode( obj ).setConst( true ) );
 
 	} else if ( type === 'object' ) {
 
@@ -103,11 +103,11 @@ const ShaderNodeObject = ( obj ) => {
 
 };
 
-const ShaderNodeObjects = ( objects ) => {
+const ShaderNodeObjects = function( objects ) {
 
 	for ( const name in objects ) {
 
-		objects[ name ] = ShaderNodeObject( objects[ name ] );
+		objects[ name ] = new ShaderNodeObject( objects[ name ] );
 
 	}
 
@@ -115,13 +115,13 @@ const ShaderNodeObjects = ( objects ) => {
 
 };
 
-const ShaderNodeArray = ( array ) => {
+const ShaderNodeArray = function( array ) {
 
 	const len = array.length;
 
 	for ( let i = 0; i < len; i ++ ) {
 
-		array[ i ] = ShaderNodeObject( array[ i ] );
+		array[ i ] = new ShaderNodeObject( array[ i ] );
 
 	}
 
@@ -129,13 +129,13 @@ const ShaderNodeArray = ( array ) => {
 
 };
 
-const ShaderNodeProxy = ( NodeClass, scope = null, factor = null ) => {
+const ShaderNodeProxy = function( NodeClass, scope = null, factor = null ) {
 
 	if ( scope === null ) {
 
 		return ( ...params ) => {
 
-			return ShaderNodeObject( new NodeClass( ...ShaderNodeArray( params ) ) );
+			return new ShaderNodeObject( new NodeClass( ...ShaderNodeArray( params ) ) );
 
 		};
 
@@ -143,17 +143,17 @@ const ShaderNodeProxy = ( NodeClass, scope = null, factor = null ) => {
 
 		return ( ...params ) => {
 
-			return ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ) ) );
+			return new ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ) ) );
 
 		};
 
 	} else {
 
-		factor = ShaderNodeObject( factor );
+		factor = new ShaderNodeObject( factor );
 
 		return ( ...params ) => {
 
-			return ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ), factor ) );
+			return new ShaderNodeObject( new NodeClass( scope, ...ShaderNodeArray( params ), factor ) );
 
 		};
 
@@ -165,9 +165,9 @@ const ShaderNodeScript = function ( jsFunc ) {
 
 	return ( inputs, builder ) => {
 
-		ShaderNodeObjects( inputs );
+		new ShaderNodeObjects( inputs );
 
-		return ShaderNodeObject( jsFunc( inputs, builder ) );
+		return new ShaderNodeObject( jsFunc( inputs, builder ) );
 
 	};
 
@@ -189,7 +189,7 @@ export const uniform = new ShaderNode( ( inputNode ) => {
 
 export const nodeObject = ( val ) => {
 
-	return ShaderNodeObject( val );
+	return new ShaderNodeObject( val );
 
 };
 
@@ -315,38 +315,38 @@ export const addTo = ( varNode, ...params ) => {
 
 };
 
-export const add = ShaderNodeProxy( OperatorNode, '+' );
-export const sub = ShaderNodeProxy( OperatorNode, '-' );
-export const mul = ShaderNodeProxy( OperatorNode, '*' );
-export const div = ShaderNodeProxy( OperatorNode, '/' );
-export const remainder = ShaderNodeProxy( OperatorNode, '%' );
-export const equal = ShaderNodeProxy( OperatorNode, '==' );
-export const assign = ShaderNodeProxy( OperatorNode, '=' );
-export const lessThan = ShaderNodeProxy( OperatorNode, '<' );
-export const greaterThan = ShaderNodeProxy( OperatorNode, '>' );
-export const lessThanEqual = ShaderNodeProxy( OperatorNode, '<=' );
-export const greaterThanEqual = ShaderNodeProxy( OperatorNode, '>=' );
-export const and = ShaderNodeProxy( OperatorNode, '&&' );
-export const or = ShaderNodeProxy( OperatorNode, '||' );
-export const xor = ShaderNodeProxy( OperatorNode, '^^' );
-export const bitAnd = ShaderNodeProxy( OperatorNode, '&' );
-export const bitOr = ShaderNodeProxy( OperatorNode, '|' );
-export const bitXor = ShaderNodeProxy( OperatorNode, '^' );
-export const shiftLeft = ShaderNodeProxy( OperatorNode, '<<' );
-export const shiftRight = ShaderNodeProxy( OperatorNode, '>>' );
-
-export const element = ShaderNodeProxy( ArrayElementNode );
-
-export const normalGeometry = ShaderNodeObject( new NormalNode( NormalNode.GEOMETRY ) );
-export const normalLocal = ShaderNodeObject( new NormalNode( NormalNode.LOCAL ) );
-export const normalWorld = ShaderNodeObject( new NormalNode( NormalNode.WORLD ) );
-export const normalView = ShaderNodeObject( new NormalNode( NormalNode.VIEW ) );
-export const transformedNormalView = ShaderNodeObject( new VarNode( new NormalNode( NormalNode.VIEW ), 'TransformedNormalView', 'vec3' ) );
-
-export const positionLocal = ShaderNodeObject( new PositionNode( PositionNode.LOCAL ) );
-export const positionWorld = ShaderNodeObject( new PositionNode( PositionNode.WORLD ) );
-export const positionView = ShaderNodeObject( new PositionNode( PositionNode.VIEW ) );
-export const positionViewDirection = ShaderNodeObject( new PositionNode( PositionNode.VIEW_DIRECTION ) );
+export const add = new ShaderNodeProxy( OperatorNode, '+' );
+export const sub = new ShaderNodeProxy( OperatorNode, '-' );
+export const mul = new ShaderNodeProxy( OperatorNode, '*' );
+export const div = new ShaderNodeProxy( OperatorNode, '/' );
+export const remainder = new ShaderNodeProxy( OperatorNode, '%' );
+export const equal = new ShaderNodeProxy( OperatorNode, '==' );
+export const assign = new ShaderNodeProxy( OperatorNode, '=' );
+export const lessThan = new ShaderNodeProxy( OperatorNode, '<' );
+export const greaterThan = new ShaderNodeProxy( OperatorNode, '>' );
+export const lessThanEqual = new ShaderNodeProxy( OperatorNode, '<=' );
+export const greaterThanEqual = new ShaderNodeProxy( OperatorNode, '>=' );
+export const and = new ShaderNodeProxy( OperatorNode, '&&' );
+export const or = new ShaderNodeProxy( OperatorNode, '||' );
+export const xor = new ShaderNodeProxy( OperatorNode, '^^' );
+export const bitAnd = new ShaderNodeProxy( OperatorNode, '&' );
+export const bitOr = new ShaderNodeProxy( OperatorNode, '|' );
+export const bitXor = new ShaderNodeProxy( OperatorNode, '^' );
+export const shiftLeft = new ShaderNodeProxy( OperatorNode, '<<' );
+export const shiftRight = new ShaderNodeProxy( OperatorNode, '>>' );
+
+export const element = new ShaderNodeProxy( ArrayElementNode );
+
+export const normalGeometry = new ShaderNodeObject( new NormalNode( NormalNode.GEOMETRY ) );
+export const normalLocal = new ShaderNodeObject( new NormalNode( NormalNode.LOCAL ) );
+export const normalWorld = new ShaderNodeObject( new NormalNode( NormalNode.WORLD ) );
+export const normalView = new ShaderNodeObject( new NormalNode( NormalNode.VIEW ) );
+export const transformedNormalView = new ShaderNodeObject( new VarNode( new NormalNode( NormalNode.VIEW ), 'TransformedNormalView', 'vec3' ) );
+
+export const positionLocal = new ShaderNodeObject( new PositionNode( PositionNode.LOCAL ) );
+export const positionWorld = new ShaderNodeObject( new PositionNode( PositionNode.WORLD ) );
+export const positionView = new ShaderNodeObject( new PositionNode( PositionNode.VIEW ) );
+export const positionViewDirection = new ShaderNodeObject( new PositionNode( PositionNode.VIEW_DIRECTION ) );
 
 export const PI = float( 3.141592653589793 );
 export const PI2 = float( 6.283185307179586 );
@@ -355,54 +355,54 @@ export const RECIPROCAL_PI = float( 0.3183098861837907 );
 export const RECIPROCAL_PI2 = float( 0.15915494309189535 );
 export const EPSILON = float( 1e-6 );
 
-export const diffuseColor = ShaderNodeObject( new PropertyNode( 'DiffuseColor', 'vec4' ) );
-export const roughness = ShaderNodeObject( new PropertyNode( 'Roughness', 'float' ) );
-export const metalness = ShaderNodeObject( new PropertyNode( 'Metalness', 'float' ) );
-export const alphaTest = ShaderNodeObject( new PropertyNode( 'AlphaTest', 'float' ) );
-export const specularColor = ShaderNodeObject( new PropertyNode( 'SpecularColor', 'color' ) );
-
-export const abs = ShaderNodeProxy( MathNode, 'abs' );
-export const acos = ShaderNodeProxy( MathNode, 'acos' );
-export const asin = ShaderNodeProxy( MathNode, 'asin' );
-export const atan = ShaderNodeProxy( MathNode, 'atan' );
-export const ceil = ShaderNodeProxy( MathNode, 'ceil' );
-export const clamp = ShaderNodeProxy( MathNode, 'clamp' );
-export const cos = ShaderNodeProxy( MathNode, 'cos' );
-export const cross = ShaderNodeProxy( MathNode, 'cross' );
-export const degrees = ShaderNodeProxy( MathNode, 'degrees' );
-export const dFdx = ShaderNodeProxy( MathNode, 'dFdx' );
-export const dFdy = ShaderNodeProxy( MathNode, 'dFdy' );
-export const distance = ShaderNodeProxy( MathNode, 'distance' );
-export const dot = ShaderNodeProxy( MathNode, 'dot' );
-export const exp = ShaderNodeProxy( MathNode, 'exp' );
-export const exp2 = ShaderNodeProxy( MathNode, 'exp2' );
-export const faceforward = ShaderNodeProxy( MathNode, 'faceforward' );
-export const floor = ShaderNodeProxy( MathNode, 'floor' );
-export const fract = ShaderNodeProxy( MathNode, 'fract' );
-export const invert = ShaderNodeProxy( MathNode, 'invert' );
-export const inversesqrt = ShaderNodeProxy( MathNode, 'inversesqrt' );
-export const length = ShaderNodeProxy( MathNode, 'length' );
-export const log = ShaderNodeProxy( MathNode, 'log' );
-export const log2 = ShaderNodeProxy( MathNode, 'log2' );
-export const max = ShaderNodeProxy( MathNode, 'max' );
-export const min = ShaderNodeProxy( MathNode, 'min' );
-export const mix = ShaderNodeProxy( MathNode, 'mix' );
-export const mod = ShaderNodeProxy( MathNode, 'mod' );
-export const negate = ShaderNodeProxy( MathNode, 'negate' );
-export const normalize = ShaderNodeProxy( MathNode, 'normalize' );
-export const pow = ShaderNodeProxy( MathNode, 'pow' );
-export const pow2 = ShaderNodeProxy( MathNode, 'pow', 2 );
-export const pow3 = ShaderNodeProxy( MathNode, 'pow', 3 );
-export const pow4 = ShaderNodeProxy( MathNode, 'pow', 4 );
-export const radians = ShaderNodeProxy( MathNode, 'radians' );
-export const reflect = ShaderNodeProxy( MathNode, 'reflect' );
-export const refract = ShaderNodeProxy( MathNode, 'refract' );
-export const round = ShaderNodeProxy( MathNode, 'round' );
-export const saturate = ShaderNodeProxy( MathNode, 'saturate' );
-export const sign = ShaderNodeProxy( MathNode, 'sign' );
-export const sin = ShaderNodeProxy( MathNode, 'sin' );
-export const smoothstep = ShaderNodeProxy( MathNode, 'smoothstep' );
-export const sqrt = ShaderNodeProxy( MathNode, 'sqrt' );
-export const step = ShaderNodeProxy( MathNode, 'step' );
-export const tan = ShaderNodeProxy( MathNode, 'tan' );
-export const transformDirection = ShaderNodeProxy( MathNode, 'transformDirection' );
+export const diffuseColor = new ShaderNodeObject( new PropertyNode( 'DiffuseColor', 'vec4' ) );
+export const roughness = new ShaderNodeObject( new PropertyNode( 'Roughness', 'float' ) );
+export const metalness = new ShaderNodeObject( new PropertyNode( 'Metalness', 'float' ) );
+export const alphaTest = new ShaderNodeObject( new PropertyNode( 'AlphaTest', 'float' ) );
+export const specularColor = new ShaderNodeObject( new PropertyNode( 'SpecularColor', 'color' ) );
+
+export const abs = new ShaderNodeProxy( MathNode, 'abs' );
+export const acos = new ShaderNodeProxy( MathNode, 'acos' );
+export const asin = new ShaderNodeProxy( MathNode, 'asin' );
+export const atan = new ShaderNodeProxy( MathNode, 'atan' );
+export const ceil = new ShaderNodeProxy( MathNode, 'ceil' );
+export const clamp = new ShaderNodeProxy( MathNode, 'clamp' );
+export const cos = new ShaderNodeProxy( MathNode, 'cos' );
+export const cross = new ShaderNodeProxy( MathNode, 'cross' );
+export const degrees = new ShaderNodeProxy( MathNode, 'degrees' );
+export const dFdx = new ShaderNodeProxy( MathNode, 'dFdx' );
+export const dFdy = new ShaderNodeProxy( MathNode, 'dFdy' );
+export const distance = new ShaderNodeProxy( MathNode, 'distance' );
+export const dot = new ShaderNodeProxy( MathNode, 'dot' );
+export const exp = new ShaderNodeProxy( MathNode, 'exp' );
+export const exp2 = new ShaderNodeProxy( MathNode, 'exp2' );
+export const faceforward = new ShaderNodeProxy( MathNode, 'faceforward' );
+export const floor = new ShaderNodeProxy( MathNode, 'floor' );
+export const fract = new ShaderNodeProxy( MathNode, 'fract' );
+export const invert = new ShaderNodeProxy( MathNode, 'invert' );
+export const inversesqrt = new ShaderNodeProxy( MathNode, 'inversesqrt' );
+export const length = new ShaderNodeProxy( MathNode, 'length' );
+export const log = new ShaderNodeProxy( MathNode, 'log' );
+export const log2 = new ShaderNodeProxy( MathNode, 'log2' );
+export const max = new ShaderNodeProxy( MathNode, 'max' );
+export const min = new ShaderNodeProxy( MathNode, 'min' );
+export const mix = new ShaderNodeProxy( MathNode, 'mix' );
+export const mod = new ShaderNodeProxy( MathNode, 'mod' );
+export const negate = new ShaderNodeProxy( MathNode, 'negate' );
+export const normalize = new ShaderNodeProxy( MathNode, 'normalize' );
+export const pow = new ShaderNodeProxy( MathNode, 'pow' );
+export const pow2 = new ShaderNodeProxy( MathNode, 'pow', 2 );
+export const pow3 = new ShaderNodeProxy( MathNode, 'pow', 3 );
+export const pow4 = new ShaderNodeProxy( MathNode, 'pow', 4 );
+export const radians = new ShaderNodeProxy( MathNode, 'radians' );
+export const reflect = new ShaderNodeProxy( MathNode, 'reflect' );
+export const refract = new ShaderNodeProxy( MathNode, 'refract' );
+export const round = new ShaderNodeProxy( MathNode, 'round' );
+export const saturate = new ShaderNodeProxy( MathNode, 'saturate' );
+export const sign = new ShaderNodeProxy( MathNode, 'sign' );
+export const sin = new ShaderNodeProxy( MathNode, 'sin' );
+export const smoothstep = new ShaderNodeProxy( MathNode, 'smoothstep' );
+export const sqrt = new ShaderNodeProxy( MathNode, 'sqrt' );
+export const step = new ShaderNodeProxy( MathNode, 'step' );
+export const tan = new ShaderNodeProxy( MathNode, 'tan' );
+export const transformDirection = new ShaderNodeProxy( MathNode, 'transformDirection' );

+ 20 - 2
examples/jsm/nodes/core/InputNode.js

@@ -32,6 +32,12 @@ class InputNode extends Node {
 
 	}
 
+	getInputHash( builder ) {
+
+		return this.getHash( builder );
+
+	}
+
 	generateConst( builder ) {
 
 		return builder.getConst( this.getNodeType( builder ), this.value );
@@ -48,9 +54,21 @@ class InputNode extends Node {
 
 		} else {
 
-			const inputType = this.getInputType( builder );
+			const inputHash = this.getInputHash( builder );
+
+			let sharedNode = builder.getNodeFromHash( inputHash );
+
+			if ( sharedNode === undefined ) {
+
+				builder.setHashNode( this, inputHash );
+
+				sharedNode = this;
+
+			}
+
+			const inputType = sharedNode.getInputType( builder );
 
-			const nodeUniform = builder.getUniformFromNode( this, builder.shaderStage, inputType );
+			const nodeUniform = builder.getUniformFromNode( sharedNode, builder.shaderStage, inputType );
 			const propertyName = builder.getPropertyName( nodeUniform );
 
 			return builder.format( propertyName, type, output );

+ 7 - 1
examples/jsm/nodes/core/NodeBuilder.js

@@ -76,6 +76,12 @@ class NodeBuilder {
 
 	}
 
+	setHashNode( node, hash ) {
+
+		this.hashNodes[ hash ] = node;
+
+	}
+
 	addNode( node ) {
 
 		if ( this.nodes.indexOf( node ) === - 1 ) {
@@ -90,7 +96,7 @@ class NodeBuilder {
 
 			this.nodes.push( node );
 
-			this.hashNodes[ node.getHash( this ) ] = node;
+			this.setHashNode( node, node.getHash( this ) );
 
 		}
 

+ 6 - 0
examples/jsm/nodes/inputs/TextureNode.js

@@ -13,6 +13,12 @@ class TextureNode extends InputNode {
 
 	}
 
+	getInputHash( /*builder*/ ) {
+
+		return this.value.uuid;
+
+	}
+
 	generate( builder, output ) {
 
 		const texture = this.value;

+ 1 - 1
examples/jsm/nodes/materials/LineBasicNodeMaterial.js

@@ -41,6 +41,6 @@ class LineBasicNodeMaterial extends NodeMaterial {
 
 }
 
-LineBasicNodeMaterial.prototype.isNodeMaterial = true;
+LineBasicNodeMaterial.prototype.isLineBasicNodeMaterial = true;
 
 export default LineBasicNodeMaterial;

+ 3 - 1
examples/jsm/nodes/materials/MeshBasicNodeMaterial.js

@@ -9,6 +9,8 @@ class MeshBasicNodeMaterial extends NodeMaterial {
 
 		super();
 
+		this.lights = true;
+
 		this.colorNode = null;
 		this.opacityNode = null;
 
@@ -41,6 +43,6 @@ class MeshBasicNodeMaterial extends NodeMaterial {
 
 }
 
-MeshBasicNodeMaterial.prototype.isNodeMaterial = true;
+MeshBasicNodeMaterial.prototype.isMeshBasicNodeMaterial = true;
 
 export default MeshBasicNodeMaterial;

+ 1 - 1
examples/jsm/nodes/materials/MeshStandardNodeMaterial.js

@@ -65,4 +65,4 @@ export default class MeshStandardNodeMaterial extends NodeMaterial {
 
 }
 
-MeshStandardNodeMaterial.prototype.isNodeMaterial = true;
+MeshStandardNodeMaterial.prototype.isMeshStandardNodeMaterial = true;

+ 3 - 1
examples/jsm/nodes/materials/PointsNodeMaterial.js

@@ -9,6 +9,8 @@ class PointsNodeMaterial extends NodeMaterial {
 
 		super();
 
+		this.transparent = true;
+
 		this.colorNode = null;
 		this.opacityNode = null;
 
@@ -45,6 +47,6 @@ class PointsNodeMaterial extends NodeMaterial {
 
 }
 
-PointsNodeMaterial.prototype.isNodeMaterial = true;
+PointsNodeMaterial.prototype.isPointsNodeMaterial = true;
 
 export default PointsNodeMaterial;

+ 3 - 3
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -25,7 +25,7 @@ import ColorSpaceNode from 'three-nodes/display/ColorSpaceNode.js';
 import LightContextNode from 'three-nodes/lights/LightContextNode.js';
 import OperatorNode from 'three-nodes/math/OperatorNode.js';
 import WGSLNodeParser from 'three-nodes/parsers/WGSLNodeParser.js';
-import { add, join, nodeObject } from 'three-nodes/ShaderNode.js';
+import { vec3, add, join, nodeObject } from 'three-nodes/ShaderNode.js';
 import { getRoughness } from 'three-nodes/functions/PhysicalMaterialFunctions.js';
 
 const wgslTypeLib = {
@@ -266,7 +266,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 			// OUTGOING LIGHT
 
-			let outgoingLightNode = nodeObject( outputNode ).xyz;
+			let outgoingLightNode = vec3( outputNode );
 
 			// EMISSIVE
 
@@ -278,7 +278,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 			}
 
-			outputNode = join( outgoingLightNode.xyz, nodeObject( diffuseColorNode ).w );
+			outputNode = join( vec3( outgoingLightNode ), nodeObject( diffuseColorNode ).w );
 
 			// OUTPUT
 

+ 6 - 1
examples/webgpu_nodes_playground.html

@@ -67,6 +67,9 @@
 			import { OrbitControls } from './jsm/controls/OrbitControls.js';
 			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
 
+			// Use PreviewEditor in WebGL for now
+			import { nodeFrame } from './jsm/renderers/webgl/nodes/WebGLNodes.js';
+
 			let stats;
 			let camera, scene, renderer;
 			let model;
@@ -146,7 +149,7 @@
 
 					const node = e.node;
 
-					if ( node.value !== null && node.value.isMaterial === true ) {
+					if ( node.value !== null && node.value.isMeshStandardNodeMaterial === true ) {
 
 						const material = node.value;
 
@@ -215,6 +218,8 @@
 
 				requestAnimationFrame( animate );
 
+				nodeFrame.update();
+
 				render();
 
 				stats.update();

+ 2 - 1
examples/webgpu_skinning.html

@@ -28,6 +28,7 @@
 		<script type="module">
 
 			import * as THREE from 'three';
+			import * as Nodes from 'three-nodes/Nodes.js';
 
 			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
 
@@ -80,7 +81,7 @@
 
 						if ( child.isMesh ) {
 
-							child.material = new THREE.MeshStandardMaterial();
+							child.material = new Nodes.MeshStandardNodeMaterial();
 							child.material.lightNode = lightNode;
 
 						}