super-three 0.172.0 → 0.173.1

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 (180) hide show
  1. package/LICENSE +1 -1
  2. package/build/three.cjs +439 -380
  3. package/build/three.core.js +413 -41
  4. package/build/three.core.min.js +2 -2
  5. package/build/three.module.js +28 -344
  6. package/build/three.module.min.js +2 -2
  7. package/build/three.tsl.js +11 -3
  8. package/build/three.tsl.min.js +2 -2
  9. package/build/three.webgpu.js +7550 -1798
  10. package/build/three.webgpu.min.js +2 -2
  11. package/build/three.webgpu.nodes.js +7551 -1798
  12. package/build/three.webgpu.nodes.min.js +2 -2
  13. package/examples/jsm/animation/CCDIKSolver.js +6 -5
  14. package/examples/jsm/capabilities/WebGPU.js +1 -1
  15. package/examples/jsm/controls/ArcballControls.js +23 -21
  16. package/examples/jsm/exporters/GLTFExporter.js +26 -25
  17. package/examples/jsm/geometries/TextGeometry.js +1 -12
  18. package/examples/jsm/interactive/InteractiveGroup.js +108 -51
  19. package/examples/jsm/libs/demuxer_mp4.js +109 -0
  20. package/examples/jsm/loaders/GCodeLoader.js +3 -1
  21. package/examples/jsm/loaders/GLTFLoader.js +0 -2
  22. package/examples/jsm/loaders/TDSLoader.js +0 -1
  23. package/examples/jsm/materials/MeshGouraudMaterial.js +2 -0
  24. package/examples/jsm/misc/GPUComputationRenderer.js +6 -7
  25. package/examples/jsm/misc/ProgressiveLightMap.js +4 -3
  26. package/examples/jsm/misc/ProgressiveLightMapGPU.js +4 -3
  27. package/examples/jsm/misc/Volume.js +7 -5
  28. package/examples/jsm/misc/VolumeSlice.js +5 -3
  29. package/examples/jsm/objects/WaterMesh.js +25 -20
  30. package/examples/jsm/physics/JoltPhysics.js +7 -7
  31. package/examples/jsm/physics/RapierPhysics.js +4 -4
  32. package/examples/jsm/postprocessing/EffectComposer.js +23 -2
  33. package/examples/jsm/postprocessing/OutputPass.js +2 -0
  34. package/examples/jsm/postprocessing/Pass.js +6 -1
  35. package/examples/jsm/shaders/OutputShader.js +5 -1
  36. package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
  37. package/examples/jsm/transpiler/TSLEncoder.js +2 -0
  38. package/package.json +1 -1
  39. package/src/Three.Core.js +2 -0
  40. package/src/Three.TSL.js +9 -1
  41. package/src/cameras/ArrayCamera.js +1 -0
  42. package/src/constants.js +6 -1
  43. package/src/core/BufferAttribute.js +4 -0
  44. package/src/core/EventDispatcher.js +8 -6
  45. package/src/extras/ImageUtils.js +1 -11
  46. package/src/loaders/nodes/NodeObjectLoader.js +1 -1
  47. package/src/materials/nodes/MeshBasicNodeMaterial.js +1 -1
  48. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +1 -1
  49. package/src/materials/nodes/NodeMaterial.js +5 -5
  50. package/src/materials/nodes/NodeMaterials.js +0 -1
  51. package/src/materials/nodes/PointsNodeMaterial.js +109 -7
  52. package/src/materials/nodes/SpriteNodeMaterial.js +1 -1
  53. package/src/materials/nodes/VolumeNodeMaterial.js +3 -3
  54. package/src/materials/nodes/manager/NodeMaterialObserver.js +8 -0
  55. package/src/nodes/Nodes.js +4 -0
  56. package/src/nodes/TSL.js +4 -0
  57. package/src/nodes/accessors/Arrays.js +30 -8
  58. package/src/nodes/accessors/BatchNode.js +3 -3
  59. package/src/nodes/accessors/BufferAttributeNode.js +1 -1
  60. package/src/nodes/accessors/Camera.js +64 -3
  61. package/src/nodes/accessors/InstanceNode.js +1 -1
  62. package/src/nodes/accessors/MaterialNode.js +9 -9
  63. package/src/nodes/accessors/ModelViewProjectionNode.js +1 -1
  64. package/src/nodes/accessors/Normal.js +6 -2
  65. package/src/nodes/accessors/Object3DNode.js +0 -1
  66. package/src/nodes/accessors/Position.js +6 -6
  67. package/src/nodes/accessors/ReferenceBaseNode.js +2 -4
  68. package/src/nodes/accessors/ReferenceNode.js +2 -3
  69. package/src/nodes/accessors/StorageBufferNode.js +42 -5
  70. package/src/nodes/accessors/Tangent.js +2 -2
  71. package/src/nodes/accessors/Texture3DNode.js +1 -1
  72. package/src/nodes/accessors/TextureNode.js +12 -5
  73. package/src/nodes/accessors/UniformArrayNode.js +9 -3
  74. package/src/nodes/accessors/VelocityNode.js +0 -2
  75. package/src/nodes/code/ScriptableNode.js +3 -3
  76. package/src/nodes/core/ArrayNode.js +125 -0
  77. package/src/nodes/core/ConstNode.js +8 -0
  78. package/src/nodes/core/Node.js +14 -1
  79. package/src/nodes/core/NodeBuilder.js +229 -19
  80. package/src/nodes/core/NodeUtils.js +11 -1
  81. package/src/nodes/core/NodeVar.js +17 -1
  82. package/src/nodes/core/OutputStructNode.js +19 -9
  83. package/src/nodes/core/StackNode.js +20 -1
  84. package/src/nodes/core/StructNode.js +121 -0
  85. package/src/nodes/core/StructType.js +13 -0
  86. package/src/nodes/core/StructTypeNode.js +82 -21
  87. package/src/nodes/core/TempNode.js +1 -1
  88. package/src/nodes/core/VarNode.js +94 -7
  89. package/src/nodes/core/VaryingNode.js +19 -3
  90. package/src/nodes/display/BlendModes.js +88 -1
  91. package/src/nodes/display/BumpMapNode.js +6 -6
  92. package/src/nodes/display/NormalMapNode.js +6 -6
  93. package/src/nodes/display/PassNode.js +3 -1
  94. package/src/nodes/display/ScreenNode.js +9 -0
  95. package/src/nodes/fog/Fog.js +17 -0
  96. package/src/nodes/gpgpu/AtomicFunctionNode.js +20 -4
  97. package/src/nodes/gpgpu/ComputeBuiltinNode.js +8 -0
  98. package/src/nodes/gpgpu/WorkgroupInfoNode.js +1 -1
  99. package/src/nodes/lighting/ShadowNode.js +1 -1
  100. package/src/nodes/math/ConditionalNode.js +8 -1
  101. package/src/nodes/math/MathNode.js +14 -1
  102. package/src/nodes/math/OperatorNode.js +96 -18
  103. package/src/nodes/pmrem/PMREMUtils.js +1 -1
  104. package/src/nodes/shapes/Shapes.js +33 -0
  105. package/src/nodes/tsl/TSLBase.js +1 -0
  106. package/src/nodes/tsl/TSLCore.js +22 -2
  107. package/src/nodes/utils/ArrayElementNode.js +1 -1
  108. package/src/nodes/utils/LoopNode.js +8 -1
  109. package/src/nodes/utils/MemberNode.js +68 -0
  110. package/src/nodes/utils/StorageArrayElementNode.js +14 -0
  111. package/src/nodes/utils/Timer.js +21 -0
  112. package/src/objects/BatchedMesh.js +1 -1
  113. package/src/objects/Line.js +6 -6
  114. package/src/renderers/WebGLRenderer.js +7 -0
  115. package/src/renderers/common/Animation.js +23 -1
  116. package/src/renderers/common/Backend.js +58 -15
  117. package/src/renderers/common/Background.js +14 -0
  118. package/src/renderers/common/Binding.js +1 -1
  119. package/src/renderers/common/BufferUtils.js +1 -1
  120. package/src/renderers/common/BundleGroup.js +1 -1
  121. package/src/renderers/common/ChainMap.js +9 -7
  122. package/src/renderers/common/ClippingContext.js +1 -1
  123. package/src/renderers/common/Color4.js +7 -3
  124. package/src/renderers/common/Geometries.js +2 -23
  125. package/src/renderers/common/Info.js +1 -45
  126. package/src/renderers/common/Lighting.js +8 -6
  127. package/src/renderers/common/Pipelines.js +3 -3
  128. package/src/renderers/common/PostProcessing.js +24 -8
  129. package/src/renderers/common/QuadMesh.js +1 -1
  130. package/src/renderers/common/RenderBundles.js +9 -3
  131. package/src/renderers/common/RenderContext.js +37 -3
  132. package/src/renderers/common/RenderContexts.js +30 -17
  133. package/src/renderers/common/RenderList.js +2 -2
  134. package/src/renderers/common/RenderLists.js +9 -3
  135. package/src/renderers/common/RenderObject.js +76 -17
  136. package/src/renderers/common/RenderObjects.js +9 -7
  137. package/src/renderers/common/Renderer.js +86 -67
  138. package/src/renderers/common/SampledTexture.js +0 -1
  139. package/src/renderers/common/StorageBufferAttribute.js +1 -1
  140. package/src/renderers/common/StorageInstancedBufferAttribute.js +1 -1
  141. package/src/renderers/common/StorageTexture.js +1 -1
  142. package/src/renderers/common/Textures.js +14 -7
  143. package/src/renderers/common/TimestampQueryPool.js +39 -0
  144. package/src/renderers/common/Uniform.js +37 -1
  145. package/src/renderers/common/UniformsGroup.js +2 -0
  146. package/src/renderers/common/XRManager.js +1193 -0
  147. package/src/renderers/common/XRRenderTarget.js +74 -0
  148. package/src/renderers/common/extras/PMREMGenerator.js +53 -8
  149. package/src/renderers/common/nodes/NodeBuilderState.js +4 -4
  150. package/src/renderers/common/nodes/NodeLibrary.js +5 -5
  151. package/src/renderers/common/nodes/NodeSampledTexture.js +0 -1
  152. package/src/renderers/common/nodes/NodeUniform.js +54 -2
  153. package/src/renderers/common/nodes/Nodes.js +25 -18
  154. package/src/renderers/webgl/WebGLBackground.js +4 -0
  155. package/src/renderers/webgl-fallback/WebGLBackend.js +295 -110
  156. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +347 -17
  157. package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +57 -0
  158. package/src/renderers/webgl-fallback/utils/WebGLCapabilities.js +28 -0
  159. package/src/renderers/webgl-fallback/utils/WebGLExtensions.js +45 -0
  160. package/src/renderers/webgl-fallback/utils/WebGLState.js +323 -11
  161. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +167 -21
  162. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +359 -0
  163. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +43 -0
  164. package/src/renderers/webgpu/WebGPUBackend.js +132 -149
  165. package/src/renderers/webgpu/WebGPURenderer.Nodes.js +6 -4
  166. package/src/renderers/webgpu/WebGPURenderer.js +5 -4
  167. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +615 -41
  168. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +85 -6
  169. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +85 -0
  170. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +102 -3
  171. package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +98 -1
  172. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +257 -9
  173. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +274 -0
  174. package/src/renderers/webgpu/utils/WebGPUUtils.js +86 -4
  175. package/src/renderers/webxr/WebXRManager.js +13 -2
  176. package/src/textures/VideoFrameTexture.js +35 -0
  177. package/examples/jsm/geometries/InstancedPointsGeometry.js +0 -176
  178. package/examples/jsm/objects/InstancedPoints.js +0 -19
  179. package/src/materials/nodes/InstancedPointsNodeMaterial.js +0 -209
  180. package/src/nodes/accessors/InstancedPointsMaterialNode.js +0 -37
@@ -157,30 +157,83 @@ if ( ( typeof navigator !== 'undefined' && /Firefox|Deno/g.test( navigator.userA
157
157
 
158
158
  }
159
159
 
160
- //
161
-
160
+ /**
161
+ * A node builder targeting WGSL.
162
+ *
163
+ * This module generates WGSL shader code from node materials and also
164
+ * generates the respective bindings and vertex buffer definitions. These
165
+ * data are later used by the renderer to create render and compute pipelines
166
+ * for render objects.
167
+ *
168
+ * @augments NodeBuilder
169
+ */
162
170
  class WGSLNodeBuilder extends NodeBuilder {
163
171
 
172
+ /**
173
+ * Constructs a new WGSL node builder renderer.
174
+ *
175
+ * @param {Object3D} object - The 3D object.
176
+ * @param {Renderer} renderer - The renderer.
177
+ */
164
178
  constructor( object, renderer ) {
165
179
 
166
180
  super( object, renderer, new WGSLNodeParser() );
167
181
 
182
+ /**
183
+ * A dictionary that holds for each shader stage ('vertex', 'fragment', 'compute')
184
+ * another dictionary which manages UBOs per group ('render','frame','object').
185
+ *
186
+ * @type {Object<String,Object<String,NodeUniformsGroup>>}
187
+ */
168
188
  this.uniformGroups = {};
169
189
 
190
+ /**
191
+ * A dictionary that holds for each shader stage a Map of builtins.
192
+ *
193
+ * @type {Object<String,Map<String,Object>>}
194
+ */
170
195
  this.builtins = {};
171
196
 
197
+ /**
198
+ * A dictionary that holds for each shader stage a Set of directives.
199
+ *
200
+ * @type {Object<String,Set<String>>}
201
+ */
172
202
  this.directives = {};
173
203
 
204
+ /**
205
+ * A map for managing scope arrays. Only relevant for when using
206
+ * {@link module:WorkgroupInfoNode} in context of compute shaders.
207
+ *
208
+ * @type {Map<String,Object>}
209
+ */
174
210
  this.scopedArrays = new Map();
175
211
 
176
212
  }
177
213
 
214
+ /**
215
+ * Checks if the given texture requires a manual conversion to the working color space.
216
+ *
217
+ * @param {Texture} texture - The texture to check.
218
+ * @return {Boolean} Whether the given texture requires a conversion to working color space or not.
219
+ */
178
220
  needsToWorkingColorSpace( texture ) {
179
221
 
180
222
  return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace;
181
223
 
182
224
  }
183
225
 
226
+ /**
227
+ * Generates the WGSL snippet for sampled textures.
228
+ *
229
+ * @private
230
+ * @param {Texture} texture - The texture.
231
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
232
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
233
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
234
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
235
+ * @return {String} The WGSL snippet.
236
+ */
184
237
  _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) {
185
238
 
186
239
  if ( shaderStage === 'fragment' ) {
@@ -207,6 +260,15 @@ class WGSLNodeBuilder extends NodeBuilder {
207
260
 
208
261
  }
209
262
 
263
+ /**
264
+ * Generates the WGSL snippet when sampling video textures.
265
+ *
266
+ * @private
267
+ * @param {String} textureProperty - The name of the video texture uniform in the shader.
268
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
269
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
270
+ * @return {String} The WGSL snippet.
271
+ */
210
272
  _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
211
273
 
212
274
  if ( shaderStage === 'fragment' ) {
@@ -221,6 +283,18 @@ class WGSLNodeBuilder extends NodeBuilder {
221
283
 
222
284
  }
223
285
 
286
+ /**
287
+ * Generates the WGSL snippet when sampling textures with explicit mip level.
288
+ *
289
+ * @private
290
+ * @param {Texture} texture - The texture.
291
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
292
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
293
+ * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
294
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
295
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
296
+ * @return {String} The WGSL snippet.
297
+ */
224
298
  _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) {
225
299
 
226
300
  if ( ( shaderStage === 'fragment' || shaderStage === 'compute' ) && this.isUnfilterable( texture ) === false ) {
@@ -239,6 +313,12 @@ class WGSLNodeBuilder extends NodeBuilder {
239
313
 
240
314
  }
241
315
 
316
+ /**
317
+ * Generates a wrap function used in context of textures.
318
+ *
319
+ * @param {Texture} texture - The texture to generate the function for.
320
+ * @return {String} The name of the generated function.
321
+ */
242
322
  generateWrapFunction( texture ) {
243
323
 
244
324
  const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }_${texture.isData3DTexture ? '3d' : '2d'}T`;
@@ -308,6 +388,29 @@ class WGSLNodeBuilder extends NodeBuilder {
308
388
 
309
389
  }
310
390
 
391
+ /**
392
+ * Generates the array declaration string.
393
+ *
394
+ * @param {String} type - The type.
395
+ * @param {Number?} [count] - The count.
396
+ * @return {String} The generated value as a shader string.
397
+ */
398
+ generateArrayDeclaration( type, count ) {
399
+
400
+ return `array< ${ this.getType( type ) }, ${ count } >`;
401
+
402
+ }
403
+
404
+ /**
405
+ * Generates a WGSL variable that holds the texture dimension of the given texture.
406
+ * It also returns information about the the number of layers (elements) of an arrayed
407
+ * texture as well as the cube face count of cube textures.
408
+ *
409
+ * @param {Texture} texture - The texture to generate the function for.
410
+ * @param {String} textureProperty - The name of the video texture uniform in the shader.
411
+ * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
412
+ * @return {String} The name of the dimension variable.
413
+ */
311
414
  generateTextureDimension( texture, textureProperty, levelSnippet ) {
312
415
 
313
416
  const textureData = this.getDataFromNode( texture, this.shaderStage, this.globalCache );
@@ -376,6 +479,15 @@ class WGSLNodeBuilder extends NodeBuilder {
376
479
 
377
480
  }
378
481
 
482
+ /**
483
+ * Generates the WGSL snippet for a manual filtered texture.
484
+ *
485
+ * @param {Texture} texture - The texture.
486
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
487
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
488
+ * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
489
+ * @return {String} The WGSL snippet.
490
+ */
379
491
  generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0u' ) {
380
492
 
381
493
  this._include( 'biquadraticTexture' );
@@ -387,6 +499,17 @@ class WGSLNodeBuilder extends NodeBuilder {
387
499
 
388
500
  }
389
501
 
502
+ /**
503
+ * Generates the WGSL snippet for a texture lookup with explicit level-of-detail.
504
+ * Since it's a lookup, no sampling or filtering is applied.
505
+ *
506
+ * @param {Texture} texture - The texture.
507
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
508
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
509
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
510
+ * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
511
+ * @return {String} The WGSL snippet.
512
+ */
390
513
  generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet = '0u' ) {
391
514
 
392
515
  const wrapFunction = this.generateWrapFunction( texture );
@@ -399,6 +522,16 @@ class WGSLNodeBuilder extends NodeBuilder {
399
522
 
400
523
  }
401
524
 
525
+ /**
526
+ * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering.
527
+ *
528
+ * @param {Texture} texture - The texture.
529
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
530
+ * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling.
531
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
532
+ * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
533
+ * @return {String} The WGSL snippet.
534
+ */
402
535
  generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) {
403
536
 
404
537
  if ( texture.isVideoTexture === true || texture.isStorageTexture === true ) {
@@ -417,18 +550,39 @@ class WGSLNodeBuilder extends NodeBuilder {
417
550
 
418
551
  }
419
552
 
553
+ /**
554
+ * Generates the WGSL snippet that writes a single texel to a texture.
555
+ *
556
+ * @param {Texture} texture - The texture.
557
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
558
+ * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling.
559
+ * @param {String} valueSnippet - A WGSL snippet that represent the new texel value.
560
+ * @return {String} The WGSL snippet.
561
+ */
420
562
  generateTextureStore( texture, textureProperty, uvIndexSnippet, valueSnippet ) {
421
563
 
422
564
  return `textureStore( ${ textureProperty }, ${ uvIndexSnippet }, ${ valueSnippet } )`;
423
565
 
424
566
  }
425
567
 
568
+ /**
569
+ * Returns `true` if the sampled values of the given texture should be compared against a reference value.
570
+ *
571
+ * @param {Texture} texture - The texture.
572
+ * @return {Boolean} Whether the sampled values of the given texture should be compared against a reference value or not.
573
+ */
426
574
  isSampleCompare( texture ) {
427
575
 
428
576
  return texture.isDepthTexture === true && texture.compareFunction !== null;
429
577
 
430
578
  }
431
579
 
580
+ /**
581
+ * Returns `true` if the given texture is unfilterable.
582
+ *
583
+ * @param {Texture} texture - The texture.
584
+ * @return {Boolean} Whether the given texture is unfilterable or not.
585
+ */
432
586
  isUnfilterable( texture ) {
433
587
 
434
588
  return this.getComponentTypeFromTexture( texture ) !== 'float' ||
@@ -438,6 +592,16 @@ class WGSLNodeBuilder extends NodeBuilder {
438
592
 
439
593
  }
440
594
 
595
+ /**
596
+ * Generates the WGSL snippet for sampling/loading the given texture.
597
+ *
598
+ * @param {Texture} texture - The texture.
599
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
600
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
601
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
602
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
603
+ * @return {String} The WGSL snippet.
604
+ */
441
605
  generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) {
442
606
 
443
607
  let snippet = null;
@@ -460,6 +624,17 @@ class WGSLNodeBuilder extends NodeBuilder {
460
624
 
461
625
  }
462
626
 
627
+ /**
628
+ * Generates the WGSL snippet for sampling/loading the given texture using explicit gradients.
629
+ *
630
+ * @param {Texture} texture - The texture.
631
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
632
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
633
+ * @param {Array<String>} gradSnippet - An array holding both gradient WGSL snippets.
634
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
635
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
636
+ * @return {String} The WGSL snippet.
637
+ */
463
638
  generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) {
464
639
 
465
640
  if ( shaderStage === 'fragment' ) {
@@ -475,6 +650,18 @@ class WGSLNodeBuilder extends NodeBuilder {
475
650
 
476
651
  }
477
652
 
653
+ /**
654
+ * Generates the WGSL snippet for sampling a depth texture and comparing the sampled depth values
655
+ * against a reference value.
656
+ *
657
+ * @param {Texture} texture - The texture.
658
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
659
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
660
+ * @param {String} compareSnippet - A WGSL snippet that represents the reference value.
661
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
662
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
663
+ * @return {String} The WGSL snippet.
664
+ */
478
665
  generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) {
479
666
 
480
667
  if ( shaderStage === 'fragment' ) {
@@ -489,6 +676,17 @@ class WGSLNodeBuilder extends NodeBuilder {
489
676
 
490
677
  }
491
678
 
679
+ /**
680
+ * Generates the WGSL snippet when sampling textures with explicit mip level.
681
+ *
682
+ * @param {Texture} texture - The texture.
683
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
684
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
685
+ * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
686
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
687
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
688
+ * @return {String} The WGSL snippet.
689
+ */
492
690
  generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) {
493
691
 
494
692
  let snippet = null;
@@ -507,6 +705,17 @@ class WGSLNodeBuilder extends NodeBuilder {
507
705
 
508
706
  }
509
707
 
708
+ /**
709
+ * Generates the WGSL snippet when sampling textures with a bias to the mip level.
710
+ *
711
+ * @param {Texture} texture - The texture.
712
+ * @param {String} textureProperty - The name of the texture uniform in the shader.
713
+ * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
714
+ * @param {String} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling.
715
+ * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
716
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
717
+ * @return {String} The WGSL snippet.
718
+ */
510
719
  generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) {
511
720
 
512
721
  if ( shaderStage === 'fragment' ) {
@@ -521,6 +730,13 @@ class WGSLNodeBuilder extends NodeBuilder {
521
730
 
522
731
  }
523
732
 
733
+ /**
734
+ * Returns a WGSL snippet that represents the property name of the given node.
735
+ *
736
+ * @param {Node} node - The node.
737
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
738
+ * @return {String} The property name.
739
+ */
524
740
  getPropertyName( node, shaderStage = this.shaderStage ) {
525
741
 
526
742
  if ( node.isNodeVarying === true && node.needsInterpolation === true ) {
@@ -542,7 +758,13 @@ class WGSLNodeBuilder extends NodeBuilder {
542
758
 
543
759
  } else if ( type === 'buffer' || type === 'storageBuffer' || type === 'indirectStorageBuffer' ) {
544
760
 
545
- return `NodeBuffer_${ node.id }.${name}`;
761
+ if ( this.isCustomStruct( node ) ) {
762
+
763
+ return name;
764
+
765
+ }
766
+
767
+ return name + '.value';
546
768
 
547
769
  } else {
548
770
 
@@ -556,18 +778,36 @@ class WGSLNodeBuilder extends NodeBuilder {
556
778
 
557
779
  }
558
780
 
781
+ /**
782
+ * Returns the output struct name.
783
+ *
784
+ * @return {String} The name of the output struct.
785
+ */
559
786
  getOutputStructName() {
560
787
 
561
788
  return 'output';
562
789
 
563
790
  }
564
791
 
792
+ /**
793
+ * Returns uniforms group count for the given shader stage.
794
+ *
795
+ * @private
796
+ * @param {String} shaderStage - The shader stage.
797
+ * @return {Number} The uniforms group count for the given shader stage.
798
+ */
565
799
  _getUniformGroupCount( shaderStage ) {
566
800
 
567
801
  return Object.keys( this.uniforms[ shaderStage ] ).length;
568
802
 
569
803
  }
570
804
 
805
+ /**
806
+ * Returns the native shader operator name for a given generic name.
807
+ *
808
+ * @param {String} op - The operator name to resolve.
809
+ * @return {String} The resolved operator name.
810
+ */
571
811
  getFunctionOperator( op ) {
572
812
 
573
813
  const fnOp = wgslFnOpLib[ op ];
@@ -584,6 +824,13 @@ class WGSLNodeBuilder extends NodeBuilder {
584
824
 
585
825
  }
586
826
 
827
+ /**
828
+ * Returns the node access for the given node and shader stage.
829
+ *
830
+ * @param {StorageTextureNode|StorageBufferNode} node - The storage node.
831
+ * @param {String} shaderStage - The shader stage.
832
+ * @return {String} The node access.
833
+ */
587
834
  getNodeAccess( node, shaderStage ) {
588
835
 
589
836
  if ( shaderStage !== 'compute' )
@@ -593,12 +840,32 @@ class WGSLNodeBuilder extends NodeBuilder {
593
840
 
594
841
  }
595
842
 
843
+ /**
844
+ * Returns A WGSL snippet representing the storage access.
845
+ *
846
+ * @param {StorageTextureNode|StorageBufferNode} node - The storage node.
847
+ * @param {String} shaderStage - The shader stage.
848
+ * @return {String} The WGSL snippet representing the storage access.
849
+ */
596
850
  getStorageAccess( node, shaderStage ) {
597
851
 
598
852
  return accessNames[ this.getNodeAccess( node, shaderStage ) ];
599
853
 
600
854
  }
601
855
 
856
+ /**
857
+ * This method is one of the more important ones since it's responsible
858
+ * for generating a matching binding instance for the given uniform node.
859
+ *
860
+ * These bindings are later used in the renderer to create bind groups
861
+ * and layouts.
862
+ *
863
+ * @param {UniformNode} node - The uniform node.
864
+ * @param {String} type - The node data type.
865
+ * @param {String} shaderStage - The shader stage.
866
+ * @param {String?} [name=null] - An optional uniform name.
867
+ * @return {NodeUniform} The node uniform object.
868
+ */
602
869
  getUniformFromNode( node, type, shaderStage, name = null ) {
603
870
 
604
871
  const uniformNode = super.getUniformFromNode( node, type, shaderStage, name );
@@ -638,7 +905,7 @@ class WGSLNodeBuilder extends NodeBuilder {
638
905
 
639
906
  if ( ( shaderStage === 'fragment' || shaderStage === 'compute' ) && this.isUnfilterable( node.value ) === false && texture.store === false ) {
640
907
 
641
- const sampler = new NodeSampler( `${uniformNode.name}_sampler`, uniformNode.node, group );
908
+ const sampler = new NodeSampler( `${ uniformNode.name }_sampler`, uniformNode.node, group );
642
909
  sampler.setVisibility( gpuShaderStageLib[ shaderStage ] );
643
910
 
644
911
  bindings.push( sampler, texture );
@@ -664,6 +931,8 @@ class WGSLNodeBuilder extends NodeBuilder {
664
931
 
665
932
  uniformGPU = buffer;
666
933
 
934
+ uniformNode.name = name ? name : 'NodeBuffer_' + uniformNode.id;
935
+
667
936
  } else {
668
937
 
669
938
  const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} );
@@ -695,6 +964,17 @@ class WGSLNodeBuilder extends NodeBuilder {
695
964
 
696
965
  }
697
966
 
967
+ /**
968
+ * This method should be used whenever builtins are required in nodes.
969
+ * The internal builtins data structure will make sure builtins are
970
+ * defined in the WGSL source.
971
+ *
972
+ * @param {String} name - The builtin name.
973
+ * @param {String} property - The property name.
974
+ * @param {String} type - The node data type.
975
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
976
+ * @return {String} The property name.
977
+ */
698
978
  getBuiltin( name, property, type, shaderStage = this.shaderStage ) {
699
979
 
700
980
  const map = this.builtins[ shaderStage ] || ( this.builtins[ shaderStage ] = new Map() );
@@ -713,12 +993,24 @@ class WGSLNodeBuilder extends NodeBuilder {
713
993
 
714
994
  }
715
995
 
996
+ /**
997
+ * Returns `true` if the given builtin is defined in the given shader stage.
998
+ *
999
+ * @param {String} name - The builtin name.
1000
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
1001
+ * @return {String} Whether the given builtin is defined in the given shader stage or not.
1002
+ */
716
1003
  hasBuiltin( name, shaderStage = this.shaderStage ) {
717
1004
 
718
1005
  return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) );
719
1006
 
720
1007
  }
721
1008
 
1009
+ /**
1010
+ * Returns the vertex index builtin.
1011
+ *
1012
+ * @return {String} The vertex index.
1013
+ */
722
1014
  getVertexIndex() {
723
1015
 
724
1016
  if ( this.shaderStage === 'vertex' ) {
@@ -731,6 +1023,12 @@ class WGSLNodeBuilder extends NodeBuilder {
731
1023
 
732
1024
  }
733
1025
 
1026
+ /**
1027
+ * Builds the given shader node.
1028
+ *
1029
+ * @param {ShaderNodeInternal} shaderNode - The shader node.
1030
+ * @return {String} The WGSL function code.
1031
+ */
734
1032
  buildFunctionCode( shaderNode ) {
735
1033
 
736
1034
  const layout = shaderNode.layout;
@@ -765,6 +1063,11 @@ ${ flowData.code }
765
1063
 
766
1064
  }
767
1065
 
1066
+ /**
1067
+ * Returns the instance index builtin.
1068
+ *
1069
+ * @return {String} The instance index.
1070
+ */
768
1071
  getInstanceIndex() {
769
1072
 
770
1073
  if ( this.shaderStage === 'vertex' ) {
@@ -777,12 +1080,22 @@ ${ flowData.code }
777
1080
 
778
1081
  }
779
1082
 
1083
+ /**
1084
+ * Returns the invocation local index builtin.
1085
+ *
1086
+ * @return {String} The invocation local index.
1087
+ */
780
1088
  getInvocationLocalIndex() {
781
1089
 
782
1090
  return this.getBuiltin( 'local_invocation_index', 'invocationLocalIndex', 'u32', 'attribute' );
783
1091
 
784
1092
  }
785
1093
 
1094
+ /**
1095
+ * Returns the subgroup size builtin.
1096
+ *
1097
+ * @return {String} The subgroup size.
1098
+ */
786
1099
  getSubgroupSize() {
787
1100
 
788
1101
  this.enableSubGroups();
@@ -791,6 +1104,11 @@ ${ flowData.code }
791
1104
 
792
1105
  }
793
1106
 
1107
+ /**
1108
+ * Returns the invocation subgroup index builtin.
1109
+ *
1110
+ * @return {String} The invocation subgroup index.
1111
+ */
794
1112
  getInvocationSubgroupIndex() {
795
1113
 
796
1114
  this.enableSubGroups();
@@ -799,6 +1117,11 @@ ${ flowData.code }
799
1117
 
800
1118
  }
801
1119
 
1120
+ /**
1121
+ * Returns the subgroup index builtin.
1122
+ *
1123
+ * @return {String} The subgroup index.
1124
+ */
802
1125
  getSubgroupIndex() {
803
1126
 
804
1127
  this.enableSubGroups();
@@ -807,42 +1130,78 @@ ${ flowData.code }
807
1130
 
808
1131
  }
809
1132
 
1133
+ /**
1134
+ * Overwritten as a NOP since this method is intended for the WebGL 2 backend.
1135
+ *
1136
+ * @return {null} Null.
1137
+ */
810
1138
  getDrawIndex() {
811
1139
 
812
1140
  return null;
813
1141
 
814
1142
  }
815
1143
 
1144
+ /**
1145
+ * Returns the front facing builtin.
1146
+ *
1147
+ * @return {String} The front facing builtin.
1148
+ */
816
1149
  getFrontFacing() {
817
1150
 
818
1151
  return this.getBuiltin( 'front_facing', 'isFront', 'bool' );
819
1152
 
820
1153
  }
821
1154
 
1155
+ /**
1156
+ * Returns the frag coord builtin.
1157
+ *
1158
+ * @return {String} The frag coord builtin.
1159
+ */
822
1160
  getFragCoord() {
823
1161
 
824
1162
  return this.getBuiltin( 'position', 'fragCoord', 'vec4<f32>' ) + '.xy';
825
1163
 
826
1164
  }
827
1165
 
1166
+ /**
1167
+ * Returns the frag depth builtin.
1168
+ *
1169
+ * @return {String} The frag depth builtin.
1170
+ */
828
1171
  getFragDepth() {
829
1172
 
830
1173
  return 'output.' + this.getBuiltin( 'frag_depth', 'depth', 'f32', 'output' );
831
1174
 
832
1175
  }
833
1176
 
1177
+ /**
1178
+ * Returns the clip distances builtin.
1179
+ *
1180
+ * @return {String} The clip distances builtin.
1181
+ */
834
1182
  getClipDistance() {
835
1183
 
836
1184
  return 'varyings.hw_clip_distances';
837
1185
 
838
1186
  }
839
1187
 
1188
+ /**
1189
+ * Whether to flip texture data along its vertical axis or not.
1190
+ *
1191
+ * @return {Boolean} Returns always `false` in context of WGSL.
1192
+ */
840
1193
  isFlipY() {
841
1194
 
842
1195
  return false;
843
1196
 
844
1197
  }
845
1198
 
1199
+ /**
1200
+ * Enables the given directive for the given shader stage.
1201
+ *
1202
+ * @param {String} name - The directive name.
1203
+ * @param {String} [shaderStage=this.shaderStage] - The shader stage to enable the directive for.
1204
+ */
846
1205
  enableDirective( name, shaderStage = this.shaderStage ) {
847
1206
 
848
1207
  const stage = this.directives[ shaderStage ] || ( this.directives[ shaderStage ] = new Set() );
@@ -850,6 +1209,12 @@ ${ flowData.code }
850
1209
 
851
1210
  }
852
1211
 
1212
+ /**
1213
+ * Returns the directives of the given shader stage as a WGSL string.
1214
+ *
1215
+ * @param {String} shaderStage - The shader stage.
1216
+ * @return {String} A WGSL snippet that enables the directives of the given stage.
1217
+ */
853
1218
  getDirectives( shaderStage ) {
854
1219
 
855
1220
  const snippets = [];
@@ -869,36 +1234,56 @@ ${ flowData.code }
869
1234
 
870
1235
  }
871
1236
 
1237
+ /**
1238
+ * Enables the 'subgroups' directive.
1239
+ */
872
1240
  enableSubGroups() {
873
1241
 
874
1242
  this.enableDirective( 'subgroups' );
875
1243
 
876
1244
  }
877
1245
 
1246
+ /**
1247
+ * Enables the 'subgroups-f16' directive.
1248
+ */
878
1249
  enableSubgroupsF16() {
879
1250
 
880
1251
  this.enableDirective( 'subgroups-f16' );
881
1252
 
882
1253
  }
883
1254
 
1255
+ /**
1256
+ * Enables the 'clip_distances' directive.
1257
+ */
884
1258
  enableClipDistances() {
885
1259
 
886
1260
  this.enableDirective( 'clip_distances' );
887
1261
 
888
1262
  }
889
1263
 
1264
+ /**
1265
+ * Enables the 'f16' directive.
1266
+ */
890
1267
  enableShaderF16() {
891
1268
 
892
1269
  this.enableDirective( 'f16' );
893
1270
 
894
1271
  }
895
1272
 
1273
+ /**
1274
+ * Enables the 'dual_source_blending' directive.
1275
+ */
896
1276
  enableDualSourceBlending() {
897
1277
 
898
1278
  this.enableDirective( 'dual_source_blending' );
899
1279
 
900
1280
  }
901
1281
 
1282
+ /**
1283
+ * Enables hardware clipping.
1284
+ *
1285
+ * @param {String} planeCount - The clipping plane count.
1286
+ */
902
1287
  enableHardwareClipping( planeCount ) {
903
1288
 
904
1289
  this.enableClipDistances();
@@ -906,6 +1291,12 @@ ${ flowData.code }
906
1291
 
907
1292
  }
908
1293
 
1294
+ /**
1295
+ * Returns the builtins of the given shader stage as a WGSL string.
1296
+ *
1297
+ * @param {String} shaderStage - The shader stage.
1298
+ * @return {String} A WGSL snippet that represents the builtins of the given stage.
1299
+ */
909
1300
  getBuiltins( shaderStage ) {
910
1301
 
911
1302
  const snippets = [];
@@ -925,6 +1316,17 @@ ${ flowData.code }
925
1316
 
926
1317
  }
927
1318
 
1319
+ /**
1320
+ * This method should be used when a new scoped buffer is used in context of
1321
+ * compute shaders. It adds the array to the internal data structure which is
1322
+ * later used to generate the respective WGSL.
1323
+ *
1324
+ * @param {String} name - The array name.
1325
+ * @param {String} scope - The scope.
1326
+ * @param {String} bufferType - The buffer type.
1327
+ * @param {String} bufferCount - The buffer count.
1328
+ * @return {String} The array name.
1329
+ */
928
1330
  getScopedArray( name, scope, bufferType, bufferCount ) {
929
1331
 
930
1332
  if ( this.scopedArrays.has( name ) === false ) {
@@ -942,6 +1344,13 @@ ${ flowData.code }
942
1344
 
943
1345
  }
944
1346
 
1347
+ /**
1348
+ * Returns the scoped arrays of the given shader stage as a WGSL string.
1349
+ *
1350
+ * @param {String} shaderStage - The shader stage.
1351
+ * @return {String|undefined} The WGSL snippet that defines the scoped arrays.
1352
+ * Returns `undefined` when used in the vertex or fragment stage.
1353
+ */
945
1354
  getScopedArrays( shaderStage ) {
946
1355
 
947
1356
  if ( shaderStage !== 'compute' ) {
@@ -964,13 +1373,19 @@ ${ flowData.code }
964
1373
 
965
1374
  }
966
1375
 
1376
+ /**
1377
+ * Returns the shader attributes of the given shader stage as a WGSL string.
1378
+ *
1379
+ * @param {String} shaderStage - The shader stage.
1380
+ * @return {String} The WGSL snippet that defines the shader attributes.
1381
+ */
967
1382
  getAttributes( shaderStage ) {
968
1383
 
969
1384
  const snippets = [];
970
1385
 
971
1386
  if ( shaderStage === 'compute' ) {
972
1387
 
973
- this.getBuiltin( 'global_invocation_id', 'id', 'vec3<u32>', 'attribute' );
1388
+ this.getBuiltin( 'global_invocation_id', 'globalId', 'vec3<u32>', 'attribute' );
974
1389
  this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3<u32>', 'attribute' );
975
1390
  this.getBuiltin( 'local_invocation_id', 'localId', 'vec3<u32>', 'attribute' );
976
1391
  this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3<u32>', 'attribute' );
@@ -1008,57 +1423,102 @@ ${ flowData.code }
1008
1423
 
1009
1424
  }
1010
1425
 
1426
+ /**
1427
+ * Returns the members of the given struct type node as a WGSL string.
1428
+ *
1429
+ * @param {StructTypeNode} struct - The struct type node.
1430
+ * @return {String} The WGSL snippet that defines the struct members.
1431
+ */
1011
1432
  getStructMembers( struct ) {
1012
1433
 
1013
1434
  const snippets = [];
1014
- const members = struct.getMemberTypes();
1015
1435
 
1016
- for ( let i = 0; i < members.length; i ++ ) {
1436
+ for ( const member of struct.members ) {
1017
1437
 
1018
- const member = members[ i ];
1019
- snippets.push( `\t@location( ${i} ) m${i} : ${ member }<f32>` );
1438
+ const prefix = struct.output ? '@location( ' + member.index + ' ) ' : '';
1020
1439
 
1021
- }
1440
+ let type = this.getType( member.type );
1022
1441
 
1023
- const builtins = this.getBuiltins( 'output' );
1442
+ if ( member.atomic ) {
1443
+
1444
+ type = 'atomic< ' + type + ' >';
1445
+
1446
+ }
1024
1447
 
1025
- if ( builtins ) snippets.push( '\t' + builtins );
1448
+ snippets.push( `\t${ prefix + member.name } : ${ type }` );
1449
+
1450
+ }
1026
1451
 
1027
1452
  return snippets.join( ',\n' );
1028
1453
 
1029
1454
  }
1030
1455
 
1456
+ /**
1457
+ * Returns the structs of the given shader stage as a WGSL string.
1458
+ *
1459
+ * @param {String} shaderStage - The shader stage.
1460
+ * @return {String} The WGSL snippet that defines the structs.
1461
+ */
1031
1462
  getStructs( shaderStage ) {
1032
1463
 
1033
- const snippets = [];
1464
+ let result = '';
1465
+
1034
1466
  const structs = this.structs[ shaderStage ];
1035
1467
 
1036
- for ( let index = 0, length = structs.length; index < length; index ++ ) {
1468
+ if ( structs.length > 0 ) {
1037
1469
 
1038
- const struct = structs[ index ];
1039
- const name = struct.name;
1470
+ const snippets = [];
1040
1471
 
1041
- let snippet = `\struct ${ name } {\n`;
1042
- snippet += this.getStructMembers( struct );
1043
- snippet += '\n}';
1472
+ for ( const struct of structs ) {
1044
1473
 
1474
+ let snippet = `struct ${ struct.name } {\n`;
1475
+ snippet += this.getStructMembers( struct );
1476
+ snippet += '\n};';
1045
1477
 
1046
- snippets.push( snippet );
1478
+ snippets.push( snippet );
1047
1479
 
1048
- snippets.push( `\nvar<private> output : ${ name };\n\n` );
1480
+ }
1481
+
1482
+ result = '\n' + snippets.join( '\n\n' ) + '\n';
1049
1483
 
1050
1484
  }
1051
1485
 
1052
- return snippets.join( '\n\n' );
1486
+ return result;
1053
1487
 
1054
1488
  }
1055
1489
 
1056
- getVar( type, name ) {
1490
+ /**
1491
+ * Returns a WGSL string representing a variable.
1492
+ *
1493
+ * @param {String} type - The variable's type.
1494
+ * @param {String} name - The variable's name.
1495
+ * @param {Number?} [count=null] - The array length.
1496
+ * @return {String} The WGSL snippet that defines a variable.
1497
+ */
1498
+ getVar( type, name, count = null ) {
1499
+
1500
+ let snippet = `var ${ name } : `;
1501
+
1502
+ if ( count !== null ) {
1503
+
1504
+ snippet += this.generateArrayDeclaration( type, count );
1505
+
1506
+ } else {
1507
+
1508
+ snippet += this.getType( type );
1509
+
1510
+ }
1057
1511
 
1058
- return `var ${ name } : ${ this.getType( type ) }`;
1512
+ return snippet;
1059
1513
 
1060
1514
  }
1061
1515
 
1516
+ /**
1517
+ * Returns the variables of the given shader stage as a WGSL string.
1518
+ *
1519
+ * @param {String} shaderStage - The shader stage.
1520
+ * @return {String} The WGSL snippet that defines the variables.
1521
+ */
1062
1522
  getVars( shaderStage ) {
1063
1523
 
1064
1524
  const snippets = [];
@@ -1068,7 +1528,7 @@ ${ flowData.code }
1068
1528
 
1069
1529
  for ( const variable of vars ) {
1070
1530
 
1071
- snippets.push( `\t${ this.getVar( variable.type, variable.name ) };` );
1531
+ snippets.push( `\t${ this.getVar( variable.type, variable.name, variable.count ) };` );
1072
1532
 
1073
1533
  }
1074
1534
 
@@ -1078,6 +1538,12 @@ ${ flowData.code }
1078
1538
 
1079
1539
  }
1080
1540
 
1541
+ /**
1542
+ * Returns the varyings of the given shader stage as a WGSL string.
1543
+ *
1544
+ * @param {String} shaderStage - The shader stage.
1545
+ * @return {String} The WGSL snippet that defines the varyings.
1546
+ */
1081
1547
  getVaryings( shaderStage ) {
1082
1548
 
1083
1549
  const snippets = [];
@@ -1130,6 +1596,18 @@ ${ flowData.code }
1130
1596
 
1131
1597
  }
1132
1598
 
1599
+ isCustomStruct( nodeUniform ) {
1600
+
1601
+ return nodeUniform.value.isStorageBufferAttribute && nodeUniform.node.structTypeNode !== null;
1602
+
1603
+ }
1604
+
1605
+ /**
1606
+ * Returns the uniforms of the given shader stage as a WGSL string.
1607
+ *
1608
+ * @param {String} shaderStage - The shader stage.
1609
+ * @return {String} The WGSL snippet that defines the uniforms.
1610
+ */
1133
1611
  getUniforms( shaderStage ) {
1134
1612
 
1135
1613
  const uniforms = this.uniforms[ shaderStage ];
@@ -1205,7 +1683,7 @@ ${ flowData.code }
1205
1683
 
1206
1684
  const componentPrefix = this.getComponentTypeFromTexture( texture ).charAt( 0 );
1207
1685
 
1208
- textureType = `texture${multisampled}_2d<${ componentPrefix }32>`;
1686
+ textureType = `texture${ multisampled }_2d<${ componentPrefix }32>`;
1209
1687
 
1210
1688
  }
1211
1689
 
@@ -1214,15 +1692,23 @@ ${ flowData.code }
1214
1692
  } else if ( uniform.type === 'buffer' || uniform.type === 'storageBuffer' || uniform.type === 'indirectStorageBuffer' ) {
1215
1693
 
1216
1694
  const bufferNode = uniform.node;
1217
- const bufferType = this.getType( bufferNode.bufferType );
1695
+ const bufferType = this.getType( bufferNode.getNodeType( this ) );
1218
1696
  const bufferCount = bufferNode.bufferCount;
1219
-
1220
1697
  const bufferCountSnippet = bufferCount > 0 && uniform.type === 'buffer' ? ', ' + bufferCount : '';
1221
- const bufferTypeSnippet = bufferNode.isAtomic ? `atomic<${bufferType}>` : `${bufferType}`;
1222
- const bufferSnippet = `\t${ uniform.name } : array< ${ bufferTypeSnippet }${ bufferCountSnippet } >\n`;
1223
1698
  const bufferAccessMode = bufferNode.isStorageBufferNode ? `storage, ${ this.getStorageAccess( bufferNode, shaderStage ) }` : 'uniform';
1224
1699
 
1225
- bufferSnippets.push( this._getWGSLStructBinding( 'NodeBuffer_' + bufferNode.id, bufferSnippet, bufferAccessMode, uniformIndexes.binding ++, uniformIndexes.group ) );
1700
+ if ( this.isCustomStruct( uniform ) ) {
1701
+
1702
+ bufferSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var<${ bufferAccessMode }> ${ uniform.name } : ${ bufferType };` );
1703
+
1704
+ } else {
1705
+
1706
+ const bufferTypeSnippet = bufferNode.isAtomic ? `atomic<${ bufferType }>` : `${ bufferType }`;
1707
+ const bufferSnippet = `\tvalue : array< ${ bufferTypeSnippet }${ bufferCountSnippet } >`;
1708
+
1709
+ bufferSnippets.push( this._getWGSLStructBinding( uniform.name, bufferSnippet, bufferAccessMode, uniformIndexes.binding ++, uniformIndexes.group ) );
1710
+
1711
+ }
1226
1712
 
1227
1713
  } else {
1228
1714
 
@@ -1257,6 +1743,9 @@ ${ flowData.code }
1257
1743
 
1258
1744
  }
1259
1745
 
1746
+ /**
1747
+ * Controls the code build of the shader stages.
1748
+ */
1260
1749
  buildCode() {
1261
1750
 
1262
1751
  const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} };
@@ -1265,6 +1754,8 @@ ${ flowData.code }
1265
1754
 
1266
1755
  for ( const shaderStage in shadersData ) {
1267
1756
 
1757
+ this.shaderStage = shaderStage;
1758
+
1268
1759
  const stageData = shadersData[ shaderStage ];
1269
1760
  stageData.uniforms = this.getUniforms( shaderStage );
1270
1761
  stageData.attributes = this.getAttributes( shaderStage );
@@ -1295,7 +1786,7 @@ ${ flowData.code }
1295
1786
 
1296
1787
  if ( flow.length > 0 ) flow += '\n';
1297
1788
 
1298
- flow += `\t// flow -> ${ slotName }\n\t`;
1789
+ flow += `\t// flow -> ${ slotName }\n`;
1299
1790
 
1300
1791
  }
1301
1792
 
@@ -1313,7 +1804,8 @@ ${ flowData.code }
1313
1804
 
1314
1805
  if ( isOutputStruct ) {
1315
1806
 
1316
- stageData.returnType = outputNode.nodeType;
1807
+ stageData.returnType = outputNode.getNodeType( this );
1808
+ stageData.structs += 'var<private> output : ' + stageData.returnType + ';';
1317
1809
 
1318
1810
  flow += `return ${ flowSlotData.result };`;
1319
1811
 
@@ -1327,7 +1819,7 @@ ${ flowData.code }
1327
1819
 
1328
1820
  stageData.returnType = 'OutputStruct';
1329
1821
  stageData.structs += this._getWGSLStruct( 'OutputStruct', structSnippet );
1330
- stageData.structs += '\nvar<private> output : OutputStruct;\n\n';
1822
+ stageData.structs += '\nvar<private> output : OutputStruct;';
1331
1823
 
1332
1824
  flow += `output.color = ${ flowSlotData.result };\n\n\treturn output;`;
1333
1825
 
@@ -1341,9 +1833,10 @@ ${ flowData.code }
1341
1833
 
1342
1834
  stageData.flow = flow;
1343
1835
 
1344
-
1345
1836
  }
1346
1837
 
1838
+ this.shaderStage = null;
1839
+
1347
1840
  if ( this.material !== null ) {
1348
1841
 
1349
1842
  this.vertexShader = this._getWGSLVertexCode( shadersData.vertex );
@@ -1357,6 +1850,13 @@ ${ flowData.code }
1357
1850
 
1358
1851
  }
1359
1852
 
1853
+ /**
1854
+ * Returns the native shader method name for a given generic name.
1855
+ *
1856
+ * @param {String} method - The method name to resolve.
1857
+ * @param {String} [output=null] - An optional output.
1858
+ * @return {String} The resolved WGSL method name.
1859
+ */
1360
1860
  getMethod( method, output = null ) {
1361
1861
 
1362
1862
  let wgslMethod;
@@ -1377,12 +1877,24 @@ ${ flowData.code }
1377
1877
 
1378
1878
  }
1379
1879
 
1880
+ /**
1881
+ * Returns the WGSL type of the given node data type.
1882
+ *
1883
+ * @param {String} type - The node data type.
1884
+ * @return {String} The WGSL type.
1885
+ */
1380
1886
  getType( type ) {
1381
1887
 
1382
1888
  return wgslTypeLib[ type ] || type;
1383
1889
 
1384
1890
  }
1385
1891
 
1892
+ /**
1893
+ * Whether the requested feature is available or not.
1894
+ *
1895
+ * @param {String} name - The requested feature.
1896
+ * @return {Boolean} Whether the requested feature is supported or not.
1897
+ */
1386
1898
  isAvailable( name ) {
1387
1899
 
1388
1900
  let result = supports[ name ];
@@ -1407,6 +1919,13 @@ ${ flowData.code }
1407
1919
 
1408
1920
  }
1409
1921
 
1922
+ /**
1923
+ * Returns the native shader method name for a given generic name.
1924
+ *
1925
+ * @private
1926
+ * @param {String} method - The method name to resolve.
1927
+ * @return {String} The resolved WGSL method name.
1928
+ */
1410
1929
  _getWGSLMethod( method ) {
1411
1930
 
1412
1931
  if ( wgslPolyfill[ method ] !== undefined ) {
@@ -1419,6 +1938,14 @@ ${ flowData.code }
1419
1938
 
1420
1939
  }
1421
1940
 
1941
+ /**
1942
+ * Includes the given method name into the current
1943
+ * function node.
1944
+ *
1945
+ * @private
1946
+ * @param {String} name - The method name to include.
1947
+ * @return {CodeNode} The respective code node.
1948
+ */
1422
1949
  _include( name ) {
1423
1950
 
1424
1951
  const codeNode = wgslPolyfill[ name ];
@@ -1434,12 +1961,22 @@ ${ flowData.code }
1434
1961
 
1435
1962
  }
1436
1963
 
1964
+ /**
1965
+ * Returns a WGSL vertex shader based on the given shader data.
1966
+ *
1967
+ * @private
1968
+ * @param {Object} shaderData - The shader data.
1969
+ * @return {String} The vertex shader.
1970
+ */
1437
1971
  _getWGSLVertexCode( shaderData ) {
1438
1972
 
1439
1973
  return `${ this.getSignature() }
1440
1974
  // directives
1441
1975
  ${shaderData.directives}
1442
1976
 
1977
+ // structs
1978
+ ${shaderData.structs}
1979
+
1443
1980
  // uniforms
1444
1981
  ${shaderData.uniforms}
1445
1982
 
@@ -1466,18 +2003,25 @@ fn main( ${shaderData.attributes} ) -> VaryingsStruct {
1466
2003
 
1467
2004
  }
1468
2005
 
2006
+ /**
2007
+ * Returns a WGSL fragment shader based on the given shader data.
2008
+ *
2009
+ * @private
2010
+ * @param {Object} shaderData - The shader data.
2011
+ * @return {String} The vertex shader.
2012
+ */
1469
2013
  _getWGSLFragmentCode( shaderData ) {
1470
2014
 
1471
2015
  return `${ this.getSignature() }
1472
2016
  // global
1473
2017
  ${ diagnostics }
1474
2018
 
1475
- // uniforms
1476
- ${shaderData.uniforms}
1477
-
1478
2019
  // structs
1479
2020
  ${shaderData.structs}
1480
2021
 
2022
+ // uniforms
2023
+ ${shaderData.uniforms}
2024
+
1481
2025
  // codes
1482
2026
  ${shaderData.codes}
1483
2027
 
@@ -1495,6 +2039,14 @@ fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} {
1495
2039
 
1496
2040
  }
1497
2041
 
2042
+ /**
2043
+ * Returns a WGSL compute shader based on the given shader data.
2044
+ *
2045
+ * @private
2046
+ * @param {Object} shaderData - The shader data.
2047
+ * @param {String} workgroupSize - The workgroup size.
2048
+ * @return {String} The vertex shader.
2049
+ */
1498
2050
  _getWGSLComputeCode( shaderData, workgroupSize ) {
1499
2051
 
1500
2052
  return `${ this.getSignature() }
@@ -1507,6 +2059,9 @@ var<private> instanceIndex : u32;
1507
2059
  // locals
1508
2060
  ${shaderData.scopedArrays}
1509
2061
 
2062
+ // structs
2063
+ ${shaderData.structs}
2064
+
1510
2065
  // uniforms
1511
2066
  ${shaderData.uniforms}
1512
2067
 
@@ -1517,7 +2072,7 @@ ${shaderData.codes}
1517
2072
  fn main( ${shaderData.attributes} ) {
1518
2073
 
1519
2074
  // system
1520
- instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize});
2075
+ instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize});
1521
2076
 
1522
2077
  // vars
1523
2078
  ${shaderData.vars}
@@ -1530,6 +2085,14 @@ fn main( ${shaderData.attributes} ) {
1530
2085
 
1531
2086
  }
1532
2087
 
2088
+ /**
2089
+ * Returns a WGSL struct based on the given name and variables.
2090
+ *
2091
+ * @private
2092
+ * @param {String} name - The struct name.
2093
+ * @param {String} vars - The struct variables.
2094
+ * @return {String} The WGSL snippet representing a struct.
2095
+ */
1533
2096
  _getWGSLStruct( name, vars ) {
1534
2097
 
1535
2098
  return `
@@ -1539,14 +2102,25 @@ ${vars}
1539
2102
 
1540
2103
  }
1541
2104
 
2105
+ /**
2106
+ * Returns a WGSL struct binding.
2107
+ *
2108
+ * @private
2109
+ * @param {String} name - The struct name.
2110
+ * @param {String} vars - The struct variables.
2111
+ * @param {String} access - The access.
2112
+ * @param {Number} [binding=0] - The binding index.
2113
+ * @param {Number} [group=0] - The group index.
2114
+ * @return {String} The WGSL snippet representing a struct binding.
2115
+ */
1542
2116
  _getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) {
1543
2117
 
1544
2118
  const structName = name + 'Struct';
1545
2119
  const structSnippet = this._getWGSLStruct( structName, vars );
1546
2120
 
1547
2121
  return `${structSnippet}
1548
- @binding( ${binding} ) @group( ${group} )
1549
- var<${access}> ${name} : ${structName};`;
2122
+ @binding( ${ binding } ) @group( ${ group } )
2123
+ var<${access}> ${ name } : ${ structName };`;
1550
2124
 
1551
2125
  }
1552
2126