Skip to content

Commit 2913095

Browse files
sunagRuthySheffi
authored andcommitted
TSL: Introduce namespace (mrdoob#31168)
* Nodes: use `.global` * introduce `namespace` * update description * use namespace to `material.positionNode` * add `docs`
1 parent 8f95967 commit 2913095

File tree

11 files changed

+165
-98
lines changed

11 files changed

+165
-98
lines changed

src/Three.TSL.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ export const mx_transform_uv = TSL.mx_transform_uv;
327327
export const mx_worley_noise_float = TSL.mx_worley_noise_float;
328328
export const mx_worley_noise_vec2 = TSL.mx_worley_noise_vec2;
329329
export const mx_worley_noise_vec3 = TSL.mx_worley_noise_vec3;
330+
export const namespace = TSL.namespace;
330331
export const negate = TSL.negate;
331332
export const neutralToneMapping = TSL.neutralToneMapping;
332333
export const nodeArray = TSL.nodeArray;

src/materials/nodes/NodeMaterial.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { positionLocal, positionView } from '../../nodes/accessors/Position.js';
1313
import { skinning } from '../../nodes/accessors/SkinningNode.js';
1414
import { morphReference } from '../../nodes/accessors/MorphNode.js';
1515
import { mix } from '../../nodes/math/MathNode.js';
16-
import { float, vec3, vec4, bool } from '../../nodes/tsl/TSLBase.js';
16+
import { namespace, float, vec3, vec4, bool } from '../../nodes/tsl/TSLBase.js';
1717
import AONode from '../../nodes/lighting/AONode.js';
1818
import { lightingContext } from '../../nodes/lighting/LightingContextNode.js';
1919
import IrradianceNode from '../../nodes/lighting/IrradianceNode.js';
@@ -767,7 +767,7 @@ class NodeMaterial extends Material {
767767

768768
if ( this.positionNode !== null ) {
769769

770-
positionLocal.assign( this.positionNode.context( { isPositionNodeInput: true } ) );
770+
positionLocal.assign( namespace( this.positionNode, 'POSITION' ) );
771771

772772
}
773773

src/nodes/accessors/Position.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,25 @@ export const positionPrevious = /*@__PURE__*/ positionGeometry.toVarying( 'posit
3333
* @tsl
3434
* @type {VaryingNode<vec3>}
3535
*/
36-
export const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.toVarying( 'v_positionWorld' ).context( { needsPositionReassign: true } );
36+
export const positionWorld = /*@__PURE__*/ ( Fn( ( builder ) => {
37+
38+
return modelWorldMatrix.mul( positionLocal ).xyz.toVarying( builder.getNamespace( 'v_positionWorld' ) );
39+
40+
}, 'vec3' ).once( 'POSITION' ) )();
3741

3842
/**
3943
* TSL object that represents the position world direction of the current rendered object.
4044
*
4145
* @tsl
4246
* @type {Node<vec3>}
4347
*/
44-
export const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).toVarying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ).context( { needsPositionReassign: true } );
48+
export const positionWorldDirection = /*@__PURE__*/ ( Fn( ( builder ) => {
49+
50+
const vertexPWD = positionLocal.transformDirection( modelWorldMatrix ).toVarying( builder.getNamespace( 'v_positionWorldDirection' ) );
51+
52+
return vertexPWD.normalize().toVar( 'positionWorldDirection' );
53+
54+
}, 'vec3' ).once( 'POSITION' ) )();
4555

4656
/**
4757
* TSL object that represents the vertex position in view space of the current rendered object.
@@ -51,9 +61,9 @@ export const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirec
5161
*/
5262
export const positionView = /*@__PURE__*/ ( Fn( ( builder ) => {
5363

54-
return builder.context.setupPositionView();
64+
return builder.context.setupPositionView().toVarying( builder.getNamespace( 'v_positionView' ) );
5565

56-
}, 'vec3' ).once() )().toVarying( 'v_positionView' ).context( { needsPositionReassign: true } );
66+
}, 'vec3' ).once( 'POSITION' ) )();
5767

5868
/**
5969
* TSL object that represents the position view direction of the current rendered object.

src/nodes/code/CodeNode.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ class CodeNode extends Node {
3636
*/
3737
this.isCodeNode = true;
3838

39+
/**
40+
* This flag is used for global cache.
41+
*
42+
* @type {boolean}
43+
* @default true
44+
*/
45+
this.global = true;
46+
3947
/**
4048
* The native code.
4149
*
@@ -62,17 +70,6 @@ class CodeNode extends Node {
6270

6371
}
6472

65-
/**
66-
* The method is overwritten so it always returns `true`.
67-
*
68-
* @return {boolean} Whether this node is global or not.
69-
*/
70-
isGlobal() {
71-
72-
return true;
73-
74-
}
75-
7673
/**
7774
* Sets the includes of this code node.
7875
*

src/nodes/core/CacheNode.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,18 @@ export default CacheNode;
9797
*/
9898
export const cache = ( node, parent ) => nodeObject( new CacheNode( nodeObject( node ), parent ) );
9999

100+
/**
101+
* Assigns a namespace to the given node by updating its context.
102+
*
103+
* Important for TSL functions that use `.once( namespace )` to ensure that the namespace will run twice,
104+
* once when the node is build in the specific namespace and once when the node is built in the others namespace.
105+
*
106+
* This is useful for nodes like `positionWorld` that need to be re-updated if used in `material.positionNode` and outside of it in the same material.
107+
*
108+
* @param {Object} node - The node to which the namespace will be assigned.
109+
* @param {string} namespace - The namespace to be assigned to the node.
110+
* @returns {Object} The updated node with the new namespace in its context.
111+
*/
112+
export const namespace = ( node, namespace ) => node.context( { namespace } );
113+
100114
addMethodChaining( 'cache', cache );

src/nodes/core/Node.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class Node extends EventDispatcher {
261261
/**
262262
* By default this method returns the value of the {@link Node#global} flag. This method
263263
* can be overwritten in derived classes if an analytical way is required to determine the
264-
* global status.
264+
* global cache referring to the current shader-stage.
265265
*
266266
* @param {NodeBuilder} builder - The current node builder.
267267
* @return {boolean} Whether this node is global or not.

src/nodes/core/NodeBuilder.js

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,58 @@ class NodeBuilder {
18621862

18631863
}
18641864

1865+
/**
1866+
* Returns the current namespace for the node builder.
1867+
*
1868+
* @return {string} The current namespace.
1869+
*/
1870+
get namespace() {
1871+
1872+
return this.context.namespace;
1873+
1874+
}
1875+
1876+
/**
1877+
* Returns the output namespace for the node builder, which is used for the current output node.
1878+
*
1879+
* @return {string} The output namespace.
1880+
*/
1881+
getOutputNamespace() {
1882+
1883+
return this.getNamespace( 'outputNode' );
1884+
1885+
}
1886+
1887+
/**
1888+
* Returns the namespace for the given property.
1889+
*
1890+
* If the property name is not set, it returns the namespace only.
1891+
* If the namespace is not set, it returns the property name.
1892+
* If the namespace is set, it returns the namespace concatenated with the property name.
1893+
*
1894+
* @param {string} [property=''] - The property name.
1895+
* @return {string} The namespace for the property.
1896+
*/
1897+
getNamespace( property = '' ) {
1898+
1899+
const ns = this.namespace;
1900+
1901+
let nsName;
1902+
1903+
if ( ns ) {
1904+
1905+
nsName = property ? ( ns + '_' + property ) : ns;
1906+
1907+
} else {
1908+
1909+
nsName = property;
1910+
1911+
}
1912+
1913+
return nsName;
1914+
1915+
}
1916+
18651917
/**
18661918
* Registers a node declaration in the current shader stage.
18671919
*
@@ -1885,7 +1937,6 @@ class NodeBuilder {
18851937

18861938
}
18871939

1888-
18891940
if ( index > 1 ) {
18901941

18911942
node.name = name;
@@ -1894,7 +1945,6 @@ class NodeBuilder {
18941945

18951946
}
18961947

1897-
18981948
declarations[ name ] = node;
18991949

19001950
}

src/nodes/core/PropertyNode.js

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ class PropertyNode extends Node {
5858
*/
5959
this.isPropertyNode = true;
6060

61+
/**
62+
* This flag is used for global cache.
63+
*
64+
* @type {boolean}
65+
* @default true
66+
*/
67+
this.global = true;
68+
6169
}
6270

6371
getHash( builder ) {
@@ -66,18 +74,6 @@ class PropertyNode extends Node {
6674

6775
}
6876

69-
/**
70-
* The method is overwritten so it always returns `true`.
71-
*
72-
* @param {NodeBuilder} builder - The current node builder.
73-
* @return {boolean} Whether this node is global or not.
74-
*/
75-
isGlobal( /*builder*/ ) {
76-
77-
return true;
78-
79-
}
80-
8177
generate( builder ) {
8278

8379
let nodeVar;

src/nodes/core/VaryingNode.js

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,16 @@ class VaryingNode extends Node {
7171
*/
7272
this.interpolationSampling = null;
7373

74-
}
75-
76-
/**
77-
* The method is overwritten so it always returns `true`.
78-
*
79-
* @param {NodeBuilder} builder - The current node builder.
80-
* @return {boolean} Whether this node is global or not.
81-
*/
82-
isGlobal( /*builder*/ ) {
83-
84-
return true;
74+
/**
75+
* This flag is used for global cache.
76+
*
77+
* @type {boolean}
78+
* @default true
79+
*/
80+
this.global = true;
8581

8682
}
8783

88-
8984
/**
9085
* Defines the interpolation type of the varying.
9186
*
@@ -168,9 +163,7 @@ class VaryingNode extends Node {
168163
const properties = builder.getNodeProperties( this );
169164
const varying = this.setupVarying( builder );
170165

171-
const needsReassign = builder.shaderStage === 'fragment' && properties.reassignPosition === true && builder.context.needsPositionReassign;
172-
173-
if ( properties.propertyName === undefined || needsReassign ) {
166+
if ( properties.propertyName === undefined ) {
174167

175168
const type = this.getNodeType( builder );
176169
const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX );
@@ -180,17 +173,6 @@ class VaryingNode extends Node {
180173

181174
properties.propertyName = propertyName;
182175

183-
if ( needsReassign ) {
184-
185-
// once reassign varying in fragment stage
186-
properties.reassignPosition = false;
187-
188-
} else if ( properties.reassignPosition === undefined && builder.context.isPositionNodeInput ) {
189-
190-
properties.reassignPosition = true;
191-
192-
}
193-
194176
}
195177

196178
return builder.getPropertyName( varying );

src/nodes/display/PassNode.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ class PassNode extends TempNode {
336336
*/
337337
this.updateBeforeType = NodeUpdateType.FRAME;
338338

339+
/**
340+
* This flag is used for global cache.
341+
*
342+
* @type {boolean}
343+
* @default true
344+
*/
345+
this.global = true;
346+
339347
}
340348

341349
/**
@@ -404,17 +412,6 @@ class PassNode extends TempNode {
404412

405413
}
406414

407-
/**
408-
* The method is overwritten so it always returns `true`.
409-
*
410-
* @return {boolean} Whether this node is global or not.
411-
*/
412-
isGlobal() {
413-
414-
return true;
415-
416-
}
417-
418415
/**
419416
* Returns the texture for the given output name.
420417
*

0 commit comments

Comments
 (0)