TSL: Fix double expressions.#32665
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
|
Unfortunately, statements like |
|
Claude (after 3 tries) suggested doing this... 👀 diff --git a/src/nodes/code/ExpressionNode.js b/src/nodes/code/ExpressionNode.js
--- a/src/nodes/code/ExpressionNode.js
+++ b/src/nodes/code/ExpressionNode.js
@@ -38,7 +38,19 @@ class ExpressionNode extends Node {
if ( type === 'void' ) {
- builder.addLineFlowCode( snippet, this );
+ // Prevent duplicate generation of void expressions (e.g., discard, return, break, continue)
+ // This can happen when the same expression is both in stack.nodes (via .toStack())
+ // and stack.outputNode (returned from a callback like If(cond, () => Discard()))
+
+ const nodeData = builder.getDataFromNode( this, builder.shaderStage );
+
+ if ( nodeData.generated !== true ) {
+
+ nodeData.generated = true;
+
+ builder.addLineFlowCode( snippet, this );
+
+ }
} else {/cc @sunag |
|
What makes TSL a middle ground between a shading language and a node system are the stacks; when added a node to the stack, it's equivalent to writing a line of code, while a pure node system creates a dynamic and independent flow. The problem with the code below is that when we use If(diffuseColor.a.mul(alphaFactor).lessThanEqual(0.1337), () => Discard())Which is the same as: If(diffuseColor.a.mul(alphaFactor).lessThanEqual(0.1337), () => {
return Discard();
} )The correct approach would be to not return a value but using If(diffuseColor.a.mul(alphaFactor).lessThanEqual(0.1337), () => void Discard())
I never cease to be amazed by AI. Certainly an approach we use for caching and avoid repetition. My only question is whether this should be linked to the stack and not necessarily to the node expression, because we might have other void nodes that could present an equivalent problem. |
Fixed #32589.
Description
I'm not sure this is the best fix but it seems calling
toStack()is only required in the method chaining case e.g. when using.discard(). In all other cases, the call can be removed.