super-three 0.169.1 → 0.170.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 (193) hide show
  1. package/build/three.cjs +974 -562
  2. package/build/three.module.js +975 -559
  3. package/build/three.module.min.js +1 -1
  4. package/build/three.webgpu.js +8398 -9842
  5. package/build/three.webgpu.min.js +1 -1
  6. package/build/three.webgpu.nodes.js +8398 -9842
  7. package/build/three.webgpu.nodes.min.js +1 -1
  8. package/examples/jsm/Addons.js +3 -3
  9. package/examples/jsm/animation/MMDAnimationHelper.js +2 -0
  10. package/examples/jsm/animation/MMDPhysics.js +2 -0
  11. package/examples/jsm/controls/TransformControls.js +22 -6
  12. package/examples/jsm/csm/CSM.js +2 -2
  13. package/examples/jsm/csm/CSMFrustum.js +7 -4
  14. package/examples/jsm/csm/CSMHelper.js +2 -0
  15. package/examples/jsm/csm/CSMShadowNode.js +435 -0
  16. package/examples/jsm/curves/NURBSCurve.js +34 -3
  17. package/examples/jsm/exporters/GLTFExporter.js +138 -71
  18. package/examples/jsm/exporters/KTX2Exporter.js +35 -12
  19. package/examples/jsm/exporters/MMDExporter.js +6 -0
  20. package/examples/jsm/exporters/USDZExporter.js +21 -3
  21. package/examples/jsm/geometries/DecalGeometry.js +65 -20
  22. package/examples/jsm/geometries/InstancedPointsGeometry.js +2 -0
  23. package/examples/jsm/helpers/TextureHelperGPU.js +175 -0
  24. package/examples/jsm/interactive/HTMLMesh.js +1 -0
  25. package/examples/jsm/lighting/TiledLighting.js +18 -0
  26. package/examples/jsm/lights/RectAreaLightTexturesLib.js +1 -1
  27. package/examples/jsm/lines/LineMaterial.js +7 -2
  28. package/examples/jsm/lines/LineSegmentsGeometry.js +2 -0
  29. package/examples/jsm/lines/webgpu/LineSegments2.js +0 -15
  30. package/examples/jsm/lines/webgpu/Wireframe.js +56 -0
  31. package/examples/jsm/loaders/3DMLoader.js +1 -0
  32. package/examples/jsm/loaders/3MFLoader.js +91 -0
  33. package/examples/jsm/loaders/FBXLoader.js +12 -2
  34. package/examples/jsm/loaders/GLTFLoader.js +2 -0
  35. package/examples/jsm/loaders/KTX2Loader.js +140 -49
  36. package/examples/jsm/loaders/LDrawLoader.js +22 -136
  37. package/examples/jsm/loaders/LottieLoader.js +1 -0
  38. package/examples/jsm/loaders/MMDLoader.js +9 -2
  39. package/examples/jsm/materials/LDrawConditionalLineMaterial.js +143 -0
  40. package/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +114 -0
  41. package/examples/jsm/materials/MeshGouraudMaterial.js +6 -2
  42. package/examples/jsm/math/ColorSpaces.js +76 -0
  43. package/examples/jsm/misc/ProgressiveLightMap.js +52 -40
  44. package/examples/jsm/misc/ProgressiveLightMapGPU.js +293 -0
  45. package/examples/jsm/misc/VolumeSlice.js +1 -0
  46. package/examples/jsm/objects/WaterMesh.js +8 -8
  47. package/examples/jsm/postprocessing/AfterimagePass.js +14 -3
  48. package/examples/jsm/postprocessing/SSRPass.js +6 -0
  49. package/examples/jsm/renderers/CSS2DRenderer.js +6 -3
  50. package/examples/jsm/renderers/CSS3DRenderer.js +7 -4
  51. package/examples/jsm/shaders/FXAAShader.js +225 -224
  52. package/examples/jsm/transpiler/ShaderToyDecoder.js +1 -1
  53. package/{src/nodes → examples/jsm/tsl}/display/AfterImageNode.js +17 -20
  54. package/{src/nodes → examples/jsm/tsl}/display/AnaglyphPassNode.js +2 -6
  55. package/{src/nodes → examples/jsm/tsl}/display/AnamorphicNode.js +12 -18
  56. package/{src/nodes → examples/jsm/tsl}/display/BleachBypass.js +1 -3
  57. package/{src/nodes → examples/jsm/tsl}/display/BloomNode.js +11 -40
  58. package/{src/nodes → examples/jsm/tsl}/display/DenoiseNode.js +18 -41
  59. package/{src/nodes → examples/jsm/tsl}/display/DepthOfFieldNode.js +2 -8
  60. package/{src/nodes → examples/jsm/tsl}/display/DotScreenNode.js +2 -9
  61. package/examples/jsm/tsl/display/FXAANode.js +316 -0
  62. package/{src/nodes → examples/jsm/tsl}/display/FilmNode.js +2 -6
  63. package/{src/nodes → examples/jsm/tsl}/display/GTAONode.js +30 -70
  64. package/{src/nodes → examples/jsm/tsl}/display/GaussianBlurNode.js +74 -36
  65. package/examples/jsm/tsl/display/LensflareNode.js +161 -0
  66. package/{src/nodes → examples/jsm/tsl}/display/Lut3DNode.js +1 -4
  67. package/{src/nodes → examples/jsm/tsl}/display/MotionBlur.js +2 -3
  68. package/examples/jsm/tsl/display/OutlineNode.js +434 -0
  69. package/{src/nodes → examples/jsm/tsl}/display/ParallaxBarrierPassNode.js +1 -5
  70. package/{src/nodes → examples/jsm/tsl}/display/PixelationPassNode.js +3 -15
  71. package/{src/nodes → examples/jsm/tsl}/display/RGBShiftNode.js +1 -6
  72. package/examples/jsm/tsl/display/SMAANode.js +620 -0
  73. package/{src/nodes → examples/jsm/tsl}/display/SSAAPassNode.js +10 -25
  74. package/examples/jsm/tsl/display/SSRNode.js +343 -0
  75. package/{src/nodes → examples/jsm/tsl}/display/Sepia.js +1 -2
  76. package/{src/nodes → examples/jsm/tsl}/display/SobelOperatorNode.js +3 -11
  77. package/{src/nodes → examples/jsm/tsl}/display/StereoCompositePassNode.js +9 -11
  78. package/{src/nodes → examples/jsm/tsl}/display/StereoPassNode.js +10 -11
  79. package/examples/jsm/tsl/display/TRAAPassNode.js +355 -0
  80. package/{src/nodes → examples/jsm/tsl}/display/TransitionNode.js +1 -6
  81. package/examples/jsm/tsl/display/hashBlur.js +24 -0
  82. package/examples/jsm/tsl/lighting/TiledLightsNode.js +392 -0
  83. package/examples/jsm/utils/{TextureUtilsGPU.js → WebGPUTextureUtils.js} +2 -1
  84. package/examples/jsm/webxr/OculusHandPointerModel.js +21 -21
  85. package/examples/jsm/webxr/Text2D.js +6 -6
  86. package/package.json +2 -2
  87. package/src/Three.WebGPU.Nodes.js +4 -0
  88. package/src/Three.WebGPU.js +4 -0
  89. package/src/constants.js +1 -6
  90. package/src/core/BufferGeometry.js +44 -6
  91. package/src/geometries/CylinderGeometry.js +2 -2
  92. package/src/materials/LineBasicMaterial.js +6 -2
  93. package/src/materials/LineDashedMaterial.js +6 -2
  94. package/src/materials/Material.js +14 -1
  95. package/src/materials/MeshBasicMaterial.js +6 -2
  96. package/src/materials/MeshDepthMaterial.js +6 -2
  97. package/src/materials/MeshDistanceMaterial.js +6 -2
  98. package/src/materials/MeshLambertMaterial.js +6 -2
  99. package/src/materials/MeshMatcapMaterial.js +6 -2
  100. package/src/materials/MeshNormalMaterial.js +6 -2
  101. package/src/materials/MeshPhongMaterial.js +6 -2
  102. package/src/materials/MeshPhysicalMaterial.js +6 -2
  103. package/src/materials/MeshStandardMaterial.js +6 -2
  104. package/src/materials/MeshToonMaterial.js +6 -2
  105. package/src/materials/PointsMaterial.js +6 -2
  106. package/src/materials/RawShaderMaterial.js +6 -2
  107. package/src/materials/ShaderMaterial.js +6 -2
  108. package/src/materials/ShadowMaterial.js +6 -2
  109. package/src/materials/SpriteMaterial.js +6 -2
  110. package/src/materials/nodes/NodeMaterial.js +31 -9
  111. package/src/materials/nodes/SpriteNodeMaterial.js +11 -2
  112. package/src/materials/nodes/manager/NodeMaterialObserver.js +111 -2
  113. package/src/math/ColorManagement.js +118 -85
  114. package/src/math/Vector4.js +11 -0
  115. package/src/nodes/Nodes.js +1 -21
  116. package/src/nodes/TSL.js +6 -24
  117. package/src/nodes/accessors/Camera.js +0 -1
  118. package/src/nodes/accessors/SceneNode.js +35 -1
  119. package/src/nodes/accessors/StorageBufferNode.js +32 -10
  120. package/src/nodes/accessors/VelocityNode.js +13 -3
  121. package/src/nodes/code/FunctionCallNode.js +16 -5
  122. package/src/nodes/code/ScriptableNode.js +4 -4
  123. package/src/nodes/core/Node.js +1 -0
  124. package/src/nodes/core/NodeBuilder.js +29 -5
  125. package/src/nodes/core/VarNode.js +15 -3
  126. package/src/nodes/display/ColorAdjustment.js +53 -4
  127. package/src/nodes/display/ColorSpaceFunctions.js +5 -5
  128. package/src/nodes/display/ColorSpaceNode.js +27 -39
  129. package/src/nodes/display/PassNode.js +6 -4
  130. package/src/nodes/display/ToneMappingNode.js +1 -1
  131. package/src/nodes/display/ViewportDepthNode.js +33 -1
  132. package/src/nodes/functions/PhysicalLightingModel.js +21 -15
  133. package/src/nodes/functions/material/getAlphaHashThreshold.js +64 -0
  134. package/src/nodes/functions/material/getGeometryRoughness.js +8 -2
  135. package/src/nodes/functions/material/getParallaxCorrectNormal.js +22 -0
  136. package/src/nodes/gpgpu/ComputeNode.js +9 -1
  137. package/src/nodes/lighting/AnalyticLightNode.js +12 -416
  138. package/src/nodes/lighting/LightsNode.js +24 -12
  139. package/src/nodes/lighting/PointLightNode.js +36 -26
  140. package/src/nodes/lighting/RectAreaLightNode.js +3 -0
  141. package/src/nodes/lighting/ShadowNode.js +484 -0
  142. package/src/nodes/utils/LoopNode.js +2 -2
  143. package/src/nodes/utils/Oscillators.js +6 -0
  144. package/src/nodes/utils/PostProcessingUtils.js +89 -0
  145. package/src/nodes/utils/ReflectorNode.js +101 -15
  146. package/src/nodes/utils/Timer.js +29 -0
  147. package/src/objects/BatchedMesh.js +458 -241
  148. package/src/renderers/WebGLRenderer.js +120 -117
  149. package/src/renderers/common/Attributes.js +4 -0
  150. package/src/renderers/common/Backend.js +2 -0
  151. package/src/renderers/common/Background.js +14 -4
  152. package/src/renderers/common/Bindings.js +3 -2
  153. package/src/renderers/common/Constants.js +2 -1
  154. package/src/renderers/common/Geometries.js +20 -0
  155. package/src/renderers/common/IndirectStorageBufferAttribute.js +15 -0
  156. package/src/renderers/common/Lighting.js +45 -0
  157. package/src/renderers/common/PostProcessingUtils.js +86 -0
  158. package/src/renderers/common/RenderList.js +39 -11
  159. package/src/renderers/common/RenderLists.js +4 -2
  160. package/src/renderers/common/RenderObject.js +18 -1
  161. package/src/renderers/common/Renderer.js +165 -26
  162. package/src/renderers/common/Textures.js +30 -14
  163. package/src/renderers/common/nodes/NodeLibrary.js +1 -14
  164. package/src/renderers/common/nodes/Nodes.js +2 -2
  165. package/src/renderers/shaders/ShaderChunk/colorspace_pars_fragment.glsl.js +4 -24
  166. package/src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl.js +8 -0
  167. package/src/renderers/shaders/ShaderChunk/map_fragment.glsl.js +2 -2
  168. package/src/renderers/webgl/WebGLBufferRenderer.js +2 -6
  169. package/src/renderers/webgl/WebGLCapabilities.js +0 -7
  170. package/src/renderers/webgl/WebGLIndexedBufferRenderer.js +2 -6
  171. package/src/renderers/webgl/WebGLProgram.js +24 -28
  172. package/src/renderers/webgl/WebGLPrograms.js +5 -2
  173. package/src/renderers/webgl/WebGLState.js +37 -1
  174. package/src/renderers/webgl/WebGLTextures.js +29 -12
  175. package/src/renderers/webgl-fallback/WebGLBackend.js +98 -31
  176. package/src/renderers/webgl-fallback/WebGLBufferRenderer.js +2 -7
  177. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +33 -8
  178. package/src/renderers/webgpu/WebGPUBackend.js +105 -25
  179. package/src/renderers/webgpu/WebGPURenderer.Nodes.js +1 -1
  180. package/src/renderers/webgpu/WebGPURenderer.js +1 -1
  181. package/src/renderers/webgpu/nodes/BasicNodeLibrary.js +0 -8
  182. package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +0 -8
  183. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +10 -20
  184. package/src/renderers/webgpu/nodes/WGSLNodeFunction.js +12 -4
  185. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +29 -9
  186. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +24 -6
  187. package/src/renderers/webgpu/utils/WebGPUUtils.js +0 -1
  188. package/src/renderers/webxr/WebXRManager.js +4 -4
  189. package/examples/jsm/cameras/CinematicCamera.js +0 -208
  190. package/src/nodes/display/FXAANode.js +0 -332
  191. package/src/nodes/utils/OscNode.js +0 -85
  192. package/src/nodes/utils/TimerNode.js +0 -97
  193. /package/examples/jsm/utils/{TextureUtils.js → WebGLTextureUtils.js} +0 -0
@@ -375,6 +375,70 @@ class ThreeMFLoader extends Loader {
375
375
 
376
376
  }
377
377
 
378
+ function parseImplicitIONode( implicitIONode ) {
379
+
380
+ const portNodes = implicitIONode.children;
381
+ const portArguments = {};
382
+ for ( let i = 0; i < portNodes.length; i ++ ) {
383
+
384
+ const args = { type: portNodes[ i ].nodeName.substring( 2 ) };
385
+ for ( let j = 0; j < portNodes[ i ].attributes.length; j ++ ) {
386
+
387
+ const attrib = portNodes[ i ].attributes[ j ];
388
+ if ( attrib.specified ) {
389
+ args[ attrib.name ] = attrib.value;
390
+ }
391
+ }
392
+
393
+ portArguments[ portNodes[ i ].getAttribute( 'identifier' ) ] = args;
394
+
395
+ }
396
+
397
+ return portArguments;
398
+
399
+ }
400
+
401
+ function parseImplicitFunctionNode( implicitFunctionNode ) {
402
+
403
+ const implicitFunctionData = {
404
+ id: implicitFunctionNode.getAttribute( 'id' ),
405
+ displayname: implicitFunctionNode.getAttribute( 'displayname' )
406
+ };
407
+
408
+ const functionNodes = implicitFunctionNode.children;
409
+
410
+ const operations = {};
411
+
412
+ for ( let i = 0; i < functionNodes.length; i ++ ) {
413
+
414
+ const operatorNode = functionNodes[ i ];
415
+
416
+ if ( operatorNode.nodeName === 'i:in' || operatorNode.nodeName === 'i:out' ) {
417
+
418
+ operations[ operatorNode.nodeName === 'i:in' ? "inputs" : "outputs" ] = parseImplicitIONode( operatorNode );
419
+
420
+ } else {
421
+
422
+ const inputNodes = operatorNode.children;
423
+ let portArguments = { "op": operatorNode.nodeName.substring( 2 ), "identifier": operatorNode.getAttribute( 'identifier' ) };
424
+ for ( let i = 0; i < inputNodes.length; i ++ ) {
425
+
426
+ portArguments[ inputNodes[ i ].nodeName.substring( 2 ) ] = parseImplicitIONode( inputNodes[ i ] );
427
+
428
+ }
429
+
430
+ operations[ portArguments[ "identifier" ] ] = portArguments;
431
+
432
+ }
433
+
434
+ }
435
+
436
+ implicitFunctionData[ 'operations' ] = operations;
437
+
438
+ return implicitFunctionData;
439
+
440
+ }
441
+
378
442
  function parseMetallicDisplaypropertiesNode( metallicDisplaypropetiesNode ) {
379
443
 
380
444
  const metallicDisplaypropertiesData = {
@@ -673,6 +737,25 @@ class ThreeMFLoader extends Loader {
673
737
 
674
738
  //
675
739
 
740
+ const implicitFunctionNodes = resourcesNode.querySelectorAll( 'implicitfunction' );
741
+
742
+ if ( implicitFunctionNodes.length > 0 ) {
743
+
744
+ resourcesData[ 'implicitfunction' ] = {};
745
+
746
+ }
747
+
748
+
749
+ for ( let i = 0; i < implicitFunctionNodes.length; i ++ ) {
750
+
751
+ const implicitFunctionNode = implicitFunctionNodes[ i ];
752
+ const implicitFunctionData = parseImplicitFunctionNode( implicitFunctionNode );
753
+ resourcesData[ 'implicitfunction' ][ implicitFunctionData[ 'id' ] ] = implicitFunctionData;
754
+
755
+ }
756
+
757
+ //
758
+
676
759
  resourcesData[ 'pbmetallicdisplayproperties' ] = {};
677
760
  const pbmetallicdisplaypropertiesNodes = resourcesNode.querySelectorAll( 'pbmetallicdisplayproperties' );
678
761
 
@@ -846,11 +929,13 @@ class ThreeMFLoader extends Loader {
846
929
  case 'linear':
847
930
  texture.magFilter = LinearFilter;
848
931
  texture.minFilter = LinearFilter;
932
+ texture.generateMipmaps = false;
849
933
  break;
850
934
 
851
935
  case 'nearest':
852
936
  texture.magFilter = NearestFilter;
853
937
  texture.minFilter = NearestFilter;
938
+ texture.generateMipmaps = false;
854
939
  break;
855
940
 
856
941
  default:
@@ -1367,6 +1452,12 @@ class ThreeMFLoader extends Loader {
1367
1452
 
1368
1453
  }
1369
1454
 
1455
+ if ( modelData.resources.implicitfunction ) {
1456
+
1457
+ console.warn( 'THREE.ThreeMFLoader: Implicit Functions are implemented in data-only.', modelData.resources.implicitfunction );
1458
+
1459
+ }
1460
+
1370
1461
  }
1371
1462
 
1372
1463
  function buildObjects( data3mf ) {
@@ -571,9 +571,19 @@ class FBXTreeParser {
571
571
 
572
572
  }
573
573
 
574
- if ( materialNode.Opacity ) {
574
+ // the transparency handling is implemented based on Blender/Unity's approach: https://github.com/sobotka/blender-addons/blob/7d80f2f97161fc8e353a657b179b9aa1f8e5280b/io_scene_fbx/import_fbx.py#L1444-L1459
575
575
 
576
- parameters.opacity = parseFloat( materialNode.Opacity.value );
576
+ parameters.opacity = 1 - ( materialNode.TransparencyFactor ? parseFloat( materialNode.TransparencyFactor.value ) : 0 );
577
+
578
+ if ( parameters.opacity === 1 || parameters.opacity === 0 ) {
579
+
580
+ parameters.opacity = ( materialNode.Opacity ? parseFloat( materialNode.Opacity.value ) : null );
581
+
582
+ if ( parameters.opacity === null ) {
583
+
584
+ parameters.opacity = 1 - ( materialNode.TransparentColor ? parseFloat( materialNode.TransparentColor.value[ 0 ] ) : 0 );
585
+
586
+ }
577
587
 
578
588
  }
579
589
 
@@ -2525,6 +2525,7 @@ function getImageURIMimeType( uri ) {
2525
2525
 
2526
2526
  if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
2527
2527
  if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
2528
+ if ( uri.search( /\.ktx2($|\?)/i ) > 0 || uri.search( /^data\:image\/ktx2/ ) === 0 ) return 'image/ktx2';
2528
2529
 
2529
2530
  return 'image/png';
2530
2531
 
@@ -3230,6 +3231,7 @@ class GLTFParser {
3230
3231
  texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
3231
3232
  texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
3232
3233
  texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
3234
+ texture.generateMipmaps = ! texture.isCompressedTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
3233
3235
 
3234
3236
  parser.associations.set( texture, { textures: textureIndex } );
3235
3237
 
@@ -18,17 +18,16 @@ import {
18
18
  CompressedCubeTexture,
19
19
  Data3DTexture,
20
20
  DataTexture,
21
- DisplayP3ColorSpace,
22
21
  FileLoader,
23
22
  FloatType,
24
23
  HalfFloatType,
25
24
  NoColorSpace,
26
25
  LinearFilter,
27
26
  LinearMipmapLinearFilter,
28
- LinearDisplayP3ColorSpace,
29
27
  LinearSRGBColorSpace,
30
28
  Loader,
31
29
  RedFormat,
30
+ RGB_BPTC_UNSIGNED_Format,
32
31
  RGB_ETC1_Format,
33
32
  RGB_ETC2_Format,
34
33
  RGB_PVRTC_4BPPV1_Format,
@@ -72,6 +71,7 @@ import {
72
71
  KHR_DF_PRIMARIES_DISPLAYP3
73
72
  } from '../libs/ktx-parse.module.js';
74
73
  import { ZSTDDecoder } from '../libs/zstddec.module.js';
74
+ import { DisplayP3ColorSpace, LinearDisplayP3ColorSpace } from '../math/ColorSpaces.js';
75
75
 
76
76
  const _taskCache = new WeakMap();
77
77
 
@@ -126,6 +126,7 @@ class KTX2Loader extends Loader {
126
126
 
127
127
  this.workerConfig = {
128
128
  astcSupported: await renderer.hasFeatureAsync( 'texture-compression-astc' ),
129
+ astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856
129
130
  etc1Supported: await renderer.hasFeatureAsync( 'texture-compression-etc1' ),
130
131
  etc2Supported: await renderer.hasFeatureAsync( 'texture-compression-etc2' ),
131
132
  dxtSupported: await renderer.hasFeatureAsync( 'texture-compression-bc' ),
@@ -143,6 +144,7 @@ class KTX2Loader extends Loader {
143
144
 
144
145
  this.workerConfig = {
145
146
  astcSupported: renderer.hasFeature( 'texture-compression-astc' ),
147
+ astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856
146
148
  etc1Supported: renderer.hasFeature( 'texture-compression-etc1' ),
147
149
  etc2Supported: renderer.hasFeature( 'texture-compression-etc2' ),
148
150
  dxtSupported: renderer.hasFeature( 'texture-compression-bc' ),
@@ -154,6 +156,8 @@ class KTX2Loader extends Loader {
154
156
 
155
157
  this.workerConfig = {
156
158
  astcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ),
159
+ astcHDRSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' )
160
+ && renderer.extensions.get( 'WEBGL_compressed_texture_astc' ).getSupportedProfiles().includes( 'hdr' ),
157
161
  etc1Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc1' ),
158
162
  etc2Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc' ),
159
163
  dxtSupported: renderer.extensions.has( 'WEBGL_compressed_texture_s3tc' ),
@@ -193,6 +197,7 @@ class KTX2Loader extends Loader {
193
197
  const body = [
194
198
  '/* constants */',
195
199
  'let _EngineFormat = ' + JSON.stringify( KTX2Loader.EngineFormat ),
200
+ 'let _EngineType = ' + JSON.stringify( KTX2Loader.EngineType ),
196
201
  'let _TranscoderFormat = ' + JSON.stringify( KTX2Loader.TranscoderFormat ),
197
202
  'let _BasisFormat = ' + JSON.stringify( KTX2Loader.BasisFormat ),
198
203
  '/* basis_transcoder.js */',
@@ -285,23 +290,23 @@ class KTX2Loader extends Loader {
285
290
 
286
291
  _createTextureFrom( transcodeResult, container ) {
287
292
 
288
- const { faces, width, height, format, type, error, dfdFlags } = transcodeResult;
293
+ const { type: messageType, error, data: { faces, width, height, format, type, dfdFlags } } = transcodeResult;
289
294
 
290
- if ( type === 'error' ) return Promise.reject( error );
295
+ if ( messageType === 'error' ) return Promise.reject( error );
291
296
 
292
297
  let texture;
293
298
 
294
299
  if ( container.faceCount === 6 ) {
295
300
 
296
- texture = new CompressedCubeTexture( faces, format, UnsignedByteType );
301
+ texture = new CompressedCubeTexture( faces, format, type );
297
302
 
298
303
  } else {
299
304
 
300
305
  const mipmaps = faces[ 0 ].mipmaps;
301
306
 
302
307
  texture = container.layerCount > 1
303
- ? new CompressedArrayTexture( mipmaps, width, height, container.layerCount, format, UnsignedByteType )
304
- : new CompressedTexture( mipmaps, width, height, format, UnsignedByteType );
308
+ ? new CompressedArrayTexture( mipmaps, width, height, container.layerCount, format, type )
309
+ : new CompressedTexture( mipmaps, width, height, format, type );
305
310
 
306
311
  }
307
312
 
@@ -326,7 +331,19 @@ class KTX2Loader extends Loader {
326
331
 
327
332
  const container = read( new Uint8Array( buffer ) );
328
333
 
329
- if ( container.vkFormat !== VK_FORMAT_UNDEFINED ) {
334
+ // Basis UASTC HDR is a subset of ASTC, which can be transcoded efficiently
335
+ // to BC6H. To detect whether a KTX2 file uses Basis UASTC HDR, or default
336
+ // ASTC, inspect the DFD color model.
337
+ //
338
+ // Source: https://github.com/BinomialLLC/basis_universal/issues/381
339
+ const isBasisHDR = container.vkFormat === VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT
340
+ && container.dataFormatDescriptor[ 0 ].colorModel === 0xA7;
341
+
342
+ // If the device supports ASTC, Basis UASTC HDR requires no transcoder.
343
+ const needsTranscoder = container.vkFormat === VK_FORMAT_UNDEFINED
344
+ || isBasisHDR && ! this.workerConfig.astcHDRSupported;
345
+
346
+ if ( ! needsTranscoder ) {
330
347
 
331
348
  return createRawTexture( container );
332
349
 
@@ -365,9 +382,11 @@ class KTX2Loader extends Loader {
365
382
 
366
383
  KTX2Loader.BasisFormat = {
367
384
  ETC1S: 0,
368
- UASTC_4x4: 1,
385
+ UASTC: 1,
386
+ UASTC_HDR: 2,
369
387
  };
370
388
 
389
+ // Source: https://github.com/BinomialLLC/basis_universal/blob/master/webgl/texture_test/index.html
371
390
  KTX2Loader.TranscoderFormat = {
372
391
  ETC1: 0,
373
392
  ETC2: 1,
@@ -386,11 +405,15 @@ KTX2Loader.TranscoderFormat = {
386
405
  RGB565: 14,
387
406
  BGR565: 15,
388
407
  RGBA4444: 16,
408
+ BC6H: 22,
409
+ RGB_HALF: 24,
410
+ RGBA_HALF: 25,
389
411
  };
390
412
 
391
413
  KTX2Loader.EngineFormat = {
392
414
  RGBAFormat: RGBAFormat,
393
415
  RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
416
+ RGB_BPTC_UNSIGNED_Format: RGB_BPTC_UNSIGNED_Format,
394
417
  RGBA_BPTC_Format: RGBA_BPTC_Format,
395
418
  RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
396
419
  RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
@@ -401,6 +424,11 @@ KTX2Loader.EngineFormat = {
401
424
  RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format,
402
425
  };
403
426
 
427
+ KTX2Loader.EngineType = {
428
+ UnsignedByteType: UnsignedByteType,
429
+ HalfFloatType: HalfFloatType,
430
+ FloatType: FloatType,
431
+ };
404
432
 
405
433
  /* WEB WORKER */
406
434
 
@@ -411,6 +439,7 @@ KTX2Loader.BasisWorker = function () {
411
439
  let BasisModule;
412
440
 
413
441
  const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
442
+ const EngineType = _EngineType; // eslint-disable-line no-undef
414
443
  const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
415
444
  const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
416
445
 
@@ -430,9 +459,9 @@ KTX2Loader.BasisWorker = function () {
430
459
 
431
460
  try {
432
461
 
433
- const { faces, buffers, width, height, hasAlpha, format, dfdFlags } = transcode( message.buffer );
462
+ const { faces, buffers, width, height, hasAlpha, format, type, dfdFlags } = transcode( message.buffer );
434
463
 
435
- self.postMessage( { type: 'transcode', id: message.id, faces, width, height, hasAlpha, format, dfdFlags }, buffers );
464
+ self.postMessage( { type: 'transcode', id: message.id, data: { faces, width, height, hasAlpha, format, type, dfdFlags } }, buffers );
436
465
 
437
466
  } catch ( error ) {
438
467
 
@@ -488,7 +517,26 @@ KTX2Loader.BasisWorker = function () {
488
517
 
489
518
  }
490
519
 
491
- const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
520
+ let basisFormat;
521
+
522
+ if ( ktx2File.isUASTC() ) {
523
+
524
+ basisFormat = BasisFormat.UASTC;
525
+
526
+ } else if ( ktx2File.isETC1S() ) {
527
+
528
+ basisFormat = BasisFormat.ETC1S;
529
+
530
+ } else if ( ktx2File.isHDR() ) {
531
+
532
+ basisFormat = BasisFormat.UASTC_HDR;
533
+
534
+ } else {
535
+
536
+ throw new Error( 'THREE.KTX2Loader: Unknown Basis encoding' );
537
+
538
+ }
539
+
492
540
  const width = ktx2File.getWidth();
493
541
  const height = ktx2File.getHeight();
494
542
  const layerCount = ktx2File.getLayers() || 1;
@@ -497,7 +545,7 @@ KTX2Loader.BasisWorker = function () {
497
545
  const hasAlpha = ktx2File.getHasAlpha();
498
546
  const dfdFlags = ktx2File.getDFDFlags();
499
547
 
500
- const { transcoderFormat, engineFormat } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
548
+ const { transcoderFormat, engineFormat, engineType } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
501
549
 
502
550
  if ( ! width || ! height || ! levelCount ) {
503
551
 
@@ -551,9 +599,15 @@ KTX2Loader.BasisWorker = function () {
551
599
 
552
600
  }
553
601
 
554
- const dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, layer, 0, transcoderFormat ) );
602
+ let dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, layer, 0, transcoderFormat ) );
555
603
  const status = ktx2File.transcodeImage( dst, mip, layer, face, transcoderFormat, 0, - 1, - 1 );
556
604
 
605
+ if ( engineType === EngineType.HalfFloatType ) {
606
+
607
+ dst = new Uint16Array( dst.buffer, dst.byteOffset, dst.byteLength / Uint16Array.BYTES_PER_ELEMENT );
608
+
609
+ }
610
+
557
611
  if ( ! status ) {
558
612
 
559
613
  cleanup();
@@ -572,122 +626,159 @@ KTX2Loader.BasisWorker = function () {
572
626
 
573
627
  }
574
628
 
575
- faces.push( { mipmaps, width, height, format: engineFormat } );
629
+ faces.push( { mipmaps, width, height, format: engineFormat, type: engineType } );
576
630
 
577
631
  }
578
632
 
579
633
  cleanup();
580
634
 
581
- return { faces, buffers, width, height, hasAlpha, format: engineFormat, dfdFlags };
635
+ return { faces, buffers, width, height, hasAlpha, dfdFlags, format: engineFormat, type: engineType };
582
636
 
583
637
  }
584
638
 
585
639
  //
586
640
 
587
- // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
588
- // device capabilities, and texture dimensions. The list below ranks the formats separately
589
- // for ETC1S and UASTC.
641
+ // Optimal choice of a transcoder target format depends on the Basis format (ETC1S, UASTC, or
642
+ // UASTC HDR), device capabilities, and texture dimensions. The list below ranks the formats
643
+ // separately for each format. Currently, priority is assigned based on:
590
644
  //
591
- // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
592
- // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
593
- // chooses RGBA32 only as a last resort and does not expose that option to the caller.
645
+ // high quality > low quality > uncompressed
646
+ //
647
+ // Prioritization may be revisited, or exposed for configuration, in the future.
648
+ //
649
+ // Reference: https://github.com/KhronosGroup/3D-Formats-Guidelines/blob/main/KTXDeveloperGuide.md
594
650
  const FORMAT_OPTIONS = [
595
651
  {
596
652
  if: 'astcSupported',
597
- basisFormat: [ BasisFormat.UASTC_4x4 ],
653
+ basisFormat: [ BasisFormat.UASTC ],
598
654
  transcoderFormat: [ TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4 ],
599
655
  engineFormat: [ EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format ],
656
+ engineType: [ EngineType.UnsignedByteType ],
600
657
  priorityETC1S: Infinity,
601
658
  priorityUASTC: 1,
602
659
  needsPowerOfTwo: false,
603
660
  },
604
661
  {
605
662
  if: 'bptcSupported',
606
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
663
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
607
664
  transcoderFormat: [ TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5 ],
608
665
  engineFormat: [ EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format ],
666
+ engineType: [ EngineType.UnsignedByteType ],
609
667
  priorityETC1S: 3,
610
668
  priorityUASTC: 2,
611
669
  needsPowerOfTwo: false,
612
670
  },
613
671
  {
614
672
  if: 'dxtSupported',
615
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
673
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
616
674
  transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ],
617
675
  engineFormat: [ EngineFormat.RGBA_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],
676
+ engineType: [ EngineType.UnsignedByteType ],
618
677
  priorityETC1S: 4,
619
678
  priorityUASTC: 5,
620
679
  needsPowerOfTwo: false,
621
680
  },
622
681
  {
623
682
  if: 'etc2Supported',
624
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
683
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
625
684
  transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC2 ],
626
685
  engineFormat: [ EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format ],
686
+ engineType: [ EngineType.UnsignedByteType ],
627
687
  priorityETC1S: 1,
628
688
  priorityUASTC: 3,
629
689
  needsPowerOfTwo: false,
630
690
  },
631
691
  {
632
692
  if: 'etc1Supported',
633
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
693
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
634
694
  transcoderFormat: [ TranscoderFormat.ETC1 ],
635
695
  engineFormat: [ EngineFormat.RGB_ETC1_Format ],
696
+ engineType: [ EngineType.UnsignedByteType ],
636
697
  priorityETC1S: 2,
637
698
  priorityUASTC: 4,
638
699
  needsPowerOfTwo: false,
639
700
  },
640
701
  {
641
702
  if: 'pvrtcSupported',
642
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
703
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
643
704
  transcoderFormat: [ TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA ],
644
705
  engineFormat: [ EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format ],
706
+ engineType: [ EngineType.UnsignedByteType ],
645
707
  priorityETC1S: 5,
646
708
  priorityUASTC: 6,
647
709
  needsPowerOfTwo: true,
648
710
  },
649
- ];
711
+ {
712
+ if: 'bptcSupported',
713
+ basisFormat: [ BasisFormat.UASTC_HDR ],
714
+ transcoderFormat: [ TranscoderFormat.BC6H ],
715
+ engineFormat: [ EngineFormat.RGB_BPTC_UNSIGNED_Format ],
716
+ engineType: [ EngineType.HalfFloatType ],
717
+ priorityHDR: 1,
718
+ needsPowerOfTwo: false,
719
+ },
650
720
 
651
- const ETC1S_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
721
+ // Uncompressed fallbacks.
652
722
 
653
- return a.priorityETC1S - b.priorityETC1S;
723
+ {
724
+ basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ],
725
+ transcoderFormat: [ TranscoderFormat.RGBA32, TranscoderFormat.RGBA32 ],
726
+ engineFormat: [ EngineFormat.RGBAFormat, EngineFormat.RGBAFormat ],
727
+ engineType: [ EngineType.UnsignedByteType, EngineType.UnsignedByteType ],
728
+ priorityETC1S: 100,
729
+ priorityUASTC: 100,
730
+ needsPowerOfTwo: false,
731
+ },
732
+ {
733
+ basisFormat: [ BasisFormat.UASTC_HDR ],
734
+ transcoderFormat: [ TranscoderFormat.RGBA_HALF ],
735
+ engineFormat: [ EngineFormat.RGBAFormat ],
736
+ engineType: [ EngineType.HalfFloatType ],
737
+ priorityHDR: 100,
738
+ needsPowerOfTwo: false,
739
+ }
740
+ ];
654
741
 
655
- } );
656
- const UASTC_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
742
+ const OPTIONS = {
743
+ // TODO: For ETC1S we intentionally sort by _UASTC_ priority, preserving
744
+ // a historical accident shown to avoid performance pitfalls for Linux with
745
+ // Firefox & AMD GPU (RadeonSI). Further work needed.
746
+ // See https://github.com/mrdoob/three.js/pull/29730.
747
+ [ BasisFormat.ETC1S ]: FORMAT_OPTIONS
748
+ .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.ETC1S ) )
749
+ .sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ),
657
750
 
658
- return a.priorityUASTC - b.priorityUASTC;
751
+ [ BasisFormat.UASTC ]: FORMAT_OPTIONS
752
+ .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.UASTC ) )
753
+ .sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ),
659
754
 
660
- } );
755
+ [ BasisFormat.UASTC_HDR ]: FORMAT_OPTIONS
756
+ .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.UASTC_HDR ) )
757
+ .sort( ( a, b ) => a.priorityHDR - b.priorityHDR ),
758
+ };
661
759
 
662
760
  function getTranscoderFormat( basisFormat, width, height, hasAlpha ) {
663
761
 
664
- let transcoderFormat;
665
- let engineFormat;
666
-
667
- const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
762
+ const options = OPTIONS[ basisFormat ];
668
763
 
669
764
  for ( let i = 0; i < options.length; i ++ ) {
670
765
 
671
766
  const opt = options[ i ];
672
767
 
673
- if ( ! config[ opt.if ] ) continue;
768
+ if ( opt.if && ! config[ opt.if ] ) continue;
674
769
  if ( ! opt.basisFormat.includes( basisFormat ) ) continue;
675
770
  if ( hasAlpha && opt.transcoderFormat.length < 2 ) continue;
676
771
  if ( opt.needsPowerOfTwo && ! ( isPowerOfTwo( width ) && isPowerOfTwo( height ) ) ) continue;
677
772
 
678
- transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ];
679
- engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ];
773
+ const transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ];
774
+ const engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ];
775
+ const engineType = opt.engineType[ 0 ];
680
776
 
681
- return { transcoderFormat, engineFormat };
777
+ return { transcoderFormat, engineFormat, engineType };
682
778
 
683
779
  }
684
780
 
685
- console.warn( 'THREE.KTX2Loader: No suitable compressed texture format found. Decoding to RGBA32.' );
686
-
687
- transcoderFormat = TranscoderFormat.RGBA32;
688
- engineFormat = EngineFormat.RGBAFormat;
689
-
690
- return { transcoderFormat, engineFormat };
781
+ throw new Error( 'THREE.KTX2Loader: Failed to identify transcoding target.' );
691
782
 
692
783
  }
693
784