@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
@@ -16,7 +16,7 @@ import { NodeAccess } from '../../../nodes/core/constants.js';
16
16
  import VarNode from '../../../nodes/core/VarNode.js';
17
17
  import ExpressionNode from '../../../nodes/code/ExpressionNode.js';
18
18
 
19
- import { NoColorSpace, FloatType, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter } from '../../../constants.js';
19
+ import { FloatType, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter } from '../../../constants.js';
20
20
 
21
21
  // GPUShaderStage is not defined in browsers not supporting WebGPU
22
22
  const GPUShaderStage = ( typeof self !== 'undefined' ) ? self.GPUShaderStage : { VERTEX: 1, FRAGMENT: 2, COMPUTE: 4 };
@@ -211,18 +211,6 @@ class WGSLNodeBuilder extends NodeBuilder {
211
211
 
212
212
  }
213
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
- */
220
- needsToWorkingColorSpace( texture ) {
221
-
222
- return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace;
223
-
224
- }
225
-
226
214
  /**
227
215
  * Generates the WGSL snippet for sampled textures.
228
216
  *
@@ -250,30 +238,7 @@ class WGSLNodeBuilder extends NodeBuilder {
250
238
 
251
239
  } else {
252
240
 
253
- return this._generateTextureSampleLevel( texture, textureProperty, uvSnippet, '0', depthSnippet );
254
-
255
- }
256
-
257
- }
258
-
259
- /**
260
- * Generates the WGSL snippet when sampling video textures.
261
- *
262
- * @private
263
- * @param {string} textureProperty - The name of the video texture uniform in the shader.
264
- * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling.
265
- * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
266
- * @return {string} The WGSL snippet.
267
- */
268
- _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
269
-
270
- if ( shaderStage === 'fragment' ) {
271
-
272
- return `textureSampleBaseClampToEdge( ${ textureProperty }, ${ textureProperty }_sampler, vec2<f32>( ${ uvSnippet }.x, 1.0 - ${ uvSnippet }.y ) )`;
273
-
274
- } else {
275
-
276
- console.error( `WebGPURenderer: THREE.VideoTexture does not support ${ shaderStage } shader.` );
241
+ return this.generateTextureSampleLevel( texture, textureProperty, uvSnippet, '0', depthSnippet );
277
242
 
278
243
  }
279
244
 
@@ -290,7 +255,7 @@ class WGSLNodeBuilder extends NodeBuilder {
290
255
  * @param {string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
291
256
  * @return {string} The WGSL snippet.
292
257
  */
293
- _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ) {
258
+ generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ) {
294
259
 
295
260
  if ( this.isUnfilterable( texture ) === false ) {
296
261
 
@@ -434,7 +399,7 @@ class WGSLNodeBuilder extends NodeBuilder {
434
399
  }
435
400
 
436
401
  // Build parameters string based on texture type and multisampling
437
- if ( isMultisampled || texture.isVideoTexture || texture.isStorageTexture ) {
402
+ if ( isMultisampled || texture.isStorageTexture ) {
438
403
 
439
404
  textureDimensionsParams = textureProperty;
440
405
 
@@ -531,11 +496,7 @@ class WGSLNodeBuilder extends NodeBuilder {
531
496
 
532
497
  let snippet;
533
498
 
534
- if ( texture.isVideoTexture === true ) {
535
-
536
- snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet } )`;
537
-
538
- } else if ( depthSnippet ) {
499
+ if ( depthSnippet ) {
539
500
 
540
501
  snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet }, u32( ${ levelSnippet } ) )`;
541
502
 
@@ -624,11 +585,7 @@ class WGSLNodeBuilder extends NodeBuilder {
624
585
 
625
586
  let snippet = null;
626
587
 
627
- if ( texture.isVideoTexture === true ) {
628
-
629
- snippet = this._generateVideoSample( textureProperty, uvSnippet, shaderStage );
630
-
631
- } else if ( this.isUnfilterable( texture ) ) {
588
+ if ( this.isUnfilterable( texture ) ) {
632
589
 
633
590
  snippet = this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, '0', shaderStage );
634
591
 
@@ -711,22 +668,22 @@ class WGSLNodeBuilder extends NodeBuilder {
711
668
  * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
712
669
  * @return {string} The WGSL snippet.
713
670
  */
714
- generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) {
671
+ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ) {
715
672
 
716
- let snippet = null;
673
+ if ( this.isUnfilterable( texture ) === false ) {
717
674
 
718
- if ( texture.isVideoTexture === true ) {
675
+ return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet } )`;
719
676
 
720
- snippet = this._generateVideoSample( textureProperty, uvSnippet, shaderStage );
677
+ } else if ( this.isFilteredTexture( texture ) ) {
678
+
679
+ return this.generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet );
721
680
 
722
681
  } else {
723
682
 
724
- snippet = this._generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet );
683
+ return this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet );
725
684
 
726
685
  }
727
686
 
728
- return snippet;
729
-
730
687
  }
731
688
 
732
689
  /**
@@ -844,9 +801,20 @@ class WGSLNodeBuilder extends NodeBuilder {
844
801
  */
845
802
  getNodeAccess( node, shaderStage ) {
846
803
 
847
- if ( shaderStage !== 'compute' )
804
+ if ( shaderStage !== 'compute' ) {
805
+
806
+ if ( node.isAtomic === true ) {
807
+
808
+ console.warn( 'WebGPURenderer: Atomic operations are only supported in compute shaders.' );
809
+
810
+ return NodeAccess.READ_WRITE;
811
+
812
+ }
813
+
848
814
  return NodeAccess.READ_ONLY;
849
815
 
816
+ }
817
+
850
818
  return node.access;
851
819
 
852
820
  }
@@ -899,7 +867,15 @@ class WGSLNodeBuilder extends NodeBuilder {
899
867
 
900
868
  if ( type === 'texture' || type === 'storageTexture' ) {
901
869
 
902
- texture = new NodeSampledTexture( uniformNode.name, uniformNode.node, group, access );
870
+ if ( node.value.is3DTexture === true ) {
871
+
872
+ texture = new NodeSampledTexture3D( uniformNode.name, uniformNode.node, group, access );
873
+
874
+ } else {
875
+
876
+ texture = new NodeSampledTexture( uniformNode.name, uniformNode.node, group, access );
877
+
878
+ }
903
879
 
904
880
  } else if ( type === 'cubeTexture' ) {
905
881
 
@@ -1721,10 +1697,6 @@ ${ flowData.code }
1721
1697
 
1722
1698
  textureType = 'texture_3d<f32>';
1723
1699
 
1724
- } else if ( texture.isVideoTexture === true ) {
1725
-
1726
- textureType = 'texture_external';
1727
-
1728
1700
  } else {
1729
1701
 
1730
1702
  const componentPrefix = this.getComponentTypeFromTexture( texture ).charAt( 0 );
@@ -1890,7 +1862,11 @@ ${ flowData.code }
1890
1862
 
1891
1863
  } else {
1892
1864
 
1893
- this.computeShader = this._getWGSLComputeCode( shadersData.compute, ( this.object.workgroupSize || [ 64 ] ).join( ', ' ) );
1865
+ // Early strictly validated in computeNode
1866
+
1867
+ const workgroupSize = this.object.workgroupSize;
1868
+
1869
+ this.computeShader = this._getWGSLComputeCode( shadersData.compute, workgroupSize );
1894
1870
 
1895
1871
  }
1896
1872
 
@@ -2095,36 +2071,40 @@ fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} {
2095
2071
  */
2096
2072
  _getWGSLComputeCode( shaderData, workgroupSize ) {
2097
2073
 
2074
+ const [ workgroupSizeX, workgroupSizeY, workgroupSizeZ ] = workgroupSize;
2075
+
2098
2076
  return `${ this.getSignature() }
2099
2077
  // directives
2100
- ${shaderData.directives}
2078
+ ${ shaderData.directives }
2101
2079
 
2102
2080
  // system
2103
2081
  var<private> instanceIndex : u32;
2104
2082
 
2105
2083
  // locals
2106
- ${shaderData.scopedArrays}
2084
+ ${ shaderData.scopedArrays }
2107
2085
 
2108
2086
  // structs
2109
- ${shaderData.structs}
2087
+ ${ shaderData.structs }
2110
2088
 
2111
2089
  // uniforms
2112
- ${shaderData.uniforms}
2090
+ ${ shaderData.uniforms }
2113
2091
 
2114
2092
  // codes
2115
- ${shaderData.codes}
2093
+ ${ shaderData.codes }
2116
2094
 
2117
- @compute @workgroup_size( ${workgroupSize} )
2118
- fn main( ${shaderData.attributes} ) {
2095
+ @compute @workgroup_size( ${ workgroupSizeX }, ${ workgroupSizeY }, ${ workgroupSizeZ } )
2096
+ fn main( ${ shaderData.attributes } ) {
2119
2097
 
2120
2098
  // system
2121
- instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize});
2099
+ instanceIndex = globalId.x
2100
+ + globalId.y * ( ${ workgroupSizeX } * numWorkgroups.x )
2101
+ + globalId.z * ( ${ workgroupSizeX } * numWorkgroups.x ) * ( ${ workgroupSizeY } * numWorkgroups.y );
2122
2102
 
2123
2103
  // vars
2124
- ${shaderData.vars}
2104
+ ${ shaderData.vars }
2125
2105
 
2126
2106
  // flow
2127
- ${shaderData.flow}
2107
+ ${ shaderData.flow }
2128
2108
 
2129
2109
  }
2130
2110
  `;
@@ -93,30 +93,6 @@ class WebGPUBindingUtils {
93
93
 
94
94
  bindingGPU.buffer = buffer;
95
95
 
96
- } else if ( binding.isSampler ) {
97
-
98
- const sampler = {}; // GPUSamplerBindingLayout
99
-
100
- if ( binding.texture.isDepthTexture ) {
101
-
102
- if ( binding.texture.compareFunction !== null ) {
103
-
104
- sampler.type = GPUSamplerBindingType.Comparison;
105
-
106
- } else if ( backend.compatibilityMode ) {
107
-
108
- sampler.type = GPUSamplerBindingType.NonFiltering;
109
-
110
- }
111
-
112
- }
113
-
114
- bindingGPU.sampler = sampler;
115
-
116
- } else if ( binding.isSampledTexture && binding.texture.isVideoTexture ) {
117
-
118
- bindingGPU.externalTexture = {}; // GPUExternalTextureBindingLayout
119
-
120
96
  } else if ( binding.isSampledTexture && binding.store ) {
121
97
 
122
98
  const storageTexture = {}; // GPUStorageTextureBindingLayout
@@ -224,6 +200,26 @@ class WebGPUBindingUtils {
224
200
 
225
201
  bindingGPU.texture = texture;
226
202
 
203
+ } else if ( binding.isSampler ) {
204
+
205
+ const sampler = {}; // GPUSamplerBindingLayout
206
+
207
+ if ( binding.texture.isDepthTexture ) {
208
+
209
+ if ( binding.texture.compareFunction !== null ) {
210
+
211
+ sampler.type = GPUSamplerBindingType.Comparison;
212
+
213
+ } else if ( backend.compatibilityMode ) {
214
+
215
+ sampler.type = GPUSamplerBindingType.NonFiltering;
216
+
217
+ }
218
+
219
+ }
220
+
221
+ bindingGPU.sampler = sampler;
222
+
227
223
  } else {
228
224
 
229
225
  console.error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` );
@@ -405,12 +401,6 @@ class WebGPUBindingUtils {
405
401
 
406
402
  entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
407
403
 
408
- } else if ( binding.isSampler ) {
409
-
410
- const textureGPU = backend.get( binding.texture );
411
-
412
- entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } );
413
-
414
404
  } else if ( binding.isSampledTexture ) {
415
405
 
416
406
  const textureData = backend.get( binding.texture );
@@ -424,7 +414,15 @@ class WebGPUBindingUtils {
424
414
  } else {
425
415
 
426
416
  const mipLevelCount = binding.store ? 1 : textureData.texture.mipLevelCount;
427
- const propertyName = `view-${ textureData.texture.width }-${ textureData.texture.height }-${ mipLevelCount }`;
417
+ let propertyName = `view-${ textureData.texture.width }-${ textureData.texture.height }`;
418
+
419
+ if ( textureData.texture.depthOrArrayLayers > 1 ) {
420
+
421
+ propertyName += `-${ textureData.texture.depthOrArrayLayers }`;
422
+
423
+ }
424
+
425
+ propertyName += `-${ mipLevelCount }`;
428
426
 
429
427
  resourceGPU = textureData[ propertyName ];
430
428
 
@@ -460,6 +458,12 @@ class WebGPUBindingUtils {
460
458
 
461
459
  entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } );
462
460
 
461
+ } else if ( binding.isSampler ) {
462
+
463
+ const textureGPU = backend.get( binding.texture );
464
+
465
+ entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } );
466
+
463
467
  }
464
468
 
465
469
  bindingPoint ++;
@@ -712,7 +712,7 @@ class WebGPUPipelineUtils {
712
712
  *
713
713
  * @private
714
714
  * @param {Material} material - The material.
715
- * @return {string} The GPU color write mask.
715
+ * @return {number} The GPU color write mask.
716
716
  */
717
717
  _getColorWriteMask( material ) {
718
718
 
@@ -159,10 +159,6 @@ class WebGPUTextureUtils {
159
159
 
160
160
  textureGPU = this._getDefaultCubeTextureGPU( format );
161
161
 
162
- } else if ( texture.isVideoTexture ) {
163
-
164
- this.backend.get( texture ).externalTexture = this._getDefaultVideoFrame();
165
-
166
162
  } else {
167
163
 
168
164
  textureGPU = this._getDefaultTextureGPU( format );
@@ -247,39 +243,23 @@ class WebGPUTextureUtils {
247
243
 
248
244
  // texture creation
249
245
 
250
- if ( texture.isVideoTexture ) {
251
-
252
- const video = texture.source.data;
253
- const videoFrame = new VideoFrame( video );
254
-
255
- textureDescriptorGPU.size.width = videoFrame.displayWidth;
256
- textureDescriptorGPU.size.height = videoFrame.displayHeight;
257
-
258
- videoFrame.close();
259
-
260
- textureData.externalTexture = video;
261
-
262
- } else {
263
-
264
- if ( format === undefined ) {
246
+ if ( format === undefined ) {
265
247
 
266
- console.warn( 'WebGPURenderer: Texture format not supported.' );
248
+ console.warn( 'WebGPURenderer: Texture format not supported.' );
267
249
 
268
- this.createDefaultTexture( texture );
269
- return;
270
-
271
- }
272
-
273
- if ( texture.isCubeTexture ) {
250
+ this.createDefaultTexture( texture );
251
+ return;
274
252
 
275
- textureDescriptorGPU.textureBindingViewDimension = GPUTextureViewDimension.Cube;
253
+ }
276
254
 
277
- }
255
+ if ( texture.isCubeTexture ) {
278
256
 
279
- textureData.texture = backend.device.createTexture( textureDescriptorGPU );
257
+ textureDescriptorGPU.textureBindingViewDimension = GPUTextureViewDimension.Cube;
280
258
 
281
259
  }
282
260
 
261
+ textureData.texture = backend.device.createTexture( textureDescriptorGPU );
262
+
283
263
  if ( isMSAA ) {
284
264
 
285
265
  const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU );
@@ -480,12 +460,6 @@ class WebGPUTextureUtils {
480
460
 
481
461
  this._copyCubeMapToTexture( options.images, textureData.texture, textureDescriptorGPU, texture.flipY, texture.premultiplyAlpha );
482
462
 
483
- } else if ( texture.isVideoTexture ) {
484
-
485
- const video = texture.source.data;
486
-
487
- textureData.externalTexture = video;
488
-
489
463
  } else {
490
464
 
491
465
  this._copyImageToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY, texture.premultiplyAlpha );
@@ -615,33 +589,6 @@ class WebGPUTextureUtils {
615
589
 
616
590
  }
617
591
 
618
- /**
619
- * Returns the default video frame used as default data in context of video textures.
620
- *
621
- * @private
622
- * @return {VideoFrame} The video frame.
623
- */
624
- _getDefaultVideoFrame() {
625
-
626
- let defaultVideoFrame = this.defaultVideoFrame;
627
-
628
- if ( defaultVideoFrame === null ) {
629
-
630
- const init = {
631
- timestamp: 0,
632
- codedWidth: 1,
633
- codedHeight: 1,
634
- format: 'RGBA',
635
- };
636
-
637
- this.defaultVideoFrame = defaultVideoFrame = new VideoFrame( new Uint8Array( [ 0, 0, 0, 0xff ] ), init );
638
-
639
- }
640
-
641
- return defaultVideoFrame;
642
-
643
- }
644
-
645
592
  /**
646
593
  * Uploads cube texture image data to the GPU memory.
647
594
  *
@@ -699,8 +646,8 @@ class WebGPUTextureUtils {
699
646
  origin: { x: 0, y: 0, z: originDepth },
700
647
  premultipliedAlpha: premultiplyAlpha
701
648
  }, {
702
- width: image.width,
703
- height: image.height,
649
+ width: textureDescriptorGPU.size.width,
650
+ height: textureDescriptorGPU.size.height,
704
651
  depthOrArrayLayers: 1
705
652
  }
706
653
  );
@@ -161,29 +161,14 @@ class WebGPUUtils {
161
161
  /**
162
162
  * Returns a modified sample count from the given sample count value.
163
163
  *
164
- * That is required since WebGPU does not support arbitrary sample counts.
164
+ * That is required since WebGPU only supports either 1 or 4.
165
165
  *
166
166
  * @param {number} sampleCount - The input sample count.
167
167
  * @return {number} The (potentially updated) output sample count.
168
168
  */
169
169
  getSampleCount( sampleCount ) {
170
170
 
171
- let count = 1;
172
-
173
- if ( sampleCount > 1 ) {
174
-
175
- // WebGPU only supports power-of-two sample counts and 2 is not a valid value
176
- count = Math.pow( 2, Math.floor( Math.log2( sampleCount ) ) );
177
-
178
- if ( count === 2 ) {
179
-
180
- count = 4;
181
-
182
- }
183
-
184
- }
185
-
186
- return count;
171
+ return sampleCount >= 4 ? 4 : 1;
187
172
 
188
173
  }
189
174
 
@@ -1,7 +1,7 @@
1
1
  import { PlaneGeometry } from '../../geometries/PlaneGeometry.js';
2
2
  import { ShaderMaterial } from '../../materials/ShaderMaterial.js';
3
3
  import { Mesh } from '../../objects/Mesh.js';
4
- import { Texture } from '../../textures/Texture.js';
4
+ import { ExternalTexture } from '../../textures/ExternalTexture.js';
5
5
 
6
6
  const _occlusion_vertex = `
7
7
  void main() {
@@ -42,9 +42,9 @@ class WebXRDepthSensing {
42
42
  constructor() {
43
43
 
44
44
  /**
45
- * A texture representing the depth of the user's environment.
45
+ * An opaque texture representing the depth of the user's environment.
46
46
  *
47
- * @type {?Texture}
47
+ * @type {?ExternalTexture}
48
48
  */
49
49
  this.texture = null;
50
50
 
@@ -74,18 +74,14 @@ class WebXRDepthSensing {
74
74
  /**
75
75
  * Inits the depth sensing module
76
76
  *
77
- * @param {WebGLRenderer} renderer - The renderer.
78
77
  * @param {XRWebGLDepthInformation} depthData - The XR depth data.
79
78
  * @param {XRRenderState} renderState - The XR render state.
80
79
  */
81
- init( renderer, depthData, renderState ) {
80
+ init( depthData, renderState ) {
82
81
 
83
82
  if ( this.texture === null ) {
84
83
 
85
- const texture = new Texture();
86
-
87
- const texProps = renderer.properties.get( texture );
88
- texProps.__webglTexture = depthData.texture;
84
+ const texture = new ExternalTexture( depthData.texture );
89
85
 
90
86
  if ( ( depthData.depthNear !== renderState.depthNear ) || ( depthData.depthFar !== renderState.depthFar ) ) {
91
87
 
@@ -146,7 +142,7 @@ class WebXRDepthSensing {
146
142
  /**
147
143
  * Returns a texture representing the depth of the user's environment.
148
144
  *
149
- * @return {?Texture} The depth texture.
145
+ * @return {?ExternalTexture} The depth texture.
150
146
  */
151
147
  getDepthTexture() {
152
148
 
@@ -9,6 +9,7 @@ import { WebGLAnimation } from '../webgl/WebGLAnimation.js';
9
9
  import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
10
10
  import { WebXRController } from './WebXRController.js';
11
11
  import { DepthTexture } from '../../textures/DepthTexture.js';
12
+ import { ExternalTexture } from '../../textures/ExternalTexture.js';
12
13
  import { DepthFormat, DepthStencilFormat, RGBAFormat, UnsignedByteType, UnsignedIntType, UnsignedInt248Type } from '../../constants.js';
13
14
  import { WebXRDepthSensing } from './WebXRDepthSensing.js';
14
15
 
@@ -52,6 +53,7 @@ class WebXRManager extends EventDispatcher {
52
53
  let xrFrame = null;
53
54
 
54
55
  const depthSensing = new WebXRDepthSensing();
56
+ const cameraAccessTextures = {};
55
57
  const attributes = gl.getContextAttributes();
56
58
 
57
59
  let initialRenderTarget = null;
@@ -232,6 +234,11 @@ class WebXRManager extends EventDispatcher {
232
234
  _currentDepthFar = null;
233
235
 
234
236
  depthSensing.reset();
237
+ for ( const key in cameraAccessTextures ) {
238
+
239
+ delete cameraAccessTextures[ key ];
240
+
241
+ }
235
242
 
236
243
  // restore framebuffer/rendering state
237
244
 
@@ -398,9 +405,15 @@ class WebXRManager extends EventDispatcher {
398
405
  currentPixelRatio = renderer.getPixelRatio();
399
406
  renderer.getSize( currentSize );
400
407
 
408
+ if ( typeof XRWebGLBinding !== 'undefined' ) {
409
+
410
+ glBinding = new XRWebGLBinding( session, gl );
411
+
412
+ }
413
+
401
414
  // Check that the browser implements the necessary APIs to use an
402
415
  // XRProjectionLayer rather than an XRWebGLLayer
403
- const useLayers = typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype;
416
+ const useLayers = glBinding !== null && 'createProjectionLayer' in XRWebGLBinding.prototype;
404
417
 
405
418
  if ( ! useLayers ) {
406
419
 
@@ -453,8 +466,6 @@ class WebXRManager extends EventDispatcher {
453
466
  scaleFactor: framebufferScaleFactor
454
467
  };
455
468
 
456
- glBinding = new XRWebGLBinding( session, gl );
457
-
458
469
  glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
459
470
 
460
471
  session.updateRenderState( { layers: [ glProjLayer ] } );
@@ -722,9 +733,10 @@ class WebXRManager extends EventDispatcher {
722
733
 
723
734
  }
724
735
 
725
- cameraL.layers.mask = camera.layers.mask | 0b010;
726
- cameraR.layers.mask = camera.layers.mask | 0b100;
727
- cameraXR.layers.mask = cameraL.layers.mask | cameraR.layers.mask;
736
+ // inherit camera layers and enable eye layers (1 = left, 2 = right)
737
+ cameraXR.layers.mask = camera.layers.mask | 0b110;
738
+ cameraL.layers.mask = cameraXR.layers.mask & 0b011;
739
+ cameraR.layers.mask = cameraXR.layers.mask & 0b101;
728
740
 
729
741
  const parent = camera.parent;
730
742
  const cameras = cameraXR.cameras;
@@ -805,7 +817,7 @@ class WebXRManager extends EventDispatcher {
805
817
  /**
806
818
  * Returns the amount of foveation used by the XR compositor for the projection layer.
807
819
  *
808
- * @return {number} The amount of foveation.
820
+ * @return {number|undefined} The amount of foveation.
809
821
  */
810
822
  this.getFoveation = function () {
811
823
 
@@ -868,6 +880,19 @@ class WebXRManager extends EventDispatcher {
868
880
 
869
881
  };
870
882
 
883
+ /**
884
+ * Retrieves an opaque texture from the view-aligned {@link XRCamera}.
885
+ * Only available during the current animation loop.
886
+ *
887
+ * @param {XRCamera} xrCamera - The camera to query.
888
+ * @return {?Texture} An opaque texture representing the current raw camera frame.
889
+ */
890
+ this.getCameraTexture = function ( xrCamera ) {
891
+
892
+ return cameraAccessTextures[ xrCamera ];
893
+
894
+ };
895
+
871
896
  // Animation Loop
872
897
 
873
898
  let onAnimationFrameCallback = null;
@@ -973,7 +998,42 @@ class WebXRManager extends EventDispatcher {
973
998
 
974
999
  if ( depthData && depthData.isValid && depthData.texture ) {
975
1000
 
976
- depthSensing.init( renderer, depthData, session.renderState );
1001
+ depthSensing.init( depthData, session.renderState );
1002
+
1003
+ }
1004
+
1005
+ }
1006
+
1007
+ const cameraAccessEnabled = enabledFeatures &&
1008
+ enabledFeatures.includes( 'camera-access' );
1009
+
1010
+ if ( cameraAccessEnabled ) {
1011
+
1012
+ renderer.state.unbindTexture();
1013
+
1014
+ if ( glBinding ) {
1015
+
1016
+ for ( let i = 0; i < views.length; i ++ ) {
1017
+
1018
+ const camera = views[ i ].camera;
1019
+
1020
+ if ( camera ) {
1021
+
1022
+ let cameraTex = cameraAccessTextures[ camera ];
1023
+
1024
+ if ( ! cameraTex ) {
1025
+
1026
+ cameraTex = new ExternalTexture();
1027
+ cameraAccessTextures[ camera ] = cameraTex;
1028
+
1029
+ }
1030
+
1031
+ const glTexture = glBinding.getCameraImage( camera );
1032
+ cameraTex.sourceTexture = glTexture;
1033
+
1034
+ }
1035
+
1036
+ }
977
1037
 
978
1038
  }
979
1039