Просмотр исходного кода

Nodes: Define `stack.assign()` as default. (#26881)

* Nodes: Define `stack.assign()` as default.

* fix name
sunag 1 год назад
Родитель
Сommit
9480ccd1ee

+ 1 - 1
examples/jsm/nodes/Nodes.js

@@ -14,6 +14,7 @@ export { default as ContextNode, context, label } from './core/ContextNode.js';
 export { default as IndexNode, vertexIndex, instanceIndex } from './core/IndexNode.js';
 export { default as LightingModel } from './core/LightingModel.js';
 export { default as Node, addNodeClass, createNodeFromType } from './core/Node.js';
+export { default as VarNode, temp } from './core/VarNode.js';
 export { default as NodeAttribute } from './core/NodeAttribute.js';
 export { default as NodeBuilder } from './core/NodeBuilder.js';
 export { default as NodeCache } from './core/NodeCache.js';
@@ -28,7 +29,6 @@ export { default as PropertyNode, property, output, diffuseColor, roughness, met
 export { default as StackNode, stack } from './core/StackNode.js';
 export { default as TempNode } from './core/TempNode.js';
 export { default as UniformNode, uniform } from './core/UniformNode.js';
-export { default as VarNode, temp } from './core/VarNode.js';
 export { default as VaryingNode, varying } from './core/VaryingNode.js';
 export { default as OutputStructNode, outputStruct } from './core/OutputStructNode.js';
 

+ 1 - 2
examples/jsm/nodes/accessors/ModelNode.js

@@ -1,6 +1,5 @@
 import Object3DNode from './Object3DNode.js';
 import { addNodeClass } from '../core/Node.js';
-import { label } from '../core/ContextNode.js';
 import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class ModelNode extends Object3DNode {
@@ -24,7 +23,7 @@ class ModelNode extends Object3DNode {
 export default ModelNode;
 
 export const modelDirection = nodeImmutable( ModelNode, ModelNode.DIRECTION );
-export const modelViewMatrix = label( nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX ), 'modelViewMatrix' );
+export const modelViewMatrix = nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX ).temp( 'ModelViewMatrix' );
 export const modelNormalMatrix = nodeImmutable( ModelNode, ModelNode.NORMAL_MATRIX );
 export const modelWorldMatrix = nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX );
 export const modelPosition = nodeImmutable( ModelNode, ModelNode.POSITION );

+ 1 - 1
examples/jsm/nodes/accessors/NormalNode.js

@@ -86,7 +86,7 @@ NormalNode.WORLD = 'world';
 export default NormalNode;
 
 export const normalGeometry = nodeImmutable( NormalNode, NormalNode.GEOMETRY );
-export const normalLocal = nodeImmutable( NormalNode, NormalNode.LOCAL );
+export const normalLocal = nodeImmutable( NormalNode, NormalNode.LOCAL ).temp( 'Normal' );
 export const normalView = nodeImmutable( NormalNode, NormalNode.VIEW );
 export const normalWorld = nodeImmutable( NormalNode, NormalNode.WORLD );
 export const transformedNormalView = property( 'vec3', 'TransformedNormalView' );

+ 1 - 1
examples/jsm/nodes/accessors/PositionNode.js

@@ -95,7 +95,7 @@ PositionNode.VIEW_DIRECTION = 'viewDirection';
 export default PositionNode;
 
 export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY );
-export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL );
+export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL ).temp( 'Position' );
 export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD );
 export const positionWorldDirection = nodeImmutable( PositionNode, PositionNode.WORLD_DIRECTION );
 export const positionView = nodeImmutable( PositionNode, PositionNode.VIEW );

+ 3 - 1
examples/jsm/nodes/core/LightingModel.js

@@ -1,6 +1,8 @@
 class LightingModel {
 
-	init( /*input, stack, builder*/ ) { }
+	start( /*input, stack, builder*/ ) { }
+
+	finish( /*input, stack, builder*/ ) { }
 
 	direct( /*input, stack, builder*/ ) { }
 

+ 2 - 0
examples/jsm/nodes/core/PropertyNode.js

@@ -9,6 +9,8 @@ class PropertyNode extends Node {
 
 		this.name = name;
 
+		this.isPropertyNode = true;
+
 	}
 
 	getHash( builder ) {

+ 19 - 1
examples/jsm/nodes/core/StackNode.js

@@ -4,7 +4,8 @@ import { bypass } from '../core/BypassNode.js';
 import { expression } from '../code/ExpressionNode.js';
 import { cond } from '../math/CondNode.js';
 import { loop } from '../utils/LoopNode.js';
-import { ShaderNode, nodeProxy } from '../shadernode/ShaderNode.js';
+import SetNode from '../utils/SetNode.js';
+import { ShaderNode, nodeProxy, nodeObject } from '../shadernode/ShaderNode.js';
 
 class StackNode extends Node {
 
@@ -68,6 +69,23 @@ class StackNode extends Node {
 
 	assign( targetNode, sourceValue ) {
 
+		sourceValue = nodeObject( sourceValue );
+
+		if ( targetNode.isSplitNode ) {
+
+			sourceValue = new SetNode( targetNode.node, targetNode.components, sourceValue );
+			targetNode = targetNode.node;
+
+		}
+
+		if ( targetNode.isPropertyNode !== true && targetNode.isVarNode !== true && targetNode.isArrayElementNode !== true && targetNode.isVaryingNode !== true ) {
+
+			console.error( 'THREE.TSL: Invalid assign, target must be a property or variable.', targetNode.getSelf() );
+
+			//return this;
+
+		}
+
 		return this.add( assign( targetNode, sourceValue ) );
 
 	}

+ 2 - 23
examples/jsm/nodes/core/VarNode.js

@@ -10,21 +10,7 @@ class VarNode extends Node {
 		this.node = node;
 		this.name = name;
 
-	}
-
-	assign( node ) {
-
-		node.traverse( ( childNode, replaceNode ) => {
-
-			if ( replaceNode && childNode.uuid === this.uuid ) {
-
-				replaceNode( this.node );
-
-			}
-
-		} );
-		this.node = node;
-		return this;
+		this.isVarNode = true;
 
 	}
 
@@ -48,14 +34,7 @@ class VarNode extends Node {
 
 	generate( builder ) {
 
-		const node = this.node;
-		const name = this.name;
-
-		if ( name === null && node.isTempNode === true ) {
-
-			return node.build( builder );
-
-		}
+		const { node, name } = this;
 
 		const type = builder.getVectorType( this.getNodeType( builder ) );
 

+ 2 - 0
examples/jsm/nodes/core/VaryingNode.js

@@ -11,6 +11,8 @@ class VaryingNode extends Node {
 		this.node = node;
 		this.name = name;
 
+		this.isVaryingNode = true;
+
 	}
 
 	isGlobal() {

+ 5 - 5
examples/jsm/nodes/functions/PhongLightingModel.js

@@ -41,24 +41,24 @@ class PhongLightingModel extends LightingModel {
 
 	}
 
-	direct( { lightDirection, lightColor, reflectedLight } ) {
+	direct( { lightDirection, lightColor, reflectedLight }, stack ) {
 
 		const dotNL = transformedNormalView.dot( lightDirection ).clamp();
 		const irradiance = dotNL.mul( lightColor );
 
-		reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
+		stack.addAssign( reflectedLight.directDiffuse, irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
 
 		if ( this.specular === true ) {
 
-			reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_BlinnPhong( { lightDirection } ) ).mul( materialSpecularStrength ) );
+			stack.addAssign( reflectedLight.directSpecular, irradiance.mul( BRDF_BlinnPhong( { lightDirection } ) ).mul( materialSpecularStrength ) );
 
 		}
 
 	}
 
-	indirectDiffuse( { irradiance, reflectedLight } ) {
+	indirectDiffuse( { irradiance, reflectedLight }, stack ) {
 
-		reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
+		stack.addAssign( reflectedLight.indirectDiffuse, irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
 
 	}
 

+ 56 - 46
examples/jsm/nodes/functions/PhysicalLightingModel.js

@@ -177,38 +177,18 @@ class PhysicalLightingModel extends LightingModel {
 
 	}
 
-	init( { reflectedLight } ) {
+	start( /*context*/ ) {
 
 		if ( this.clearcoat === true ) {
 
-			this.clearcoatRadiance = vec3().temp();
-			this.clearcoatSpecular = vec3().temp();
-
-			const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
-
-			const Fcc = F_Schlick( {
-				dotVH: dotNVcc,
-				f0: clearcoatF0,
-				f90: clearcoatF90
-			} );
-
-			const outgoingLight = reflectedLight.total;
-			const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecular.mul( clearcoat ) );
-
-			outgoingLight.assign( clearcoatLight );
+			this.clearcoatRadiance = vec3().temp( 'clearcoatRadiance' );
+			this.clearcoatSpecular = vec3().temp( 'clearcoatSpecular' );
 
 		}
 
 		if ( this.sheen === true ) {
 
-			this.sheenSpecular = vec3().temp();
-
-			const outgoingLight = reflectedLight.total;
-
-			const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus();
-			const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecular );
-
-			outgoingLight.assign( sheenLight );
+			this.sheenSpecular = vec3().temp( 'sheenSpecular' );
 
 		}
 
@@ -227,7 +207,7 @@ class PhysicalLightingModel extends LightingModel {
 	// Approximates multiscattering in order to preserve energy.
 	// http://www.jcgt.org/published/0008/01/03/
 
-	computeMultiscattering( singleScatter, multiScatter, specularF90 = float( 1 ) ) {
+	computeMultiscattering( stack, singleScatter, multiScatter, specularF90 = float( 1 ) ) {
 
 		const fab = DFGApprox( { roughness } );
 
@@ -241,19 +221,19 @@ class PhysicalLightingModel extends LightingModel {
 		const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21
 		const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() );
 
-		singleScatter.addAssign( FssEss );
-		multiScatter.addAssign( Fms.mul( Ems ) );
+		stack.addAssign( singleScatter, FssEss );
+		stack.addAssign( multiScatter, Fms.mul( Ems ) );
 
 	}
 
-	direct( { lightDirection, lightColor, reflectedLight } ) {
+	direct( { lightDirection, lightColor, reflectedLight }, stack ) {
 
 		const dotNL = transformedNormalView.dot( lightDirection ).clamp();
 		const irradiance = dotNL.mul( lightColor );
 
 		if ( this.sheen === true ) {
 
-			this.sheenSpecular.addAssign( irradiance.mul( BRDF_Sheen( { lightDirection } ) ) );
+			stack.addAssign( this.sheenSpecular, irradiance.mul( BRDF_Sheen( { lightDirection } ) ) );
 
 		}
 
@@ -262,27 +242,27 @@ class PhysicalLightingModel extends LightingModel {
 			const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp();
 			const ccIrradiance = dotNLcc.mul( lightColor );
 
-			this.clearcoatSpecular.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) );
+			stack.addAssign( this.clearcoatSpecular, ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) );
 
 		}
 
-		reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
+		stack.addAssign( reflectedLight.directDiffuse, irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
 
-		reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, iridescenceFresnel: this.iridescenceFresnel } ) ) );
+		stack.addAssign( reflectedLight.directSpecular, irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, iridescenceFresnel: this.iridescenceFresnel } ) ) );
 
 	}
 
-	indirectDiffuse( { irradiance, reflectedLight } ) {
+	indirectDiffuse( { irradiance, reflectedLight }, stack ) {
 
-		reflectedLight.indirectDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
+		stack.addAssign( reflectedLight.indirectDiffuse, irradiance.mul( BRDF_Lambert( { diffuseColor } ) ) );
 
 	}
 
-	indirectSpecular( { radiance, iblIrradiance, reflectedLight, } ) {
+	indirectSpecular( { radiance, iblIrradiance, reflectedLight }, stack ) {
 
 		if ( this.sheen === true ) {
 
-			this.sheenSpecular.addAssign( iblIrradiance.mul(
+			stack.addAssign( this.sheenSpecular, iblIrradiance.mul(
 				sheen,
 				IBLSheenBRDF( transformedNormalView, positionViewDirection, sheenRoughness )
 			) );
@@ -300,30 +280,30 @@ class PhysicalLightingModel extends LightingModel {
 				roughness: clearcoatRoughness
 			} );
 
-			this.clearcoatSpecular.addAssign( this.clearcoatRadiance.mul( clearcoatEnv ) );
+			stack.addAssign( this.clearcoatSpecular, this.clearcoatRadiance.mul( clearcoatEnv ) );
 
 		}
 
 		// Both indirect specular and indirect diffuse light accumulate here
 
-		const singleScattering = vec3().temp();
-		const multiScattering = vec3().temp();
+		const singleScattering = vec3().temp( 'singleScattering' );
+		const multiScattering = vec3().temp( 'multiScattering' );
 		const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
 
-		this.computeMultiscattering( singleScattering, multiScattering );
+		this.computeMultiscattering( stack, singleScattering, multiScattering );
 
 		const totalScattering = singleScattering.add( multiScattering );
 
 		const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() );
 
-		reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
-		reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );
+		stack.addAssign( reflectedLight.indirectSpecular, radiance.mul( singleScattering ) );
+		stack.addAssign( reflectedLight.indirectSpecular, multiScattering.mul( cosineWeightedIrradiance ) );
 
-		reflectedLight.indirectDiffuse.addAssign( diffuse.mul( cosineWeightedIrradiance ) );
+		stack.addAssign( reflectedLight.indirectDiffuse, diffuse.mul( cosineWeightedIrradiance ) );
 
 	}
 
-	ambientOcclusion( { ambientOcclusion, reflectedLight } ) {
+	ambientOcclusion( { ambientOcclusion, reflectedLight }, stack ) {
 
 		const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
 
@@ -332,9 +312,39 @@ class PhysicalLightingModel extends LightingModel {
 
 		const aoNode = ambientOcclusion.sub( aoNV.pow( aoExp ).oneMinus() ).clamp();
 
-		reflectedLight.indirectDiffuse.mulAssign( ambientOcclusion );
+		stack.mulAssign( reflectedLight.indirectDiffuse, ambientOcclusion );
+		stack.mulAssign( reflectedLight.indirectSpecular, aoNode );
+
+	}
+
+	finish( context, stack ) {
+
+		const { outgoingLight } = context;
+
+		if ( this.clearcoat === true ) {
+
+			const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
+
+			const Fcc = F_Schlick( {
+				dotVH: dotNVcc,
+				f0: clearcoatF0,
+				f90: clearcoatF90
+			} );
+
+			const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecular.mul( clearcoat ) );
 
-		reflectedLight.indirectSpecular.mulAssign( aoNode );
+			stack.assign( outgoingLight, clearcoatLight );
+
+		}
+
+		if ( this.sheen === true ) {
+
+			const sheenEnergyComp = sheen.r.max( sheen.g ).max( sheen.b ).mul( 0.157 ).oneMinus();
+			const sheenLight = outgoingLight.mul( sheenEnergyComp ).add( this.sheenSpecular );
+
+			stack.assign( outgoingLight, sheenLight );
+
+		}
 
 	}
 

+ 1 - 1
examples/jsm/nodes/lighting/AONode.js

@@ -16,7 +16,7 @@ class AONode extends LightingNode {
 		const aoIntensity = 1;
 		const aoNode = this.aoNode.x.sub( 1.0 ).mul( aoIntensity ).add( 1.0 );
 
-		builder.context.ambientOcclusion.mulAssign( aoNode );
+		builder.stack.mulAssign( builder.context.ambientOcclusion, aoNode );
 
 	}
 

+ 2 - 2
examples/jsm/nodes/lighting/AmbientLightNode.js

@@ -12,9 +12,9 @@ class AmbientLightNode extends AnalyticLightNode {
 
 	}
 
-	setup( { context } ) {
+	setup( builder ) {
 
-		context.irradiance.addAssign( this.colorNode );
+		builder.stack.addAssign( builder.context.irradiance, this.colorNode );
 
 	}
 

+ 1 - 1
examples/jsm/nodes/lighting/DirectionalLightNode.js

@@ -27,7 +27,7 @@ class DirectionalLightNode extends AnalyticLightNode {
 			lightDirection,
 			lightColor,
 			reflectedLight
-		} );
+		}, builder.stack, builder );
 
 	}
 

+ 5 - 9
examples/jsm/nodes/lighting/EnvironmentNode.js

@@ -27,7 +27,6 @@ class EnvironmentNode extends LightingNode {
 	setup( builder ) {
 
 		let envNode = this.envNode;
-		const properties = builder.getNodeProperties( this );
 
 		if ( envNode.isTextureNode && envNode.value.isCubeTexture !== true ) {
 
@@ -62,9 +61,11 @@ class EnvironmentNode extends LightingNode {
 
 		//
 
-		builder.context.radiance.addAssign( isolateRadiance );
+		const { stack } = builder;
 
-		builder.context.iblIrradiance.addAssign( irradiance );
+		stack.addAssign( builder.context.radiance, isolateRadiance );
+
+		stack.addAssign( builder.context.iblIrradiance, irradiance );
 
 		//
 
@@ -75,15 +76,10 @@ class EnvironmentNode extends LightingNode {
 			const clearcoatRadianceContext = context( envNode, createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity );
 			const isolateClearcoatRadiance = cache( clearcoatRadianceContext );
 
-			clearcoatRadiance.addAssign( isolateClearcoatRadiance );
+			stack.addAssign( clearcoatRadiance, isolateClearcoatRadiance );
 
 		}
 
-		//
-
-		properties.radiance = isolateRadiance;
-		properties.irradiance = irradiance;
-
 	}
 
 }

+ 21 - 57
examples/jsm/nodes/lighting/LightingContextNode.js

@@ -1,6 +1,4 @@
 import ContextNode from '../core/ContextNode.js';
-import { add } from '../math/OperatorNode.js';
-import { mix } from '../math/MathNode.js';
 import { addNodeClass } from '../core/Node.js';
 import { addNodeElement, nodeProxy, float, vec3 } from '../shadernode/ShaderNode.js';
 
@@ -14,80 +12,46 @@ class LightingContextNode extends ContextNode {
 		this.backdropNode = backdropNode;
 		this.backdropAlphaNode = backdropAlphaNode;
 
-	}
-
-	getNodeType( /*builder*/ ) {
-
-		return 'vec3';
+		this._context = null;
 
 	}
 
-	setup( builder ) {
-
-		const { lightingModel, backdropNode, backdropAlphaNode } = this;
-
-		const context = this.context = {}; // reset context
-		const properties = builder.getNodeProperties( this );
-
-		const directDiffuse = vec3().temp(),
-			directSpecular = vec3().temp(),
-			indirectDiffuse = vec3().temp(),
-			indirectSpecular = vec3().temp();
-
-		let totalDiffuse = add( directDiffuse, indirectDiffuse );
-
-		if ( backdropNode !== null ) {
-
-			totalDiffuse = vec3( backdropAlphaNode !== null ? mix( totalDiffuse, backdropNode, backdropAlphaNode ) : backdropNode );
+	getContext() {
 
-		}
+		const { backdropNode, backdropAlphaNode } = this;
 
-		const totalSpecular = add( directSpecular, indirectSpecular );
-		const total = add( totalDiffuse, totalSpecular ).temp();
+		const directDiffuse = vec3().temp( 'directDiffuse' ),
+			directSpecular = vec3().temp( 'directSpecular' ),
+			indirectDiffuse = vec3().temp( 'indirectDiffuse' ),
+			indirectSpecular = vec3().temp( 'indirectSpecular' );
 
 		const reflectedLight = {
 			directDiffuse,
 			directSpecular,
 			indirectDiffuse,
-			indirectSpecular,
-			total
+			indirectSpecular
 		};
 
-		const lighting = {
-			radiance: vec3().temp(),
-			irradiance: vec3().temp(),
-			iblIrradiance: vec3().temp(),
-			ambientOcclusion: float( 1 ).temp()
+		const context = {
+			radiance: vec3().temp( 'radiance' ),
+			irradiance: vec3().temp( 'irradiance' ),
+			iblIrradiance: vec3().temp( 'iblIrradiance' ),
+			ambientOcclusion: float( 1 ).temp( 'ambientOcclusion' ),
+			reflectedLight,
+			backdrop: backdropNode,
+			backdropAlpha : backdropAlphaNode
 		};
 
-		context.reflectedLight = reflectedLight;
-		context.lightingModel = lightingModel || context.lightingModel;
-
-		Object.assign( properties, reflectedLight, lighting );
-		Object.assign( context, lighting );
-
-		if ( lightingModel ) {
-
-			lightingModel.init( context, builder.stack, builder );
-
-			lightingModel.indirectDiffuse( context, builder.stack, builder );
-			lightingModel.indirectSpecular( context, builder.stack, builder );
-			lightingModel.ambientOcclusion( context, builder.stack, builder );
-
-		}
-
-		return super.setup( builder );
+		return context;
 
 	}
 
-	generate( builder ) {
-
-		const { context } = this;
-		const type = this.getNodeType( builder );
+	setup( builder ) {
 
-		super.generate( builder, type );
+		this.context = this._context || ( this._context = this.getContext() );
+		this.context.lightingModel = this.lightingModel || builder.context.lightingModel;
 
-		return context.reflectedLight.total.build( builder, type );
+		return super.setup( builder );
 
 	}
 

+ 62 - 4
examples/jsm/nodes/lighting/LightsNode.js

@@ -1,6 +1,6 @@
 import Node from '../core/Node.js';
 import AnalyticLightNode from './AnalyticLightNode.js';
-import { nodeObject, nodeProxy } from '../shadernode/ShaderNode.js';
+import { nodeObject, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
 
 const LightNodes = new WeakMap();
 
@@ -16,6 +16,11 @@ class LightsNode extends Node {
 
 		super( 'vec3' );
 
+		this.totalDiffuseNode = vec3().temp( 'totalDiffuse' );
+		this.totalSpecularNode = vec3().temp( 'totalSpecular' );
+
+		this.outgoingLightNode = vec3().temp( 'outgoingLight' );
+
 		this.lightNodes = lightNodes;
 
 		this._hash = null;
@@ -30,14 +35,67 @@ class LightsNode extends Node {
 
 	setup( builder ) {
 
-		const lightNodes = this.lightNodes;
+		const context = builder.context;
+		const lightingModel = context.lightingModel;
 
-		for ( const lightNode of lightNodes ) {
+		let outgoingLightNode = this.outgoingLightNode;
+
+		if ( lightingModel ) {
+
+			const { lightNodes, totalDiffuseNode, totalSpecularNode } = this;
+
+			context.outgoingLight = outgoingLightNode;
+
+			const stack = builder.addStack();
+
+			//
+
+			lightingModel.start( context, stack, builder );
+
+			// lights
+
+			for ( const lightNode of lightNodes ) {
+
+				lightNode.build( builder );
+	
+			}
 
-			lightNode.build( builder );
+			//
+
+			lightingModel.indirectDiffuse( context, stack, builder );
+			lightingModel.indirectSpecular( context, stack, builder );
+			lightingModel.ambientOcclusion( context, stack, builder );
+
+			//
+
+			const { backdrop, backdropAlpha } = context;
+			const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context.reflectedLight;
+
+			let totalDiffuse = directDiffuse.add( indirectDiffuse );
+
+			if ( backdrop !== null ) {
+
+				totalDiffuse = vec3( backdropAlpha !== null ? backdropAlpha.mix( totalDiffuse, backdrop ) : backdrop );
+	
+			}
+
+			stack.assign( totalDiffuseNode, totalDiffuse );
+			stack.assign( totalSpecularNode, directSpecular.add( indirectSpecular ) );
+
+			stack.assign( outgoingLightNode, totalDiffuseNode.add( totalSpecularNode ) );
+
+			//
+
+			lightingModel.finish( context, stack, builder );
+
+			//
+
+			outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() );
 
 		}
 
+		return outgoingLightNode;
+
 	}
 
 	getHash( builder ) {

+ 1 - 1
examples/jsm/nodes/lighting/PointLightNode.js

@@ -55,7 +55,7 @@ class PointLightNode extends AnalyticLightNode {
 			lightDirection,
 			lightColor,
 			reflectedLight
-		} );
+		}, builder.stack, builder );
 
 	}
 

+ 1 - 1
examples/jsm/nodes/lighting/SpotLightNode.js

@@ -76,7 +76,7 @@ class SpotLightNode extends AnalyticLightNode {
 			lightDirection,
 			lightColor,
 			reflectedLight
-		} );
+		}, builder.stack, builder );
 
 	}
 

+ 1 - 2
examples/jsm/nodes/materials/Line2NodeMaterial.js

@@ -84,7 +84,6 @@ class Line2NodeMaterial extends NodeMaterial {
 			stack.assign( start, modelViewMatrix.mul( vec4( instanceStart, 1.0 ) ) ); // force assignment into correct place in flow
 			stack.assign( end, modelViewMatrix.mul( vec4( instanceEnd, 1.0 ) ) );
 
-
 			if ( useWorldUnits ) {
 
 				stack.assign( varying( vec3(), 'worldStart' ), start.xyz );
@@ -124,7 +123,7 @@ class Line2NodeMaterial extends NodeMaterial {
 			const ndcEnd = clipEnd.xyz.div( clipEnd.w );
 
 			// direction
-			const dir = ndcEnd.xy.sub( ndcStart.xy );
+			const dir = ndcEnd.xy.sub( ndcStart.xy ).temp();
 
 			// account for clip-space aspect ratio
 			stack.assign( dir.x, dir.x.mul( aspect ) );

+ 1 - 1
examples/jsm/nodes/shadernode/ShaderNode.js

@@ -48,7 +48,7 @@ const shaderNodeHandler = {
 
 				const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) );
 
-				return ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) );
+				return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) );
 
 			} else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
 

+ 2 - 0
examples/jsm/nodes/utils/ArrayElementNode.js

@@ -9,6 +9,8 @@ class ArrayElementNode extends Node { // @TODO: If extending from TempNode it br
 		this.node = node;
 		this.indexNode = indexNode;
 
+		this.isArrayElementNode = true;
+
 	}
 
 	getNodeType( builder ) {

+ 2 - 0
examples/jsm/nodes/utils/SplitNode.js

@@ -12,6 +12,8 @@ class SplitNode extends Node {
 		this.node = node;
 		this.components = components;
 
+		this.isSplitNode = true;
+
 	}
 
 	getVectorLength() {

+ 1 - 1
examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js

@@ -584,7 +584,7 @@ class WGSLNodeBuilder extends NodeBuilder {
 
 					let attributesSnippet = `@location( ${index} )`;
 
-					if ( varying.type === 'int' || varying.type === 'uint' ) {
+					if ( /^(int|uint|ivec|uvec)/.test( varying.type ) ) {
 
 						attributesSnippet += ' @interpolate( flat )';
 

+ 1 - 1
examples/webgpu_compute_points.html

@@ -80,7 +80,7 @@
 					const pointer = uniform( pointerVector );
 					const limit = uniform( scaleVector );
 
-					const position = particle.add( velocity );
+					const position = particle.add( velocity ).temp();
 
 					stack.assign( velocity.x, position.x.abs().greaterThanEqual( limit.x ).cond( velocity.x.negate(), velocity.x ) );
 					stack.assign( velocity.y, position.y.abs().greaterThanEqual( limit.y ).cond( velocity.y.negate(), velocity.y ) );

+ 2 - 2
examples/webgpu_lights_custom.html

@@ -35,9 +35,9 @@
 
 			class CustomLightingModel extends LightingModel {
 
-				direct( { lightColor, reflectedLight } ) {
+				direct( { lightColor, reflectedLight }, stack ) {
 
-					reflectedLight.directDiffuse.addAssign( lightColor );
+					stack.addAssign( reflectedLight.directDiffuse, lightColor );
 
 				}