@plastic-software/three 0.178.0 → 0.179.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 (141) hide show
  1. package/README.md +1 -1
  2. package/build/three.cjs +856 -196
  3. package/build/three.core.js +647 -123
  4. package/build/three.core.min.js +1 -1
  5. package/build/three.module.js +211 -76
  6. package/build/three.module.min.js +1 -1
  7. package/build/three.tsl.js +70 -21
  8. package/build/three.tsl.min.js +1 -1
  9. package/build/three.webgpu.js +1796 -557
  10. package/build/three.webgpu.min.js +1 -1
  11. package/build/three.webgpu.nodes.js +1754 -557
  12. package/build/three.webgpu.nodes.min.js +1 -1
  13. package/examples/jsm/Addons.js +1 -2
  14. package/examples/jsm/capabilities/WebGPU.js +1 -1
  15. package/examples/jsm/csm/CSMShadowNode.js +4 -4
  16. package/examples/jsm/environments/RoomEnvironment.js +8 -3
  17. package/examples/jsm/exporters/USDZExporter.js +676 -299
  18. package/examples/jsm/geometries/RoundedBoxGeometry.js +47 -8
  19. package/examples/jsm/interactive/HTMLMesh.js +5 -3
  20. package/examples/jsm/libs/meshopt_decoder.module.js +75 -58
  21. package/examples/jsm/lights/LightProbeGenerator.js +14 -3
  22. package/examples/jsm/loaders/EXRLoader.js +210 -22
  23. package/examples/jsm/loaders/FBXLoader.js +1 -1
  24. package/examples/jsm/loaders/MaterialXLoader.js +212 -30
  25. package/examples/jsm/loaders/TTFLoader.js +13 -1
  26. package/examples/jsm/loaders/USDLoader.js +219 -0
  27. package/examples/jsm/loaders/USDZLoader.js +4 -892
  28. package/examples/jsm/loaders/usd/USDAParser.js +741 -0
  29. package/examples/jsm/loaders/usd/USDCParser.js +17 -0
  30. package/examples/jsm/objects/LensflareMesh.js +3 -3
  31. package/examples/jsm/objects/SkyMesh.js +2 -2
  32. package/examples/jsm/physics/RapierPhysics.js +14 -5
  33. package/examples/jsm/postprocessing/GTAOPass.js +10 -9
  34. package/examples/jsm/postprocessing/OutlinePass.js +17 -17
  35. package/examples/jsm/postprocessing/SSAOPass.js +10 -9
  36. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +11 -2
  37. package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
  38. package/examples/jsm/tsl/display/BloomNode.js +8 -7
  39. package/examples/jsm/tsl/display/GaussianBlurNode.js +6 -8
  40. package/examples/jsm/tsl/display/{TRAAPassNode.js → TRAANode.js} +181 -172
  41. package/examples/jsm/tsl/lighting/TiledLightsNode.js +1 -1
  42. package/package.json +1 -1
  43. package/src/Three.Core.js +1 -0
  44. package/src/Three.TSL.js +69 -20
  45. package/src/animation/KeyframeTrack.js +1 -1
  46. package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
  47. package/src/animation/tracks/StringKeyframeTrack.js +1 -1
  48. package/src/cameras/Camera.js +14 -0
  49. package/src/cameras/OrthographicCamera.js +1 -1
  50. package/src/cameras/PerspectiveCamera.js +1 -1
  51. package/src/constants.js +1 -1
  52. package/{examples/jsm/misc → src/core}/Timer.js +4 -42
  53. package/src/extras/PMREMGenerator.js +11 -0
  54. package/src/helpers/CameraHelper.js +41 -11
  55. package/src/helpers/SkeletonHelper.js +35 -6
  56. package/src/lights/LightShadow.js +21 -8
  57. package/src/lights/PointLightShadow.js +1 -1
  58. package/src/loaders/FileLoader.js +25 -2
  59. package/src/loaders/ImageBitmapLoader.js +23 -0
  60. package/src/loaders/Loader.js +14 -0
  61. package/src/loaders/LoadingManager.js +23 -0
  62. package/src/materials/MeshBasicMaterial.js +1 -1
  63. package/src/materials/nodes/Line2NodeMaterial.js +0 -8
  64. package/src/materials/nodes/NodeMaterial.js +1 -1
  65. package/src/materials/nodes/PointsNodeMaterial.js +5 -0
  66. package/src/materials/nodes/manager/NodeMaterialObserver.js +87 -2
  67. package/src/math/Frustum.js +19 -8
  68. package/src/math/FrustumArray.js +10 -5
  69. package/src/math/Line3.js +129 -2
  70. package/src/math/Matrix4.js +48 -27
  71. package/src/math/Spherical.js +2 -2
  72. package/src/nodes/Nodes.js +1 -0
  73. package/src/nodes/TSL.js +1 -0
  74. package/src/nodes/accessors/Camera.js +12 -12
  75. package/src/nodes/accessors/Normal.js +11 -11
  76. package/src/nodes/accessors/ReferenceNode.js +18 -3
  77. package/src/nodes/accessors/SceneNode.js +1 -1
  78. package/src/nodes/accessors/StorageTextureNode.js +1 -1
  79. package/src/nodes/accessors/TextureNode.js +12 -0
  80. package/src/nodes/core/ArrayNode.js +12 -0
  81. package/src/nodes/core/AssignNode.js +3 -0
  82. package/src/nodes/core/ContextNode.js +20 -1
  83. package/src/nodes/core/Node.js +14 -2
  84. package/src/nodes/core/NodeBuilder.js +25 -20
  85. package/src/nodes/core/NodeUtils.js +4 -1
  86. package/src/nodes/core/StackNode.js +42 -0
  87. package/src/nodes/core/UniformNode.js +63 -5
  88. package/src/nodes/core/VarNode.js +91 -2
  89. package/src/nodes/display/PassNode.js +148 -2
  90. package/src/nodes/display/ViewportTextureNode.js +67 -7
  91. package/src/nodes/functions/PhysicalLightingModel.js +2 -2
  92. package/src/nodes/gpgpu/AtomicFunctionNode.js +1 -1
  93. package/src/nodes/gpgpu/ComputeNode.js +67 -23
  94. package/src/nodes/gpgpu/WorkgroupInfoNode.js +28 -3
  95. package/src/nodes/lighting/ProjectorLightNode.js +19 -6
  96. package/src/nodes/lighting/ShadowFilterNode.js +1 -1
  97. package/src/nodes/materialx/MaterialXNodes.js +131 -2
  98. package/src/nodes/materialx/lib/mx_noise.js +165 -1
  99. package/src/nodes/math/ConditionalNode.js +1 -1
  100. package/src/nodes/math/MathNode.js +78 -54
  101. package/src/nodes/math/OperatorNode.js +22 -22
  102. package/src/nodes/tsl/TSLCore.js +64 -9
  103. package/src/nodes/utils/DebugNode.js +1 -1
  104. package/src/nodes/utils/EventNode.js +83 -0
  105. package/src/nodes/utils/RTTNode.js +9 -0
  106. package/src/objects/BatchedMesh.js +4 -2
  107. package/src/renderers/WebGLRenderer.js +21 -22
  108. package/src/renderers/common/Bindings.js +19 -18
  109. package/src/renderers/common/Color4.js +2 -2
  110. package/src/renderers/common/PostProcessing.js +60 -5
  111. package/src/renderers/common/Renderer.js +18 -15
  112. package/src/renderers/common/SampledTexture.js +3 -71
  113. package/src/renderers/common/Sampler.js +79 -0
  114. package/src/renderers/common/Storage3DTexture.js +21 -0
  115. package/src/renderers/common/StorageArrayTexture.js +21 -0
  116. package/src/renderers/common/StorageTexture.js +19 -0
  117. package/src/renderers/common/Textures.js +19 -3
  118. package/src/renderers/common/XRManager.js +26 -8
  119. package/src/renderers/common/nodes/NodeSampledTexture.js +0 -12
  120. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +20 -2
  121. package/src/renderers/shaders/ShaderLib/depth.glsl.js +11 -2
  122. package/src/renderers/webgl/WebGLCapabilities.js +2 -2
  123. package/src/renderers/webgl/WebGLMaterials.js +6 -6
  124. package/src/renderers/webgl/WebGLProgram.js +22 -16
  125. package/src/renderers/webgl/WebGLPrograms.js +4 -4
  126. package/src/renderers/webgl/WebGLShadowMap.js +11 -1
  127. package/src/renderers/webgl/WebGLTextures.js +19 -7
  128. package/src/renderers/webgl-fallback/WebGLBackend.js +22 -12
  129. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +2 -2
  130. package/src/renderers/webgpu/WebGPUBackend.js +54 -15
  131. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +53 -73
  132. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +35 -31
  133. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +1 -1
  134. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +11 -64
  135. package/src/renderers/webgpu/utils/WebGPUUtils.js +2 -17
  136. package/src/renderers/webxr/WebXRDepthSensing.js +6 -10
  137. package/src/renderers/webxr/WebXRManager.js +68 -8
  138. package/src/textures/ExternalTexture.js +45 -0
  139. package/src/textures/FramebufferTexture.js +2 -2
  140. package/src/textures/Source.js +11 -1
  141. package/src/textures/VideoTexture.js +30 -2
@@ -245,6 +245,36 @@ class StackNode extends Node {
245
245
 
246
246
  }
247
247
 
248
+ setup( builder ) {
249
+
250
+ const nodeProperties = builder.getNodeProperties( this );
251
+
252
+ let index = 0;
253
+
254
+ for ( const childNode of this.getChildren() ) {
255
+
256
+ if ( childNode.isVarNode && childNode.intent === true ) {
257
+
258
+ const properties = builder.getNodeProperties( childNode );
259
+
260
+ if ( properties.assign !== true ) {
261
+
262
+ continue;
263
+
264
+ }
265
+
266
+ }
267
+
268
+ nodeProperties[ 'node' + index ++ ] = childNode;
269
+
270
+ }
271
+
272
+ // return a outputNode if exists or null
273
+
274
+ return nodeProperties.outputNode || null;
275
+
276
+ }
277
+
248
278
  build( builder, ...params ) {
249
279
 
250
280
  const previousBuildStack = builder.currentStack;
@@ -258,6 +288,18 @@ class StackNode extends Node {
258
288
 
259
289
  for ( const node of this.nodes ) {
260
290
 
291
+ if ( node.isVarNode && node.intent === true ) {
292
+
293
+ const properties = builder.getNodeProperties( node );
294
+
295
+ if ( properties.assign !== true ) {
296
+
297
+ continue;
298
+
299
+ }
300
+
301
+ }
302
+
261
303
  if ( buildStage === 'setup' ) {
262
304
 
263
305
  node.build( builder );
@@ -59,7 +59,7 @@ class UniformNode extends InputNode {
59
59
  * @param {string} name - The name of the uniform.
60
60
  * @return {UniformNode} A reference to this node.
61
61
  */
62
- label( name ) {
62
+ setName( name ) {
63
63
 
64
64
  this.name = name;
65
65
 
@@ -67,6 +67,21 @@ class UniformNode extends InputNode {
67
67
 
68
68
  }
69
69
 
70
+ /**
71
+ * Sets the {@link UniformNode#name} property.
72
+ *
73
+ * @deprecated
74
+ * @param {string} name - The name of the uniform.
75
+ * @return {UniformNode} A reference to this node.
76
+ */
77
+ label( name ) {
78
+
79
+ console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179
80
+
81
+ return this.setName( name );
82
+
83
+ }
84
+
70
85
  /**
71
86
  * Sets the {@link UniformNode#groupNode} property.
72
87
  *
@@ -125,6 +140,20 @@ class UniformNode extends InputNode {
125
140
 
126
141
  }
127
142
 
143
+ getInputType( builder ) {
144
+
145
+ let type = super.getInputType( builder );
146
+
147
+ if ( type === 'bool' ) {
148
+
149
+ type = 'uint';
150
+
151
+ }
152
+
153
+ return type;
154
+
155
+ }
156
+
128
157
  generate( builder, output ) {
129
158
 
130
159
  const type = this.getNodeType( builder );
@@ -143,12 +172,41 @@ class UniformNode extends InputNode {
143
172
 
144
173
  const sharedNodeType = sharedNode.getInputType( builder );
145
174
 
146
- const nodeUniform = builder.getUniformFromNode( sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.label );
147
- const propertyName = builder.getPropertyName( nodeUniform );
175
+ const nodeUniform = builder.getUniformFromNode( sharedNode, sharedNodeType, builder.shaderStage, this.name || builder.context.nodeName );
176
+ const uniformName = builder.getPropertyName( nodeUniform );
177
+
178
+ if ( builder.context.nodeName !== undefined ) delete builder.context.nodeName;
179
+
180
+ //
181
+
182
+ let snippet = uniformName;
183
+
184
+ if ( type === 'bool' ) {
185
+
186
+ // cache to variable
187
+
188
+ const nodeData = builder.getDataFromNode( this );
189
+
190
+ let propertyName = nodeData.propertyName;
148
191
 
149
- if ( builder.context.label !== undefined ) delete builder.context.label;
192
+ if ( propertyName === undefined ) {
193
+
194
+ const nodeVar = builder.getVarFromNode( this, null, 'bool' );
195
+ propertyName = builder.getPropertyName( nodeVar );
196
+
197
+ nodeData.propertyName = propertyName;
198
+
199
+ snippet = builder.format( uniformName, sharedNodeType, type );
200
+
201
+ builder.addLineFlowCode( `${ propertyName } = ${ snippet }`, this );
202
+
203
+ }
204
+
205
+ snippet = propertyName;
206
+
207
+ }
150
208
 
151
- return builder.format( propertyName, type, output );
209
+ return builder.format( snippet, type, output );
152
210
 
153
211
  }
154
212
 
@@ -1,5 +1,5 @@
1
1
  import Node from './Node.js';
2
- import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';
2
+ import { addMethodChaining, getCurrentStack, nodeProxy } from '../tsl/TSLCore.js';
3
3
 
4
4
  /**
5
5
  * Class for representing shader variables as nodes. Variables are created from
@@ -81,6 +81,45 @@ class VarNode extends Node {
81
81
  */
82
82
  this.parents = true;
83
83
 
84
+ /**
85
+ * This flag is used to indicate that this node is used for intent.
86
+ *
87
+ * @type {boolean}
88
+ * @default false
89
+ */
90
+ this.intent = false;
91
+
92
+ }
93
+
94
+ /**
95
+ * Sets the intent flag for this node.
96
+ *
97
+ * This flag is used to indicate that this node is used for intent
98
+ * and should not be built directly. Instead, it is used to indicate that
99
+ * the node should be treated as a variable intent.
100
+ *
101
+ * It's useful for assigning variables without needing creating a new variable node.
102
+ *
103
+ * @param {boolean} value - The value to set for the intent flag.
104
+ * @returns {VarNode} This node.
105
+ */
106
+ setIntent( value ) {
107
+
108
+ this.intent = value;
109
+
110
+ return this;
111
+
112
+ }
113
+
114
+ /**
115
+ * Returns the intent flag of this node.
116
+ *
117
+ * @return {boolean} The intent flag.
118
+ */
119
+ getIntent() {
120
+
121
+ return this.intent;
122
+
84
123
  }
85
124
 
86
125
  getMemberType( builder, name ) {
@@ -101,6 +140,31 @@ class VarNode extends Node {
101
140
 
102
141
  }
103
142
 
143
+ getArrayCount( builder ) {
144
+
145
+ return this.node.getArrayCount( builder );
146
+
147
+ }
148
+
149
+ build( ...params ) {
150
+
151
+ if ( this.intent === true ) {
152
+
153
+ const builder = params[ 0 ];
154
+ const properties = builder.getNodeProperties( this );
155
+
156
+ if ( properties.assign !== true ) {
157
+
158
+ return this.node.build( ...params );
159
+
160
+ }
161
+
162
+ }
163
+
164
+ return super.build( ...params );
165
+
166
+ }
167
+
104
168
  generate( builder ) {
105
169
 
106
170
  const { node, name, readOnly } = this;
@@ -138,7 +202,7 @@ class VarNode extends Node {
138
202
 
139
203
  } else {
140
204
 
141
- const count = builder.getArrayCount( node );
205
+ const count = node.getArrayCount( builder );
142
206
 
143
207
  declarationPrefix = `const ${ builder.getVar( nodeVar.type, propertyName, count ) }`;
144
208
 
@@ -189,10 +253,35 @@ export const Var = ( node, name = null ) => createVar( node, name ).toStack();
189
253
  */
190
254
  export const Const = ( node, name = null ) => createVar( node, name, true ).toStack();
191
255
 
256
+ //
257
+ //
258
+
259
+ /**
260
+ * TSL function for creating a var intent node.
261
+ *
262
+ * @tsl
263
+ * @function
264
+ * @param {Node} node - The node for which a variable should be created.
265
+ * @param {?string} name - The name of the variable in the shader.
266
+ * @returns {VarNode}
267
+ */
268
+ export const VarIntent = ( node ) => {
269
+
270
+ if ( getCurrentStack() === null ) {
271
+
272
+ return node;
273
+
274
+ }
275
+
276
+ return createVar( node ).setIntent( true ).toStack();
277
+
278
+ };
279
+
192
280
  // Method chaining
193
281
 
194
282
  addMethodChaining( 'toVar', Var );
195
283
  addMethodChaining( 'toConst', Const );
284
+ addMethodChaining( 'toVarIntent', VarIntent );
196
285
 
197
286
  // Deprecated
198
287
 
@@ -7,6 +7,7 @@ import { viewZToOrthographicDepth, perspectiveDepthToViewZ } from './ViewportDep
7
7
 
8
8
  import { HalfFloatType/*, FloatType*/ } from '../../constants.js';
9
9
  import { Vector2 } from '../../math/Vector2.js';
10
+ import { Vector4 } from '../../math/Vector4.js';
10
11
  import { DepthTexture } from '../../textures/DepthTexture.js';
11
12
  import { RenderTarget } from '../../core/RenderTarget.js';
12
13
 
@@ -48,7 +49,7 @@ class PassTextureNode extends TextureNode {
48
49
 
49
50
  setup( builder ) {
50
51
 
51
- if ( builder.object.isQuadMesh ) this.passNode.build( builder );
52
+ this.passNode.build( builder );
52
53
 
53
54
  return super.setup( builder );
54
55
 
@@ -323,10 +324,43 @@ class PassNode extends TempNode {
323
324
  */
324
325
  this._mrt = null;
325
326
 
327
+ /**
328
+ * Layer object for configuring the camera that is used
329
+ * to produce the pass.
330
+ *
331
+ * @private
332
+ * @type {?Layers}
333
+ * @default null
334
+ */
326
335
  this._layers = null;
327
336
 
337
+ /**
338
+ * Scales the resolution of the internal render target.
339
+ *
340
+ * @private
341
+ * @type {number}
342
+ * @default 1
343
+ */
328
344
  this._resolution = 1;
329
345
 
346
+ /**
347
+ * Custom viewport definition.
348
+ *
349
+ * @private
350
+ * @type {?Vector4}
351
+ * @default null
352
+ */
353
+ this._viewport = null;
354
+
355
+ /**
356
+ * Custom scissor definition.
357
+ *
358
+ * @private
359
+ * @type {?Vector4}
360
+ * @default null
361
+ */
362
+ this._scissor = null;
363
+
330
364
  /**
331
365
  * This flag can be used for type testing.
332
366
  *
@@ -374,7 +408,6 @@ class PassNode extends TempNode {
374
408
  * Gets the current resolution of the pass.
375
409
  *
376
410
  * @return {number} The current resolution. A value of `1` means full resolution.
377
- * @default 1
378
411
  */
379
412
  getResolution() {
380
413
 
@@ -382,6 +415,12 @@ class PassNode extends TempNode {
382
415
 
383
416
  }
384
417
 
418
+ /**
419
+ * Sets the layer configuration that should be used when rendering the pass.
420
+ *
421
+ * @param {Layers} layers - The layers object to set.
422
+ * @return {PassNode} A reference to this pass.
423
+ */
385
424
  setLayers( layers ) {
386
425
 
387
426
  this._layers = layers;
@@ -390,6 +429,11 @@ class PassNode extends TempNode {
390
429
 
391
430
  }
392
431
 
432
+ /**
433
+ * Gets the current layer configuration of the pass.
434
+ *
435
+ * @return {?Layers} .
436
+ */
393
437
  getLayers() {
394
438
 
395
439
  return this._layers;
@@ -591,6 +635,32 @@ class PassNode extends TempNode {
591
635
 
592
636
  }
593
637
 
638
+ /**
639
+ * Precompiles the pass.
640
+ *
641
+ * Note that this method must be called after the pass configuartion is complete.
642
+ * So calls like `setMRT()` and `getTextureNode()` must proceed the precompilation.
643
+ *
644
+ * @async
645
+ * @param {Renderer} renderer - The renderer.
646
+ * @return {Promise} A Promise that resolves when the compile has been finished.
647
+ * @see {@link Renderer#compileAsync}
648
+ */
649
+ async compileAsync( renderer ) {
650
+
651
+ const currentRenderTarget = renderer.getRenderTarget();
652
+ const currentMRT = renderer.getMRT();
653
+
654
+ renderer.setRenderTarget( this.renderTarget );
655
+ renderer.setMRT( this._mrt );
656
+
657
+ await renderer.compileAsync( this.scene, this.camera );
658
+
659
+ renderer.setRenderTarget( currentRenderTarget );
660
+ renderer.setMRT( currentMRT );
661
+
662
+ }
663
+
594
664
  setup( { renderer } ) {
595
665
 
596
666
  this.renderTarget.samples = this.options.samples === undefined ? renderer.samples : this.options.samples;
@@ -680,6 +750,82 @@ class PassNode extends TempNode {
680
750
 
681
751
  this.renderTarget.setSize( effectiveWidth, effectiveHeight );
682
752
 
753
+ if ( this._scissor !== null ) this.renderTarget.scissor.copy( this._scissor );
754
+ if ( this._viewport !== null ) this.renderTarget.viewport.copy( this._viewport );
755
+
756
+ }
757
+
758
+ /**
759
+ * This method allows to define the pass's scissor rectangle. By default, the scissor rectangle is kept
760
+ * in sync with the pass's dimensions. To reverse the process and use auto-sizing again, call the method
761
+ * with `null` as the single argument.
762
+ *
763
+ * @param {?(number | Vector4)} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit.
764
+ * Instead of passing four arguments, the method also works with a single four-dimensional vector.
765
+ * @param {number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit.
766
+ * @param {number} width - The width of the scissor box in logical pixel unit.
767
+ * @param {number} height - The height of the scissor box in logical pixel unit.
768
+ */
769
+ setScissor( x, y, width, height ) {
770
+
771
+ if ( x === null ) {
772
+
773
+ this._scissor = null;
774
+
775
+ } else {
776
+
777
+ if ( this._scissor === null ) this._scissor = new Vector4();
778
+
779
+ if ( x.isVector4 ) {
780
+
781
+ this._scissor.copy( x );
782
+
783
+ } else {
784
+
785
+ this._scissor.set( x, y, width, height );
786
+
787
+ }
788
+
789
+ this._scissor.multiplyScalar( this._pixelRatio * this._resolution ).floor();
790
+
791
+ }
792
+
793
+ }
794
+
795
+ /**
796
+ * This method allows to define the pass's viewport. By default, the viewport is kept in sync
797
+ * with the pass's dimensions. To reverse the process and use auto-sizing again, call the method
798
+ * with `null` as the single argument.
799
+ *
800
+ * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit.
801
+ * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit.
802
+ * @param {number} width - The width of the viewport in logical pixel unit.
803
+ * @param {number} height - The height of the viewport in logical pixel unit.
804
+ */
805
+ setViewport( x, y, width, height ) {
806
+
807
+ if ( x === null ) {
808
+
809
+ this._viewport = null;
810
+
811
+ } else {
812
+
813
+ if ( this._viewport === null ) this._viewport = new Vector4();
814
+
815
+ if ( x.isVector4 ) {
816
+
817
+ this._viewport.copy( x );
818
+
819
+ } else {
820
+
821
+ this._viewport.set( x, y, width, height );
822
+
823
+ }
824
+
825
+ this._viewport.multiplyScalar( this._pixelRatio * this._resolution ).floor();
826
+
827
+ }
828
+
683
829
  }
684
830
 
685
831
  /**
@@ -35,10 +35,18 @@ class ViewportTextureNode extends TextureNode {
35
35
  */
36
36
  constructor( uvNode = screenUV, levelNode = null, framebufferTexture = null ) {
37
37
 
38
+ let defaultFramebuffer = null;
39
+
38
40
  if ( framebufferTexture === null ) {
39
41
 
40
- framebufferTexture = new FramebufferTexture();
41
- framebufferTexture.minFilter = LinearMipmapLinearFilter;
42
+ defaultFramebuffer = new FramebufferTexture();
43
+ defaultFramebuffer.minFilter = LinearMipmapLinearFilter;
44
+
45
+ framebufferTexture = defaultFramebuffer;
46
+
47
+ } else {
48
+
49
+ defaultFramebuffer = framebufferTexture;
42
50
 
43
51
  }
44
52
 
@@ -52,6 +60,16 @@ class ViewportTextureNode extends TextureNode {
52
60
  */
53
61
  this.generateMipmaps = false;
54
62
 
63
+ /**
64
+ * The reference framebuffer texture. This is used to store the framebuffer texture
65
+ * for the current render target. If the render target changes, a new framebuffer texture
66
+ * is created automatically.
67
+ *
68
+ * @type {FramebufferTexture}
69
+ * @default null
70
+ */
71
+ this.defaultFramebuffer = defaultFramebuffer;
72
+
55
73
  /**
56
74
  * This flag can be used for type testing.
57
75
  *
@@ -62,24 +80,64 @@ class ViewportTextureNode extends TextureNode {
62
80
  this.isOutputTextureNode = true;
63
81
 
64
82
  /**
65
- * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders the
66
- * scene once per frame in its {@link ViewportTextureNode#updateBefore} method.
83
+ * The `updateBeforeType` is set to `NodeUpdateType.RENDER` since the node renders the
84
+ * scene once per render in its {@link ViewportTextureNode#updateBefore} method.
67
85
  *
68
86
  * @type {string}
69
87
  * @default 'frame'
70
88
  */
71
- this.updateBeforeType = NodeUpdateType.FRAME;
89
+ this.updateBeforeType = NodeUpdateType.RENDER;
90
+
91
+ /**
92
+ * The framebuffer texture for the current renderer context.
93
+ *
94
+ * @type {WeakMap<RenderTarget, FramebufferTexture>}
95
+ * @private
96
+ */
97
+ this._textures = new WeakMap();
98
+
99
+ }
100
+
101
+ getFrameBufferTexture( reference = null ) {
102
+
103
+ const defaultFramebuffer = this.referenceNode ? this.referenceNode.defaultFramebuffer : this.defaultFramebuffer;
104
+
105
+ if ( reference === null ) {
106
+
107
+ return defaultFramebuffer;
108
+
109
+ }
110
+
111
+ if ( this._textures.has( reference ) === false ) {
112
+
113
+ const framebufferTexture = defaultFramebuffer.clone();
114
+
115
+ this._textures.set( reference, framebufferTexture );
116
+
117
+ }
118
+
119
+ return this._textures.get( reference );
72
120
 
73
121
  }
74
122
 
75
123
  updateBefore( frame ) {
76
124
 
77
125
  const renderer = frame.renderer;
78
- renderer.getDrawingBufferSize( _size );
126
+ const renderTarget = renderer.getRenderTarget();
127
+
128
+ if ( renderTarget === null ) {
129
+
130
+ renderer.getDrawingBufferSize( _size );
131
+
132
+ } else {
133
+
134
+ _size.set( renderTarget.width, renderTarget.height );
135
+
136
+ }
79
137
 
80
138
  //
81
139
 
82
- const framebufferTexture = this.value;
140
+ const framebufferTexture = this.getFrameBufferTexture( renderTarget );
83
141
 
84
142
  if ( framebufferTexture.image.width !== _size.width || framebufferTexture.image.height !== _size.height ) {
85
143
 
@@ -98,6 +156,8 @@ class ViewportTextureNode extends TextureNode {
98
156
 
99
157
  framebufferTexture.generateMipmaps = currentGenerateMipmaps;
100
158
 
159
+ this.value = framebufferTexture;
160
+
101
161
  }
102
162
 
103
163
  clone() {
@@ -575,7 +575,7 @@ class PhysicalLightingModel extends LightingModel {
575
575
  * @param {Object} lightData - The light data.
576
576
  * @param {NodeBuilder} builder - The current node builder.
577
577
  */
578
- direct( { lightDirection, lightColor, reflectedLight } ) {
578
+ direct( { lightDirection, lightColor, reflectedLight }, /* builder */ ) {
579
579
 
580
580
  const dotNL = normalView.dot( lightDirection ).clamp();
581
581
  const irradiance = dotNL.mul( lightColor );
@@ -608,7 +608,7 @@ class PhysicalLightingModel extends LightingModel {
608
608
  * @param {Object} input - The input data.
609
609
  * @param {NodeBuilder} builder - The current node builder.
610
610
  */
611
- directRectArea( { lightColor, lightPosition, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 } ) {
611
+ directRectArea( { lightColor, lightPosition, halfWidth, halfHeight, reflectedLight, ltc_1, ltc_2 }, /* builder */ ) {
612
612
 
613
613
  const p0 = lightPosition.add( halfWidth ).sub( halfHeight ); // counterclockwise; light shines in local neg z direction
614
614
  const p1 = lightPosition.sub( halfWidth ).sub( halfHeight );
@@ -113,7 +113,7 @@ class AtomicFunctionNode extends Node {
113
113
  }
114
114
 
115
115
  const methodSnippet = `${ builder.getMethod( method, type ) }( ${ params.join( ', ' ) } )`;
116
- const isVoid = parents.length === 1 && parents[ 0 ].isStackNode === true;
116
+ const isVoid = parents ? ( parents.length === 1 && parents[ 0 ].isStackNode === true ) : false;
117
117
 
118
118
  if ( isVoid ) {
119
119