Skip to content

Commit 8a74698

Browse files
authored
TSL: Add active stack and improve "node block" support (#32109)
* add active stack and improve "node block" support * VarNode: Use `intent` for non-stack * update * fix sync set context value * simplification * simplification * Update RangeNode.js
1 parent ca2f49e commit 8a74698

File tree

6 files changed

+136
-46
lines changed

6 files changed

+136
-46
lines changed

src/nodes/core/NodeBuilder.js

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,13 +435,13 @@ class NodeBuilder {
435435
*/
436436
this.subBuildLayers = [];
437437

438+
438439
/**
439-
* The current stack of nodes.
440+
* The active stack nodes.
440441
*
441-
* @type {?StackNode}
442-
* @default null
442+
* @type {Array<StackNode>}
443443
*/
444-
this.currentStack = null;
444+
this.activeStacks = [];
445445

446446
/**
447447
* The current sub-build TSL function(Fn).
@@ -1605,6 +1605,58 @@ class NodeBuilder {
16051605

16061606
}
16071607

1608+
/**
1609+
* Adds an active stack to the internal stack.
1610+
*
1611+
* @param {StackNode} stack - The stack node to add.
1612+
*/
1613+
setActiveStack( stack ) {
1614+
1615+
this.activeStacks.push( stack );
1616+
1617+
}
1618+
1619+
/**
1620+
* Removes the active stack from the internal stack.
1621+
*
1622+
* @param {StackNode} stack - The stack node to remove.
1623+
*/
1624+
removeActiveStack( stack ) {
1625+
1626+
if ( this.activeStacks[ this.activeStacks.length - 1 ] === stack ) {
1627+
1628+
this.activeStacks.pop();
1629+
1630+
} else {
1631+
1632+
throw new Error( 'NodeBuilder: Invalid active stack removal.' );
1633+
1634+
}
1635+
1636+
}
1637+
1638+
/**
1639+
* Returns the active stack.
1640+
*
1641+
* @return {StackNode} The active stack.
1642+
*/
1643+
getActiveStack() {
1644+
1645+
return this.activeStacks[ this.activeStacks.length - 1 ];
1646+
1647+
}
1648+
1649+
/**
1650+
* Returns the base stack.
1651+
*
1652+
* @return {StackNode} The base stack.
1653+
*/
1654+
getBaseStack() {
1655+
1656+
return this.activeStacks[ 0 ];
1657+
1658+
}
1659+
16081660
/**
16091661
* Adds a stack node to the internal stack.
16101662
*

src/nodes/core/StackNode.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,11 @@ class StackNode extends Node {
289289

290290
build( builder, ...params ) {
291291

292-
const previousBuildStack = builder.currentStack;
293292
const previousStack = getCurrentStack();
294293

295294
setCurrentStack( this );
296295

297-
builder.currentStack = this;
296+
builder.setActiveStack( this );
298297

299298
const buildStage = builder.buildStage;
300299

@@ -312,6 +311,9 @@ class StackNode extends Node {
312311

313312
if ( buildStage === 'setup' ) {
314313

314+
const nodeData = builder.getDataFromNode( node );
315+
nodeData.stack = this;
316+
315317
node.build( builder );
316318

317319
} else if ( buildStage === 'analyze' ) {
@@ -351,7 +353,7 @@ class StackNode extends Node {
351353

352354
setCurrentStack( previousStack );
353355

354-
builder.currentStack = previousBuildStack;
356+
builder.removeActiveStack( this );
355357

356358
return result;
357359

src/nodes/core/VarNode.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Node from './Node.js';
2-
import { addMethodChaining, getCurrentStack, nodeProxy } from '../tsl/TSLCore.js';
2+
import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';
33
import { error } from '../../utils.js';
44

55
/**
@@ -179,9 +179,19 @@ class VarNode extends Node {
179179

180180
build( ...params ) {
181181

182-
if ( this.intent === true ) {
182+
const builder = params[ 0 ];
183+
184+
if ( this._hasStack( builder ) === false && builder.buildStage === 'setup' ) {
185+
186+
if ( builder.context.nodeLoop || builder.context.nodeBlock ) {
183187

184-
const builder = params[ 0 ];
188+
builder.getBaseStack().addToStack( this );
189+
190+
}
191+
192+
}
193+
194+
if ( this.intent === true ) {
185195

186196
if ( this.isAssign( builder ) !== true ) {
187197

@@ -262,6 +272,14 @@ class VarNode extends Node {
262272

263273
}
264274

275+
_hasStack( builder ) {
276+
277+
const nodeData = builder.getDataFromNode( this );
278+
279+
return nodeData.stack !== undefined;
280+
281+
}
282+
265283
}
266284

267285
export default VarNode;
@@ -313,12 +331,6 @@ export const Const = ( node, name = null ) => createVar( node, name, true ).toSt
313331
*/
314332
export const VarIntent = ( node ) => {
315333

316-
if ( getCurrentStack() === null ) {
317-
318-
return node;
319-
320-
}
321-
322334
return createVar( node ).setIntent( true ).toStack();
323335

324336
};

src/nodes/functions/VolumetricLightingModel.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class VolumetricLightingModel extends LightingModel {
3030

3131
start( builder ) {
3232

33-
const { material, context } = builder;
33+
const { material } = builder;
3434

3535
const startPos = property( 'vec3' );
3636
const endPos = property( 'vec3' );
@@ -79,13 +79,13 @@ class VolumetricLightingModel extends LightingModel {
7979

8080
linearDepthRay.assign( linearDepth( viewZToPerspectiveDepth( positionViewRay.z, cameraNear, cameraFar ) ) );
8181

82-
context.sceneDepthNode = linearDepth( material.depthNode ).toVar();
82+
builder.context.sceneDepthNode = linearDepth( material.depthNode ).toVar();
8383

8484
}
8585

86-
context.positionWorld = positionRay;
87-
context.shadowPositionWorld = positionRay;
88-
context.positionView = positionViewRay;
86+
builder.context.positionWorld = positionRay;
87+
builder.context.shadowPositionWorld = positionRay;
88+
builder.context.positionView = positionViewRay;
8989

9090
scatteringDensity.assign( 0 );
9191

src/nodes/geometry/RangeNode.js

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ class RangeNode extends Node {
6767
*/
6868
getVectorLength( builder ) {
6969

70-
const minLength = builder.getTypeLength( getValueType( this.minNode.value ) );
71-
const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) );
70+
const minNode = this.getConstNode( this.minNode );
71+
const maxNode = this.getConstNode( this.maxNode );
72+
73+
const minLength = builder.getTypeLength( getValueType( minNode.value ) );
74+
const maxLength = builder.getTypeLength( getValueType( maxNode.value ) );
7275

7376
return minLength > maxLength ? minLength : maxLength;
7477

@@ -86,6 +89,36 @@ class RangeNode extends Node {
8689

8790
}
8891

92+
/**
93+
* Returns a constant node from the given node by traversing it.
94+
*
95+
* @param {Node} node - The node to traverse.
96+
* @returns {Node} The constant node, if found.
97+
*/
98+
getConstNode( node ) {
99+
100+
let output = null;
101+
102+
node.traverse( n => {
103+
104+
if ( n.isConstNode === true ) {
105+
106+
output = n;
107+
108+
}
109+
110+
} );
111+
112+
if ( output === null ) {
113+
114+
throw new Error( 'THREE.TSL: No "ConstNode" found in node graph.' );
115+
116+
}
117+
118+
return output;
119+
120+
}
121+
89122
setup( builder ) {
90123

91124
const object = builder.object;
@@ -94,8 +127,11 @@ class RangeNode extends Node {
94127

95128
if ( object.count > 1 ) {
96129

97-
const minValue = this.minNode.value;
98-
const maxValue = this.maxNode.value;
130+
const minNode = this.getConstNode( this.minNode );
131+
const maxNode = this.getConstNode( this.maxNode );
132+
133+
const minValue = minNode.value;
134+
const maxValue = maxNode.value;
99135

100136
const minLength = builder.getTypeLength( getValueType( minValue ) );
101137
const maxLength = builder.getTypeLength( getValueType( maxValue ) );

src/nodes/utils/LoopNode.js

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class LoopNode extends Node {
5454
*/
5555
constructor( params = [] ) {
5656

57-
super();
57+
super( 'void' );
5858

5959
this.params = params;
6060

@@ -100,16 +100,20 @@ class LoopNode extends Node {
100100

101101
}
102102

103-
const stack = builder.addStack(); // TODO: cache() it
103+
const stack = builder.addStack();
104104

105-
properties.returnsNode = this.params[ this.params.length - 1 ]( inputs, builder );
105+
const fnCall = this.params[ this.params.length - 1 ]( inputs );
106+
107+
properties.returnsNode = fnCall.context( { nodeLoop: fnCall } );
106108
properties.stackNode = stack;
107109

108110
const baseParam = this.params[ 0 ];
109111

110112
if ( baseParam.isNode !== true && typeof baseParam.update === 'function' ) {
111113

112-
properties.updateNode = Fn( this.params[ 0 ].update )( inputs );
114+
const fnUpdateCall = Fn( this.params[ 0 ].update )( inputs );
115+
116+
properties.updateNode = fnUpdateCall.context( { nodeLoop: fnUpdateCall } );
113117

114118
}
115119

@@ -119,20 +123,6 @@ class LoopNode extends Node {
119123

120124
}
121125

122-
/**
123-
* This method is overwritten since the node type is inferred based on the loop configuration.
124-
*
125-
* @param {NodeBuilder} builder - The current node builder.
126-
* @return {string} The node type.
127-
*/
128-
getNodeType( builder ) {
129-
130-
const { returnsNode } = this.getProperties( builder );
131-
132-
return returnsNode ? returnsNode.getNodeType( builder ) : 'void';
133-
134-
}
135-
136126
setup( builder ) {
137127

138128
// setup properties
@@ -312,7 +302,7 @@ class LoopNode extends Node {
312302

313303
const stackSnippet = stackNode.build( builder, 'void' );
314304

315-
const returnsSnippet = properties.returnsNode ? properties.returnsNode.build( builder ) : '';
305+
properties.returnsNode.build( builder, 'void' );
316306

317307
builder.removeFlowTab().addFlowCode( '\n' + builder.tab + stackSnippet );
318308

@@ -324,8 +314,6 @@ class LoopNode extends Node {
324314

325315
builder.addFlowTab();
326316

327-
return returnsSnippet;
328-
329317
}
330318

331319
}

0 commit comments

Comments
 (0)