@plastic-software/three 0.179.0 → 0.180.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/build/three.cjs +166 -106
  2. package/build/three.core.js +112 -20
  3. package/build/three.core.min.js +1 -1
  4. package/build/three.module.js +55 -89
  5. package/build/three.module.min.js +1 -1
  6. package/build/three.tsl.js +30 -5
  7. package/build/three.tsl.min.js +1 -1
  8. package/build/three.webgpu.js +2896 -1048
  9. package/build/three.webgpu.min.js +1 -1
  10. package/build/three.webgpu.nodes.js +2896 -1048
  11. package/build/three.webgpu.nodes.min.js +1 -1
  12. package/examples/jsm/Addons.js +1 -1
  13. package/examples/jsm/controls/ArcballControls.js +7 -7
  14. package/examples/jsm/controls/DragControls.js +6 -56
  15. package/examples/jsm/controls/FirstPersonControls.js +2 -2
  16. package/examples/jsm/controls/PointerLockControls.js +0 -8
  17. package/examples/jsm/exporters/GLTFExporter.js +30 -22
  18. package/examples/jsm/exporters/KTX2Exporter.js +4 -2
  19. package/examples/jsm/exporters/PLYExporter.js +1 -1
  20. package/examples/jsm/libs/ktx-parse.module.js +1 -1
  21. package/examples/jsm/lines/Line2.js +3 -3
  22. package/examples/jsm/lines/LineGeometry.js +1 -1
  23. package/examples/jsm/lines/LineSegments2.js +2 -2
  24. package/examples/jsm/lines/Wireframe.js +2 -2
  25. package/examples/jsm/lines/WireframeGeometry2.js +1 -1
  26. package/examples/jsm/lines/webgpu/LineSegments2.js +1 -1
  27. package/examples/jsm/lines/webgpu/Wireframe.js +1 -1
  28. package/examples/jsm/loaders/ColladaLoader.js +1 -1
  29. package/examples/jsm/loaders/EXRLoader.js +5 -5
  30. package/examples/jsm/loaders/GLTFLoader.js +9 -5
  31. package/examples/jsm/loaders/HDRCubeTextureLoader.js +5 -5
  32. package/examples/jsm/loaders/HDRLoader.js +486 -0
  33. package/examples/jsm/loaders/KTX2Loader.js +112 -32
  34. package/examples/jsm/loaders/RGBELoader.js +7 -473
  35. package/examples/jsm/loaders/TTFLoader.js +4 -4
  36. package/examples/jsm/loaders/UltraHDRLoader.js +1 -1
  37. package/examples/jsm/loaders/lwo/IFFParser.js +1 -1
  38. package/examples/jsm/materials/WoodNodeMaterial.js +533 -0
  39. package/examples/jsm/math/ColorSpaces.js +19 -1
  40. package/examples/jsm/math/ConvexHull.js +2 -2
  41. package/examples/jsm/math/Lut.js +2 -2
  42. package/examples/jsm/misc/MD2CharacterComplex.js +1 -1
  43. package/examples/jsm/misc/ProgressiveLightMap.js +1 -1
  44. package/examples/jsm/misc/Volume.js +1 -1
  45. package/examples/jsm/postprocessing/OutlinePass.js +1 -1
  46. package/examples/jsm/postprocessing/SSRPass.js +37 -8
  47. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +1 -1
  48. package/examples/jsm/transpiler/GLSLDecoder.js +22 -19
  49. package/examples/jsm/transpiler/TSLEncoder.js +2 -10
  50. package/examples/jsm/transpiler/WGSLEncoder.js +24 -0
  51. package/examples/jsm/tsl/display/AnamorphicNode.js +27 -4
  52. package/examples/jsm/tsl/display/BloomNode.js +3 -3
  53. package/examples/jsm/tsl/display/ChromaticAberrationNode.js +2 -1
  54. package/examples/jsm/tsl/display/DepthOfFieldNode.js +439 -90
  55. package/examples/jsm/tsl/display/GTAONode.js +8 -0
  56. package/examples/jsm/tsl/display/GaussianBlurNode.js +47 -35
  57. package/examples/jsm/tsl/display/OutlineNode.js +2 -2
  58. package/examples/jsm/tsl/display/SSRNode.js +180 -65
  59. package/examples/jsm/tsl/display/TRAANode.js +1 -1
  60. package/examples/jsm/tsl/display/boxBlur.js +64 -0
  61. package/examples/jsm/tsl/display/hashBlur.js +15 -18
  62. package/examples/jsm/utils/BufferGeometryUtils.js +1 -1
  63. package/examples/jsm/utils/ShadowMapViewerGPU.js +12 -5
  64. package/examples/jsm/webxr/OculusHandModel.js +1 -1
  65. package/package.json +1 -1
  66. package/src/Three.Core.js +1 -0
  67. package/src/Three.TSL.js +29 -4
  68. package/src/animation/AnimationClip.js +17 -2
  69. package/src/constants.js +11 -3
  70. package/src/core/BufferGeometry.js +2 -2
  71. package/src/extras/TextureUtils.js +2 -1
  72. package/src/extras/lib/earcut.js +1 -1
  73. package/src/lights/webgpu/ProjectorLight.js +1 -1
  74. package/src/materials/Material.js +12 -0
  75. package/src/materials/MeshDistanceMaterial.js +1 -1
  76. package/src/materials/nodes/PointsNodeMaterial.js +81 -28
  77. package/src/materials/nodes/SpriteNodeMaterial.js +3 -15
  78. package/src/materials/nodes/manager/NodeMaterialObserver.js +1 -1
  79. package/src/math/ColorManagement.js +7 -1
  80. package/src/nodes/Nodes.js +3 -0
  81. package/src/nodes/TSL.js +3 -0
  82. package/src/nodes/accessors/BufferNode.js +1 -1
  83. package/src/nodes/accessors/Camera.js +133 -7
  84. package/src/nodes/accessors/ClippingNode.js +6 -5
  85. package/src/nodes/accessors/CubeTextureNode.js +2 -2
  86. package/src/nodes/accessors/InstanceNode.js +3 -1
  87. package/src/nodes/accessors/Object3DNode.js +1 -1
  88. package/src/nodes/accessors/ReferenceBaseNode.js +1 -1
  89. package/src/nodes/accessors/ReferenceNode.js +1 -1
  90. package/src/nodes/accessors/Texture3DNode.js +13 -0
  91. package/src/nodes/accessors/TextureNode.js +71 -19
  92. package/src/nodes/code/FunctionCallNode.js +19 -0
  93. package/src/nodes/code/FunctionNode.js +23 -0
  94. package/src/nodes/core/AssignNode.js +4 -3
  95. package/src/nodes/core/ContextNode.js +24 -0
  96. package/src/nodes/core/Node.js +16 -20
  97. package/src/nodes/core/NodeBuilder.js +48 -14
  98. package/src/nodes/core/NodeFrame.js +1 -1
  99. package/src/nodes/core/NodeUniform.js +1 -1
  100. package/src/nodes/core/NodeUtils.js +1 -2
  101. package/src/nodes/core/StackNode.js +29 -4
  102. package/src/nodes/core/StructNode.js +5 -5
  103. package/src/nodes/core/StructTypeNode.js +1 -0
  104. package/src/nodes/core/SubBuildNode.js +2 -2
  105. package/src/nodes/core/UniformNode.js +16 -9
  106. package/src/nodes/core/VarNode.js +0 -21
  107. package/src/nodes/display/FrontFacingNode.js +4 -8
  108. package/src/nodes/display/PassNode.js +1 -1
  109. package/src/nodes/display/ScreenNode.js +42 -13
  110. package/src/nodes/display/ViewportDepthTextureNode.js +16 -4
  111. package/src/nodes/display/ViewportSharedTextureNode.js +12 -0
  112. package/src/nodes/display/ViewportTextureNode.js +42 -12
  113. package/src/nodes/gpgpu/SubgroupFunctionNode.js +430 -0
  114. package/src/nodes/lighting/LightsNode.js +1 -1
  115. package/src/nodes/math/BitcastNode.js +156 -0
  116. package/src/nodes/math/ConditionalNode.js +18 -2
  117. package/src/nodes/math/MathNode.js +3 -15
  118. package/src/nodes/math/OperatorNode.js +4 -3
  119. package/src/nodes/tsl/TSLCore.js +432 -152
  120. package/src/nodes/utils/JoinNode.js +3 -1
  121. package/src/nodes/utils/MemberNode.js +58 -7
  122. package/src/nodes/utils/RTTNode.js +1 -1
  123. package/src/nodes/utils/ReflectorNode.js +51 -7
  124. package/src/nodes/utils/SampleNode.js +12 -2
  125. package/src/nodes/utils/SplitNode.js +11 -0
  126. package/src/nodes/utils/Timer.js +0 -47
  127. package/src/objects/BatchedMesh.js +2 -2
  128. package/src/objects/LOD.js +1 -1
  129. package/src/objects/Sprite.js +2 -2
  130. package/src/renderers/WebGLRenderer.js +0 -9
  131. package/src/renderers/common/Attributes.js +1 -1
  132. package/src/renderers/common/Backend.js +19 -1
  133. package/src/renderers/common/Bindings.js +2 -0
  134. package/src/renderers/common/ChainMap.js +1 -1
  135. package/src/renderers/common/DataMap.js +1 -1
  136. package/src/renderers/common/Pipelines.js +1 -1
  137. package/src/renderers/common/RenderContext.js +2 -2
  138. package/src/renderers/common/RenderObject.js +14 -2
  139. package/src/renderers/common/Renderer.js +39 -19
  140. package/src/renderers/common/SampledTexture.js +1 -1
  141. package/src/renderers/common/Sampler.js +25 -13
  142. package/src/renderers/common/Textures.js +34 -12
  143. package/src/renderers/common/TimestampQueryPool.js +3 -3
  144. package/src/renderers/common/XRManager.js +35 -19
  145. package/src/renderers/common/nodes/NodeBuilderState.js +1 -1
  146. package/src/renderers/common/nodes/NodeLibrary.js +5 -5
  147. package/src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl.js +1 -1
  148. package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl.js +1 -1
  149. package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl.js +1 -1
  150. package/src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl.js +1 -1
  151. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +7 -15
  152. package/src/renderers/shaders/ShaderLib/depth.glsl.js +1 -1
  153. package/src/renderers/webgl/WebGLProgram.js +4 -4
  154. package/src/renderers/webgl/WebGLShadowMap.js +1 -1
  155. package/src/renderers/webgl/WebGLTextures.js +1 -0
  156. package/src/renderers/webgl/WebGLUtils.js +3 -2
  157. package/src/renderers/webgl-fallback/WebGLBackend.js +186 -135
  158. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +110 -17
  159. package/src/renderers/webgl-fallback/utils/WebGLState.js +1 -1
  160. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +52 -3
  161. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +9 -10
  162. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +3 -2
  163. package/src/renderers/webgpu/WebGPUBackend.js +35 -31
  164. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +124 -34
  165. package/src/renderers/webgpu/utils/WebGPUConstants.js +2 -2
  166. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +9 -18
  167. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +114 -25
  168. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +3 -3
  169. package/src/renderers/webxr/WebXRManager.js +39 -24
  170. package/src/textures/ExternalTexture.js +15 -4
  171. package/src/textures/Source.js +1 -1
  172. package/src/textures/VideoTexture.js +0 -3
  173. package/examples/jsm/loaders/RGBMLoader.js +0 -1148
@@ -13,6 +13,8 @@ let currentStack = null;
13
13
 
14
14
  const NodeElements = new Map();
15
15
 
16
+ // Extend Node Class for TSL using prototype
17
+
16
18
  export function addMethodChaining( name, nodeElement ) {
17
19
 
18
20
  if ( NodeElements.has( name ) ) {
@@ -26,152 +28,274 @@ export function addMethodChaining( name, nodeElement ) {
26
28
 
27
29
  NodeElements.set( name, nodeElement );
28
30
 
31
+ if ( name !== 'assign' ) {
32
+
33
+ // Changing Node prototype to add method chaining
34
+
35
+ Node.prototype[ name ] = function ( ...params ) {
36
+
37
+ //if ( name === 'toVarIntent' ) return this;
38
+
39
+ return this.isStackNode ? this.add( nodeElement( ...params ) ) : nodeElement( this, ...params );
40
+
41
+ };
42
+
43
+ // Adding assign method chaining
44
+
45
+ Node.prototype[ name + 'Assign' ] = function ( ...params ) {
46
+
47
+ return this.isStackNode ? this.assign( params[ 0 ], nodeElement( ...params ) ) : this.assign( nodeElement( this, ...params ) );
48
+
49
+ };
50
+
51
+ }
52
+
29
53
  }
30
54
 
31
55
  const parseSwizzle = ( props ) => props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace( /a|q/g, 'w' );
32
56
  const parseSwizzleAndSort = ( props ) => parseSwizzle( props ).split( '' ).sort().join( '' );
33
57
 
34
- const shaderNodeHandler = {
58
+ Node.prototype.assign = function ( ...params ) {
59
+
60
+ if ( this.isStackNode !== true ) {
35
61
 
36
- setup( NodeClosure, params ) {
62
+ if ( currentStack !== null ) {
37
63
 
38
- const inputs = params.shift();
64
+ currentStack.assign( this, ...params );
39
65
 
40
- return NodeClosure( nodeObjects( inputs ), ...params );
66
+ } else {
67
+
68
+ console.error( 'THREE.TSL: No stack defined for assign operation. Make sure the assign is inside a Fn().' );
41
69
 
42
- },
70
+ }
43
71
 
44
- get( node, prop, nodeObj ) {
72
+ return this;
45
73
 
46
- if ( typeof prop === 'string' && node[ prop ] === undefined ) {
74
+ } else {
47
75
 
48
- if ( node.isStackNode !== true && prop === 'assign' ) {
76
+ const nodeElement = NodeElements.get( 'assign' );
49
77
 
50
- return ( ...params ) => {
78
+ return this.add( nodeElement( ...params ) );
51
79
 
52
- currentStack.assign( nodeObj, ...params );
80
+ }
53
81
 
54
- return nodeObj;
82
+ };
55
83
 
56
- };
84
+ Node.prototype.toVarIntent = function () {
85
+
86
+ return this;
87
+
88
+ };
89
+
90
+ Node.prototype.get = function ( value ) {
91
+
92
+ return new MemberNode( this, value );
93
+
94
+ };
95
+
96
+ // Cache prototype for TSL
57
97
 
58
- } else if ( NodeElements.has( prop ) ) {
98
+ const proto = {};
59
99
 
60
- const nodeElement = NodeElements.get( prop );
100
+ // Set swizzle properties for xyzw, rgba, and stpq.
61
101
 
62
- return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params );
102
+ function setProtoSwizzle( property, altA, altB ) {
63
103
 
64
- } else if ( prop === 'toVarIntent' ) {
104
+ // swizzle properties
65
105
 
66
- return () => nodeObj;
106
+ proto[ property ] = proto[ altA ] = proto[ altB ] = {
67
107
 
68
- } else if ( prop === 'self' ) {
108
+ get() {
69
109
 
70
- return node;
110
+ this._cache = this._cache || {};
71
111
 
72
- } else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) {
112
+ //
73
113
 
74
- const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) );
114
+ let split = this._cache[ property ];
75
115
 
76
- return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) );
116
+ if ( split === undefined ) {
77
117
 
78
- } else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
118
+ split = new SplitNode( this, property );
79
119
 
80
- // accessing properties ( swizzle )
120
+ this._cache[ property ] = split;
81
121
 
82
- prop = parseSwizzle( prop );
122
+ }
123
+
124
+ return split;
125
+
126
+ },
127
+
128
+ set( value ) {
129
+
130
+ this[ property ].assign( nodeObject( value ) );
131
+
132
+ }
133
+
134
+ };
135
+
136
+ // set properties ( swizzle ) and sort to xyzw sequence
137
+
138
+ const propUpper = property.toUpperCase();
139
+ const altAUpper = altA.toUpperCase();
140
+ const altBUpper = altB.toUpperCase();
141
+
142
+ // Set methods for swizzle properties
143
+
144
+ Node.prototype[ 'set' + propUpper ] = Node.prototype[ 'set' + altAUpper ] = Node.prototype[ 'set' + altBUpper ] = function ( value ) {
145
+
146
+ const swizzle = parseSwizzleAndSort( property );
147
+
148
+ return new SetNode( this, swizzle, nodeObject( value ) );
149
+
150
+ };
83
151
 
84
- return nodeObject( new SplitNode( nodeObj, prop ) );
152
+ // Set methods for flip properties
85
153
 
86
- } else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) {
154
+ Node.prototype[ 'flip' + propUpper ] = Node.prototype[ 'flip' + altAUpper ] = Node.prototype[ 'flip' + altBUpper ] = function () {
87
155
 
88
- // set properties ( swizzle ) and sort to xyzw sequence
156
+ const swizzle = parseSwizzleAndSort( property );
89
157
 
90
- prop = parseSwizzleAndSort( prop.slice( 3 ).toLowerCase() );
158
+ return new FlipNode( this, swizzle );
91
159
 
92
- return ( value ) => nodeObject( new SetNode( node, prop, nodeObject( value ) ) );
160
+ };
93
161
 
94
- } else if ( /^flip[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) {
162
+ }
95
163
 
96
- // set properties ( swizzle ) and sort to xyzw sequence
164
+ const swizzleA = [ 'x', 'y', 'z', 'w' ];
165
+ const swizzleB = [ 'r', 'g', 'b', 'a' ];
166
+ const swizzleC = [ 's', 't', 'p', 'q' ];
97
167
 
98
- prop = parseSwizzleAndSort( prop.slice( 4 ).toLowerCase() );
168
+ for ( let a = 0; a < 4; a ++ ) {
99
169
 
100
- return () => nodeObject( new FlipNode( nodeObject( node ), prop ) );
170
+ let prop = swizzleA[ a ];
171
+ let altA = swizzleB[ a ];
172
+ let altB = swizzleC[ a ];
101
173
 
102
- } else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) {
174
+ setProtoSwizzle( prop, altA, altB );
103
175
 
104
- // accessing property
176
+ for ( let b = 0; b < 4; b ++ ) {
105
177
 
106
- if ( prop === 'width' ) prop = 'x';
107
- else if ( prop === 'height' ) prop = 'y';
108
- else if ( prop === 'depth' ) prop = 'z';
178
+ prop = swizzleA[ a ] + swizzleA[ b ];
179
+ altA = swizzleB[ a ] + swizzleB[ b ];
180
+ altB = swizzleC[ a ] + swizzleC[ b ];
109
181
 
110
- return nodeObject( new SplitNode( node, prop ) );
182
+ setProtoSwizzle( prop, altA, altB );
111
183
 
112
- } else if ( /^\d+$/.test( prop ) === true ) {
184
+ for ( let c = 0; c < 4; c ++ ) {
113
185
 
114
- // accessing array
186
+ prop = swizzleA[ a ] + swizzleA[ b ] + swizzleA[ c ];
187
+ altA = swizzleB[ a ] + swizzleB[ b ] + swizzleB[ c ];
188
+ altB = swizzleC[ a ] + swizzleC[ b ] + swizzleC[ c ];
115
189
 
116
- return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) );
190
+ setProtoSwizzle( prop, altA, altB );
117
191
 
118
- } else if ( /^get$/.test( prop ) === true ) {
192
+ for ( let d = 0; d < 4; d ++ ) {
119
193
 
120
- // accessing properties
194
+ prop = swizzleA[ a ] + swizzleA[ b ] + swizzleA[ c ] + swizzleA[ d ];
195
+ altA = swizzleB[ a ] + swizzleB[ b ] + swizzleB[ c ] + swizzleB[ d ];
196
+ altB = swizzleC[ a ] + swizzleC[ b ] + swizzleC[ c ] + swizzleC[ d ];
121
197
 
122
- return ( value ) => nodeObject( new MemberNode( nodeObj, value ) );
198
+ setProtoSwizzle( prop, altA, altB );
123
199
 
124
200
  }
125
201
 
126
202
  }
127
203
 
128
- return Reflect.get( node, prop, nodeObj );
204
+ }
205
+
206
+ }
207
+
208
+ // Set/get static properties for array elements (0-31).
209
+
210
+ for ( let i = 0; i < 32; i ++ ) {
129
211
 
130
- },
212
+ proto[ i ] = {
131
213
 
132
- set( node, prop, value, nodeObj ) {
214
+ get() {
133
215
 
134
- if ( typeof prop === 'string' && node[ prop ] === undefined ) {
216
+ this._cache = this._cache || {};
135
217
 
136
- // setting properties
218
+ //
137
219
 
138
- if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) {
220
+ let element = this._cache[ i ];
139
221
 
140
- nodeObj[ prop ].assign( value );
222
+ if ( element === undefined ) {
141
223
 
142
- return true;
224
+ element = new ArrayElementNode( this, new ConstNode( i, 'uint' ) );
225
+
226
+ this._cache[ i ] = element;
143
227
 
144
228
  }
145
229
 
230
+ return element;
231
+
232
+ },
233
+
234
+ set( value ) {
235
+
236
+ this[ i ].assign( nodeObject( value ) );
237
+
146
238
  }
147
239
 
148
- return Reflect.set( node, prop, value, nodeObj );
240
+ };
149
241
 
150
- }
242
+ }
151
243
 
152
- };
244
+ /*
245
+ // Set properties for width, height, and depth.
153
246
 
154
- const nodeObjectsCacheMap = new WeakMap();
155
- const nodeBuilderFunctionsCacheMap = new WeakMap();
247
+ function setProtoProperty( property, target ) {
156
248
 
157
- const ShaderNodeObject = function ( obj, altType = null ) {
249
+ proto[ property ] = {
158
250
 
159
- const type = getValueType( obj );
251
+ get() {
160
252
 
161
- if ( type === 'node' ) {
253
+ this._cache = this._cache || {};
254
+
255
+ //
256
+
257
+ let split = this._cache[ target ];
258
+
259
+ if ( split === undefined ) {
162
260
 
163
- let nodeObject = nodeObjectsCacheMap.get( obj );
261
+ split = new SplitNode( this, target );
164
262
 
165
- if ( nodeObject === undefined ) {
263
+ this._cache[ target ] = split;
166
264
 
167
- nodeObject = new Proxy( obj, shaderNodeHandler );
265
+ }
266
+
267
+ return split;
268
+
269
+ },
270
+
271
+ set( value ) {
168
272
 
169
- nodeObjectsCacheMap.set( obj, nodeObject );
170
- nodeObjectsCacheMap.set( nodeObject, nodeObject );
273
+ this[ target ].assign( nodeObject( value ) );
171
274
 
172
275
  }
173
276
 
174
- return nodeObject;
277
+ };
278
+
279
+ }
280
+
281
+ setProtoProperty( 'width', 'x' );
282
+ setProtoProperty( 'height', 'y' );
283
+ setProtoProperty( 'depth', 'z' );
284
+ */
285
+
286
+ Object.defineProperties( Node.prototype, proto );
287
+
288
+ // --- FINISH ---
289
+
290
+ const nodeBuilderFunctionsCacheMap = new WeakMap();
291
+
292
+ const ShaderNodeObject = function ( obj, altType = null ) {
293
+
294
+ const type = getValueType( obj );
295
+
296
+ if ( type === 'node' ) {
297
+
298
+ return obj;
175
299
 
176
300
  } else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) {
177
301
 
@@ -322,12 +446,12 @@ const ShaderNodeImmutable = function ( NodeClass, ...params ) {
322
446
 
323
447
  class ShaderCallNodeInternal extends Node {
324
448
 
325
- constructor( shaderNode, inputNodes ) {
449
+ constructor( shaderNode, rawInputs ) {
326
450
 
327
451
  super();
328
452
 
329
453
  this.shaderNode = shaderNode;
330
- this.inputNodes = inputNodes;
454
+ this.rawInputs = rawInputs;
331
455
 
332
456
  this.isShaderCallNodeInternal = true;
333
457
 
@@ -347,7 +471,7 @@ class ShaderCallNodeInternal extends Node {
347
471
 
348
472
  call( builder ) {
349
473
 
350
- const { shaderNode, inputNodes } = this;
474
+ const { shaderNode, rawInputs } = this;
351
475
 
352
476
  const properties = builder.getNodeProperties( shaderNode );
353
477
 
@@ -392,40 +516,48 @@ class ShaderCallNodeInternal extends Node {
392
516
 
393
517
  builder.addInclude( functionNode );
394
518
 
395
- result = nodeObject( functionNode.call( inputNodes ) );
519
+ //
396
520
 
397
- } else {
521
+ const inputs = rawInputs ? getLayoutParameters( rawInputs ) : null;
398
522
 
399
- let inputs = inputNodes;
523
+ result = nodeObject( functionNode.call( inputs ) );
400
524
 
401
- if ( Array.isArray( inputs ) ) {
525
+ } else {
402
526
 
403
- // If inputs is an array, we need to convert it to a Proxy
404
- // so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )`
405
- // and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )`
527
+ const secureNodeBuilder = new Proxy( builder, {
406
528
 
407
- let index = 0;
529
+ get: ( target, property, receiver ) => {
408
530
 
409
- inputs = new Proxy( inputs, {
410
- get: ( target, property, receiver ) => {
531
+ let value;
411
532
 
412
- if ( target[ property ] === undefined ) {
533
+ if ( Symbol.iterator === property ) {
413
534
 
414
- return target[ index ++ ];
535
+ value = function* () {
415
536
 
416
- } else {
537
+ yield undefined;
417
538
 
418
- return Reflect.get( target, property, receiver );
539
+ };
419
540
 
420
- }
541
+ } else {
542
+
543
+ value = Reflect.get( target, property, receiver );
421
544
 
422
545
  }
423
- } );
424
546
 
425
- }
547
+ return value;
548
+
549
+ }
550
+
551
+ } );
552
+
553
+ //
554
+
555
+ const inputs = rawInputs ? getProxyParameters( rawInputs ) : null;
556
+
557
+ const hasParameters = Array.isArray( rawInputs ) ? rawInputs.length > 0 : rawInputs !== null;
426
558
 
427
559
  const jsFunc = shaderNode.jsFunc;
428
- const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], builder ) : jsFunc( builder );
560
+ const outputNode = hasParameters || jsFunc.length > 1 ? jsFunc( inputs, secureNodeBuilder ) : jsFunc( secureNodeBuilder );
429
561
 
430
562
  result = nodeObject( outputNode );
431
563
 
@@ -528,6 +660,110 @@ class ShaderCallNodeInternal extends Node {
528
660
 
529
661
  }
530
662
 
663
+ function getLayoutParameters( params ) {
664
+
665
+ let output;
666
+
667
+ nodeObjects( params );
668
+
669
+ const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
670
+
671
+ if ( isArrayAsParameter ) {
672
+
673
+ output = [ ...params ];
674
+
675
+ } else {
676
+
677
+ output = params[ 0 ];
678
+
679
+ }
680
+
681
+ return output;
682
+
683
+ }
684
+
685
+ function getProxyParameters( params ) {
686
+
687
+ let index = 0;
688
+
689
+ nodeObjects( params );
690
+
691
+ return new Proxy( params, {
692
+
693
+ get: ( target, property, receiver ) => {
694
+
695
+ let value;
696
+
697
+ if ( property === 'length' ) {
698
+
699
+ value = params.length;
700
+
701
+ return value;
702
+
703
+ }
704
+
705
+ if ( Symbol.iterator === property ) {
706
+
707
+ value = function* () {
708
+
709
+ for ( const inputNode of params ) {
710
+
711
+ yield nodeObject( inputNode );
712
+
713
+ }
714
+
715
+ };
716
+
717
+ } else {
718
+
719
+ if ( params.length > 0 ) {
720
+
721
+ if ( Object.getPrototypeOf( params[ 0 ] ) === Object.prototype ) {
722
+
723
+ const objectTarget = params[ 0 ];
724
+
725
+ if ( objectTarget[ property ] === undefined ) {
726
+
727
+ value = objectTarget[ index ++ ];
728
+
729
+ } else {
730
+
731
+ value = Reflect.get( objectTarget, property, receiver );
732
+
733
+ }
734
+
735
+ } else if ( params[ 0 ] instanceof Node ) {
736
+
737
+ if ( params[ property ] === undefined ) {
738
+
739
+ value = params[ index ++ ];
740
+
741
+ } else {
742
+
743
+ value = Reflect.get( params, property, receiver );
744
+
745
+ }
746
+
747
+ }
748
+
749
+ } else {
750
+
751
+ value = Reflect.get( target, property, receiver );
752
+
753
+ }
754
+
755
+ value = nodeObject( value );
756
+
757
+ }
758
+
759
+ return value;
760
+
761
+ }
762
+
763
+ } );
764
+
765
+ }
766
+
531
767
  class ShaderNodeInternal extends Node {
532
768
 
533
769
  constructor( jsFunc, nodeType ) {
@@ -551,11 +787,9 @@ class ShaderNodeInternal extends Node {
551
787
 
552
788
  }
553
789
 
554
- call( inputs = null ) {
790
+ call( rawInputs = null ) {
555
791
 
556
- nodeObjects( inputs );
557
-
558
- return nodeObject( new ShaderCallNodeInternal( this, inputs ) );
792
+ return nodeObject( new ShaderCallNodeInternal( this, rawInputs ) );
559
793
 
560
794
  }
561
795
 
@@ -611,7 +845,25 @@ const ConvertType = function ( type, cacheMap = null ) {
611
845
 
612
846
  return ( ...params ) => {
613
847
 
614
- if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) {
848
+ for ( const param of params ) {
849
+
850
+ if ( param === undefined ) {
851
+
852
+ console.error( `THREE.TSL: Invalid parameter for the type "${ type }".` );
853
+
854
+ return nodeObject( new ConstNode( 0, type ) );
855
+
856
+ }
857
+
858
+ }
859
+
860
+ if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => {
861
+
862
+ const paramType = typeof param;
863
+
864
+ return paramType !== 'object' && paramType !== 'function';
865
+
866
+ } ) ) ) {
615
867
 
616
868
  params = [ getValueFromType( type, ...params ) ];
617
869
 
@@ -650,7 +902,7 @@ export const getConstNodeType = ( value ) => ( value !== undefined && value !==
650
902
 
651
903
  export function ShaderNode( jsFunc, nodeType ) {
652
904
 
653
- return new Proxy( new ShaderNodeInternal( jsFunc, nodeType ), shaderNodeHandler );
905
+ return new ShaderNodeInternal( jsFunc, nodeType );
654
906
 
655
907
  }
656
908
 
@@ -664,119 +916,147 @@ export const nodeProxyIntent = ( NodeClass, scope = null, factor = null, setting
664
916
 
665
917
  let fnId = 0;
666
918
 
667
- export const Fn = ( jsFunc, layout = null ) => {
919
+ class FnNode extends Node {
668
920
 
669
- let nodeType = null;
921
+ constructor( jsFunc, layout = null ) {
670
922
 
671
- if ( layout !== null ) {
672
-
673
- if ( typeof layout === 'object' ) {
923
+ super();
674
924
 
675
- nodeType = layout.return;
925
+ let nodeType = null;
676
926
 
677
- } else {
927
+ if ( layout !== null ) {
678
928
 
679
- if ( typeof layout === 'string' ) {
929
+ if ( typeof layout === 'object' ) {
680
930
 
681
- nodeType = layout;
931
+ nodeType = layout.return;
682
932
 
683
933
  } else {
684
934
 
685
- console.error( 'THREE.TSL: Invalid layout type.' );
935
+ if ( typeof layout === 'string' ) {
936
+
937
+ nodeType = layout;
938
+
939
+ } else {
940
+
941
+ console.error( 'THREE.TSL: Invalid layout type.' );
942
+
943
+ }
944
+
945
+ layout = null;
686
946
 
687
947
  }
688
948
 
689
- layout = null;
949
+ }
950
+
951
+ this.shaderNode = new ShaderNode( jsFunc, nodeType );
952
+
953
+ if ( layout !== null ) {
954
+
955
+ this.setLayout( layout );
690
956
 
691
957
  }
692
958
 
959
+ this.isFn = true;
960
+
693
961
  }
694
962
 
695
- const shaderNode = new ShaderNode( jsFunc, nodeType );
963
+ setLayout( layout ) {
696
964
 
697
- const fn = ( ...params ) => {
965
+ const nodeType = this.shaderNode.nodeType;
698
966
 
699
- let inputs;
967
+ if ( typeof layout.inputs !== 'object' ) {
700
968
 
701
- nodeObjects( params );
969
+ const fullLayout = {
970
+ name: 'fn' + fnId ++,
971
+ type: nodeType,
972
+ inputs: []
973
+ };
702
974
 
703
- const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
975
+ for ( const name in layout ) {
704
976
 
705
- if ( isArrayAsParameter ) {
977
+ if ( name === 'return' ) continue;
706
978
 
707
- inputs = [ ...params ];
979
+ fullLayout.inputs.push( {
980
+ name: name,
981
+ type: layout[ name ]
982
+ } );
708
983
 
709
- } else {
984
+ }
710
985
 
711
- inputs = params[ 0 ];
986
+ layout = fullLayout;
712
987
 
713
988
  }
714
989
 
715
- const fnCall = shaderNode.call( inputs );
990
+ this.shaderNode.setLayout( layout );
991
+
992
+ return this;
993
+
994
+ }
995
+
996
+ getNodeType( builder ) {
997
+
998
+ return this.shaderNode.getNodeType( builder ) || 'float';
999
+
1000
+ }
1001
+
1002
+ call( ...params ) {
716
1003
 
717
- if ( nodeType === 'void' ) fnCall.toStack();
1004
+ const fnCall = this.shaderNode.call( params );
1005
+
1006
+ if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
718
1007
 
719
1008
  return fnCall.toVarIntent();
720
1009
 
721
- };
1010
+ }
722
1011
 
723
- fn.shaderNode = shaderNode;
724
- fn.id = shaderNode.id;
1012
+ once( subBuilds = null ) {
725
1013
 
726
- fn.isFn = true;
1014
+ this.shaderNode.once = true;
1015
+ this.shaderNode.subBuilds = subBuilds;
727
1016
 
728
- fn.getNodeType = ( ...params ) => shaderNode.getNodeType( ...params );
729
- fn.getCacheKey = ( ...params ) => shaderNode.getCacheKey( ...params );
1017
+ return this;
730
1018
 
731
- fn.setLayout = ( layout ) => {
1019
+ }
732
1020
 
733
- shaderNode.setLayout( layout );
1021
+ generate( builder ) {
734
1022
 
735
- return fn;
1023
+ const type = this.getNodeType( builder );
736
1024
 
737
- };
1025
+ console.error( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' );
738
1026
 
739
- fn.once = ( subBuilds = null ) => {
1027
+ return builder.generateConst( type );
740
1028
 
741
- shaderNode.once = true;
742
- shaderNode.subBuilds = subBuilds;
1029
+ }
743
1030
 
744
- return fn;
1031
+ }
745
1032
 
746
- };
1033
+ export function Fn( jsFunc, layout = null ) {
747
1034
 
748
- if ( layout !== null ) {
1035
+ const instance = new FnNode( jsFunc, layout );
749
1036
 
750
- if ( typeof layout.inputs !== 'object' ) {
1037
+ return new Proxy( () => {}, {
751
1038
 
752
- const fullLayout = {
753
- name: 'fn' + fnId ++,
754
- type: nodeType,
755
- inputs: []
756
- };
1039
+ apply( target, thisArg, params ) {
757
1040
 
758
- for ( const name in layout ) {
1041
+ return instance.call( ...params );
759
1042
 
760
- if ( name === 'return' ) continue;
1043
+ },
761
1044
 
762
- fullLayout.inputs.push( {
763
- name: name,
764
- type: layout[ name ]
765
- } );
1045
+ get( target, prop, receiver ) {
766
1046
 
767
- }
1047
+ return Reflect.get( instance, prop, receiver );
768
1048
 
769
- layout = fullLayout;
1049
+ },
770
1050
 
771
- }
1051
+ set( target, prop, value, receiver ) {
772
1052
 
773
- fn.setLayout( layout );
1053
+ return Reflect.set( instance, prop, value, receiver );
774
1054
 
775
- }
1055
+ }
776
1056
 
777
- return fn;
1057
+ } );
778
1058
 
779
- };
1059
+ }
780
1060
 
781
1061
  //
782
1062