Skip to content

Commit 1388d16

Browse files
authored
TSL: Introduce automatic use of .toVar() to assign() (#31459)
* introduce automatic use of `.toVar()` to `assign()` * fix nodeObj return * move `builder.getArrayCount()` -> `node.getArrayCount()` * Update NodeBuilder.js * add `builder.flowBuildStage()` * add docs and rename `intention` -> `intent` * rename `nodeProxyIntention` -> `nodeProxyIntent` * Update VarNode.js * add `VarIntent` * Update NodeMaterial.js * improve setup check
1 parent a681a5f commit 1388d16

File tree

12 files changed

+294
-103
lines changed

12 files changed

+294
-103
lines changed

src/Three.TSL.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ export const uvec2 = TSL.uvec2;
519519
export const uvec3 = TSL.uvec3;
520520
export const uvec4 = TSL.uvec4;
521521
export const Var = TSL.Var;
522+
export const VarIntent = TSL.VarIntent;
522523
export const varying = TSL.varying;
523524
export const varyingProperty = TSL.varyingProperty;
524525
export const vec2 = TSL.vec2;

src/materials/nodes/NodeMaterial.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ class NodeMaterial extends Material {
10711071

10721072
output.assign( outputNode );
10731073

1074-
outputNode = vec4( fogNode.toStack() );
1074+
outputNode = vec4( fogNode.toVar() );
10751075

10761076
}
10771077

src/nodes/core/ArrayNode.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ class ArrayNode extends TempNode {
5858

5959
}
6060

61+
/**
62+
* Returns the number of elements in the node array.
63+
*
64+
* @param {NodeBuilder} builder - The current node builder.
65+
* @return {number} The number of elements in the node array.
66+
*/
67+
getArrayCount( /*builder*/ ) {
68+
69+
return this.count;
70+
71+
}
72+
6173
/**
6274
* Returns the node's type.
6375
*

src/nodes/core/AssignNode.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ class AssignNode extends TempNode {
9797

9898
const { targetNode, sourceNode } = this;
9999

100+
const targetProperties = builder.getNodeProperties( targetNode );
101+
targetProperties.assign = true;
102+
100103
const properties = builder.getNodeProperties( this );
101104
properties.sourceNode = sourceNode;
102105
properties.targetNode = targetNode.context( { assign: true } );

src/nodes/core/Node.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,18 @@ class Node extends EventDispatcher {
480480

481481
}
482482

483+
/**
484+
* Returns the number of elements in the node array.
485+
*
486+
* @param {NodeBuilder} builder - The current node builder.
487+
* @return {?number} The number of elements in the node array.
488+
*/
489+
getArrayCount( /*builder*/ ) {
490+
491+
return null;
492+
493+
}
494+
483495
/**
484496
* Represents the setup stage which is the first step of the build process, see {@link Node#build} method.
485497
* This method is often overwritten in derived modules to prepare the node which is used as the output/result.

src/nodes/core/NodeBuilder.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,23 +1747,6 @@ class NodeBuilder {
17471747

17481748
}
17491749

1750-
/**
1751-
* Returns the array length.
1752-
*
1753-
* @param {Node} node - The node.
1754-
* @return {?number} The array length.
1755-
*/
1756-
getArrayCount( node ) {
1757-
1758-
let count = null;
1759-
1760-
if ( node.isArrayNode ) count = node.count;
1761-
else if ( node.isVarNode && node.node.isArrayNode ) count = node.node.count;
1762-
1763-
return count;
1764-
1765-
}
1766-
17671750
/**
17681751
* Returns an instance of {@link NodeVar} for the given variable node.
17691752
*
@@ -1807,7 +1790,7 @@ class NodeBuilder {
18071790

18081791
//
18091792

1810-
const count = this.getArrayCount( node );
1793+
const count = node.getArrayCount( this );
18111794

18121795
nodeVar = new NodeVar( name, type, readOnly, count );
18131796

@@ -2233,6 +2216,28 @@ class NodeBuilder {
22332216

22342217
}
22352218

2219+
/**
2220+
* Executes the node in a specific build stage.
2221+
*
2222+
* @param {Node} node - The node to execute.
2223+
* @param {string} buildStage - The build stage to execute the node in.
2224+
* @param {Node|string|null} output - Expected output type. For example 'vec3'.
2225+
* @return {Node|string|null} The result of the node build.
2226+
*/
2227+
flowBuildStage( node, buildStage, output = null ) {
2228+
2229+
const previousBuildStage = this.getBuildStage();
2230+
2231+
this.setBuildStage( buildStage );
2232+
2233+
const result = node.build( this, output );
2234+
2235+
this.setBuildStage( previousBuildStage );
2236+
2237+
return result;
2238+
2239+
}
2240+
22362241
/**
22372242
* Runs the node flow through all the steps of creation, 'setup', 'analyze', 'generate'.
22382243
*

src/nodes/core/StackNode.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,36 @@ class StackNode extends Node {
245245

246246
}
247247

248+
setup( builder ) {
249+
250+
const nodeProperties = builder.getNodeProperties( this );
251+
252+
let index = 0;
253+
254+
for ( const childNode of this.getChildren() ) {
255+
256+
if ( childNode.isVarNode && childNode.intent === true ) {
257+
258+
const properties = builder.getNodeProperties( childNode );
259+
260+
if ( properties.assign !== true ) {
261+
262+
continue;
263+
264+
}
265+
266+
}
267+
268+
nodeProperties[ 'node' + index ++ ] = childNode;
269+
270+
}
271+
272+
// return a outputNode if exists or null
273+
274+
return nodeProperties.outputNode || null;
275+
276+
}
277+
248278
build( builder, ...params ) {
249279

250280
const previousBuildStack = builder.currentStack;
@@ -258,6 +288,18 @@ class StackNode extends Node {
258288

259289
for ( const node of this.nodes ) {
260290

291+
if ( node.isVarNode && node.intent === true ) {
292+
293+
const properties = builder.getNodeProperties( node );
294+
295+
if ( properties.assign !== true ) {
296+
297+
continue;
298+
299+
}
300+
301+
}
302+
261303
if ( buildStage === 'setup' ) {
262304

263305
node.build( builder );

src/nodes/core/VarNode.js

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

44
/**
55
* Class for representing shader variables as nodes. Variables are created from
@@ -81,6 +81,45 @@ class VarNode extends Node {
8181
*/
8282
this.parents = true;
8383

84+
/**
85+
* This flag is used to indicate that this node is used for intent.
86+
*
87+
* @type {boolean}
88+
* @default false
89+
*/
90+
this.intent = false;
91+
92+
}
93+
94+
/**
95+
* Sets the intent flag for this node.
96+
*
97+
* This flag is used to indicate that this node is used for intent
98+
* and should not be built directly. Instead, it is used to indicate that
99+
* the node should be treated as a variable intent.
100+
*
101+
* It's useful for assigning variables without needing creating a new variable node.
102+
*
103+
* @param {boolean} value - The value to set for the intent flag.
104+
* @returns {VarNode} This node.
105+
*/
106+
setIntent( value ) {
107+
108+
this.intent = value;
109+
110+
return this;
111+
112+
}
113+
114+
/**
115+
* Returns the intent flag of this node.
116+
*
117+
* @return {boolean} The intent flag.
118+
*/
119+
getIntent() {
120+
121+
return this.intent;
122+
84123
}
85124

86125
getMemberType( builder, name ) {
@@ -101,6 +140,31 @@ class VarNode extends Node {
101140

102141
}
103142

143+
getArrayCount( builder ) {
144+
145+
return this.node.getArrayCount( builder );
146+
147+
}
148+
149+
build( ...params ) {
150+
151+
if ( this.intent === true ) {
152+
153+
const builder = params[ 0 ];
154+
const properties = builder.getNodeProperties( this );
155+
156+
if ( properties.assign !== true ) {
157+
158+
return this.node.build( ...params );
159+
160+
}
161+
162+
}
163+
164+
return super.build( ...params );
165+
166+
}
167+
104168
generate( builder ) {
105169

106170
const { node, name, readOnly } = this;
@@ -138,7 +202,7 @@ class VarNode extends Node {
138202

139203
} else {
140204

141-
const count = builder.getArrayCount( node );
205+
const count = node.getArrayCount( builder );
142206

143207
declarationPrefix = `const ${ builder.getVar( nodeVar.type, propertyName, count ) }`;
144208

@@ -189,10 +253,35 @@ export const Var = ( node, name = null ) => createVar( node, name ).toStack();
189253
*/
190254
export const Const = ( node, name = null ) => createVar( node, name, true ).toStack();
191255

256+
//
257+
//
258+
259+
/**
260+
* TSL function for creating a var intent node.
261+
*
262+
* @tsl
263+
* @function
264+
* @param {Node} node - The node for which a variable should be created.
265+
* @param {?string} name - The name of the variable in the shader.
266+
* @returns {VarNode}
267+
*/
268+
export const VarIntent = ( node ) => {
269+
270+
if ( getCurrentStack() === null ) {
271+
272+
return node;
273+
274+
}
275+
276+
return createVar( node ).setIntent( true ).toStack();
277+
278+
};
279+
192280
// Method chaining
193281

194282
addMethodChaining( 'toVar', Var );
195283
addMethodChaining( 'toConst', Const );
284+
addMethodChaining( 'toVarIntent', VarIntent );
196285

197286
// Deprecated
198287

src/nodes/math/ConditionalNode.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class ConditionalNode extends Node {
7373

7474
// fallback setup
7575

76-
this.setup( builder );
76+
builder.flowBuildStage( this, 'setup' );
7777

7878
return this.getNodeType( builder );
7979

0 commit comments

Comments
 (0)