@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
@@ -1,20 +1,26 @@
1
- import { FileLoader, Loader, TextureLoader, RepeatWrapping, MeshBasicNodeMaterial, MeshPhysicalNodeMaterial } from 'three/webgpu';
1
+ import {
2
+ FileLoader, Loader, TextureLoader, RepeatWrapping, MeshBasicNodeMaterial,
3
+ MeshPhysicalNodeMaterial, DoubleSide,
4
+ } from 'three/webgpu';
2
5
 
3
6
  import {
4
7
  float, bool, int, vec2, vec3, vec4, color, texture,
5
8
  positionLocal, positionWorld, uv, vertexColor,
6
9
  normalLocal, normalWorld, tangentLocal, tangentWorld,
7
- add, sub, mul, div, mod, abs, sign, floor, ceil, round, pow, sin, cos, tan,
8
- asin, acos, atan2, sqrt, exp, clamp, min, max, normalize, length, dot, cross, normalMap,
10
+ mul, abs, sign, floor, ceil, round, sin, cos, tan,
11
+ asin, acos, sqrt, exp, clamp, min, max, normalize, length, dot, cross, normalMap,
9
12
  remap, smoothstep, luminance, mx_rgbtohsv, mx_hsvtorgb,
10
- mix, split,
13
+ mix, saturation, transpose, determinant, inverse, log, reflect, refract, element,
11
14
  mx_ramplr, mx_ramptb, mx_splitlr, mx_splittb,
12
15
  mx_fractal_noise_float, mx_noise_float, mx_cell_noise_float, mx_worley_noise_float,
13
16
  mx_transform_uv,
14
17
  mx_safepower, mx_contrast,
15
18
  mx_srgb_texture_to_lin_rec709,
16
- saturation,
17
- timerLocal, frameId
19
+ mx_add, mx_atan2, mx_divide, mx_modulo, mx_multiply, mx_power, mx_subtract,
20
+ mx_timer, mx_frame, mat3, mx_ramp4,
21
+ mx_invert, mx_ifgreater, mx_ifgreatereq, mx_ifequal, distance,
22
+ mx_separate, mx_place2d, mx_rotate2d, mx_rotate3d, mx_heighttonormal,
23
+ mx_unifiednoise2d, mx_unifiednoise3d
18
24
  } from 'three/tsl';
19
25
 
20
26
  const colorSpaceLib = {
@@ -35,19 +41,9 @@ class MXElement {
35
41
 
36
42
  // Ref: https://github.com/mrdoob/three.js/issues/24674
37
43
 
38
- const mx_add = ( in1, in2 = float( 0 ) ) => add( in1, in2 );
39
- const mx_subtract = ( in1, in2 = float( 0 ) ) => sub( in1, in2 );
40
- const mx_multiply = ( in1, in2 = float( 1 ) ) => mul( in1, in2 );
41
- const mx_divide = ( in1, in2 = float( 1 ) ) => div( in1, in2 );
42
- const mx_modulo = ( in1, in2 = float( 1 ) ) => mod( in1, in2 );
43
- const mx_power = ( in1, in2 = float( 1 ) ) => pow( in1, in2 );
44
- const mx_atan2 = ( in1 = float( 0 ), in2 = float( 1 ) ) => atan2( in1, in2 );
45
- const mx_timer = () => timerLocal();
46
- const mx_frame = () => frameId;
47
- const mx_invert = ( in1, amount = float( 1 ) ) => sub( amount, in1 );
44
+ // Enhanced separate node to support multi-output referencing (outx, outy, outz, outw)
48
45
 
49
- const separate = ( in1, channel ) => split( in1, channel.at( - 1 ) );
50
- const extract = ( in1, index ) => in1.element( index );
46
+ // Type/arity-aware MaterialX node wrappers
51
47
 
52
48
  const MXElements = [
53
49
 
@@ -70,7 +66,7 @@ const MXElements = [
70
66
  new MXElement( 'acos', acos, [ 'in' ] ),
71
67
  new MXElement( 'atan2', mx_atan2, [ 'in1', 'in2' ] ),
72
68
  new MXElement( 'sqrt', sqrt, [ 'in' ] ),
73
- //new MtlXElement( 'ln', ... ),
69
+ new MXElement( 'ln', log, [ 'in' ] ),
74
70
  new MXElement( 'exp', exp, [ 'in' ] ),
75
71
  new MXElement( 'clamp', clamp, [ 'in', 'low', 'high' ] ),
76
72
  new MXElement( 'min', min, [ 'in1', 'in2' ] ),
@@ -79,20 +75,27 @@ const MXElements = [
79
75
  new MXElement( 'magnitude', length, [ 'in1', 'in2' ] ),
80
76
  new MXElement( 'dotproduct', dot, [ 'in1', 'in2' ] ),
81
77
  new MXElement( 'crossproduct', cross, [ 'in' ] ),
78
+ new MXElement( 'distance', distance, [ 'in1', 'in2' ] ),
82
79
  new MXElement( 'invert', mx_invert, [ 'in', 'amount' ] ),
83
80
  //new MtlXElement( 'transformpoint', ... ),
84
81
  //new MtlXElement( 'transformvector', ... ),
85
82
  //new MtlXElement( 'transformnormal', ... ),
86
- //new MtlXElement( 'transformmatrix', ... ),
83
+ new MXElement( 'transformmatrix', mul, [ 'in1', 'in2' ] ),
87
84
  new MXElement( 'normalmap', normalMap, [ 'in', 'scale' ] ),
88
- //new MtlXElement( 'transpose', ... ),
89
- //new MtlXElement( 'determinant', ... ),
90
- //new MtlXElement( 'invertmatrix', ... ),
85
+ new MXElement( 'transpose', transpose, [ 'in' ] ),
86
+ new MXElement( 'determinant', determinant, [ 'in' ] ),
87
+ new MXElement( 'invertmatrix', inverse, [ 'in' ] ),
88
+ new MXElement( 'creatematrix', mat3, [ 'in1', 'in2', 'in3' ] ),
91
89
  //new MtlXElement( 'rotate2d', rotateUV, [ 'in', radians( 'amount' )** ] ),
92
90
  //new MtlXElement( 'rotate3d', ... ),
93
91
  //new MtlXElement( 'arrayappend', ... ),
94
92
  //new MtlXElement( 'dot', ... ),
95
93
 
94
+ new MXElement( 'length', length, [ 'in' ] ),
95
+ new MXElement( 'crossproduct', cross, [ 'in1', 'in2' ] ),
96
+ new MXElement( 'floor', floor, [ 'in' ] ),
97
+ new MXElement( 'ceil', ceil, [ 'in' ] ),
98
+
96
99
  // << Adjustment >>
97
100
  new MXElement( 'remap', remap, [ 'in', 'inlow', 'inhigh', 'outlow', 'outhigh' ] ),
98
101
  new MXElement( 'smoothstep', smoothstep, [ 'in', 'low', 'high' ] ),
@@ -113,6 +116,7 @@ const MXElements = [
113
116
  // << Procedural >>
114
117
  new MXElement( 'ramplr', mx_ramplr, [ 'valuel', 'valuer', 'texcoord' ] ),
115
118
  new MXElement( 'ramptb', mx_ramptb, [ 'valuet', 'valueb', 'texcoord' ] ),
119
+ new MXElement( 'ramp4', mx_ramp4, [ 'valuetl', 'valuetr', 'valuebl', 'valuebr', 'texcoord' ] ),
116
120
  new MXElement( 'splitlr', mx_splitlr, [ 'valuel', 'valuer', 'texcoord' ] ),
117
121
  new MXElement( 'splittb', mx_splittb, [ 'valuet', 'valueb', 'texcoord' ] ),
118
122
  new MXElement( 'noise2d', mx_noise_float, [ 'texcoord', 'amplitude', 'pivot' ] ),
@@ -122,23 +126,34 @@ const MXElements = [
122
126
  new MXElement( 'cellnoise3d', mx_cell_noise_float, [ 'texcoord' ] ),
123
127
  new MXElement( 'worleynoise2d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),
124
128
  new MXElement( 'worleynoise3d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),
125
-
129
+ new MXElement( 'unifiednoise2d', mx_unifiednoise2d, [ 'type', 'texcoord', 'freq', 'offset', 'jitter', 'outmin', 'outmax', 'clampoutput', 'octaves', 'lacunarity', 'diminish' ] ),
130
+ new MXElement( 'unifiednoise3d', mx_unifiednoise3d, [ 'type', 'texcoord', 'freq', 'offset', 'jitter', 'outmin', 'outmax', 'clampoutput', 'octaves', 'lacunarity', 'diminish' ] ),
126
131
  // << Supplemental >>
127
132
  //new MtlXElement( 'tiledimage', ... ),
128
133
  //new MtlXElement( 'triplanarprojection', triplanarTextures, [ 'filex', 'filey', 'filez' ] ),
129
134
  //new MtlXElement( 'ramp4', ... ),
130
- //new MtlXElement( 'place2d', mx_place2d, [ 'texcoord', 'pivot', 'scale', 'rotate', 'offset' ] ),
135
+ new MXElement( 'place2d', mx_place2d, [ 'texcoord', 'pivot', 'scale', 'rotate', 'offset', 'operationorder' ] ),
131
136
  new MXElement( 'safepower', mx_safepower, [ 'in1', 'in2' ] ),
132
137
  new MXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ] ),
133
138
  //new MtlXElement( 'hsvadjust', ... ),
134
139
  new MXElement( 'saturate', saturation, [ 'in', 'amount' ] ),
135
- new MXElement( 'extract', extract, [ 'in', 'index' ] ),
136
- new MXElement( 'separate2', separate, [ 'in' ] ),
137
- new MXElement( 'separate3', separate, [ 'in' ] ),
138
- new MXElement( 'separate4', separate, [ 'in' ] ),
140
+ new MXElement( 'extract', element, [ 'in', 'index' ] ),
141
+ new MXElement( 'separate2', mx_separate, [ 'in' ] ),
142
+ new MXElement( 'separate3', mx_separate, [ 'in' ] ),
143
+ new MXElement( 'separate4', mx_separate, [ 'in' ] ),
144
+ new MXElement( 'reflect', reflect, [ 'in', 'normal' ] ),
145
+ new MXElement( 'refract', refract, [ 'in', 'normal', 'ior' ] ),
139
146
 
140
147
  new MXElement( 'time', mx_timer ),
141
- new MXElement( 'frame', mx_frame )
148
+ new MXElement( 'frame', mx_frame ),
149
+ new MXElement( 'ifgreater', mx_ifgreater, [ 'value1', 'value2', 'in1', 'in2' ] ),
150
+ new MXElement( 'ifgreatereq', mx_ifgreatereq, [ 'value1', 'value2', 'in1', 'in2' ] ),
151
+ new MXElement( 'ifequal', mx_ifequal, [ 'value1', 'value2', 'in1', 'in2' ] ),
152
+
153
+ // Placeholder implementations for unsupported nodes
154
+ new MXElement( 'rotate2d', mx_rotate2d, [ 'in', 'amount' ] ),
155
+ new MXElement( 'rotate3d', mx_rotate3d, [ 'in', 'amount', 'axis' ] ),
156
+ new MXElement( 'heighttonormal', mx_heighttonormal, [ 'in', 'scale', 'texcoord' ] ),
142
157
 
143
158
  ];
144
159
 
@@ -220,6 +235,22 @@ class MaterialXLoader extends Loader {
220
235
  /**
221
236
  * Parses the given MaterialX data and returns the resulting materials.
222
237
  *
238
+ * Supported standard_surface inputs:
239
+ * - base, base_color: Base color/albedo
240
+ * - opacity: Alpha/transparency
241
+ * - specular_roughness: Surface roughness
242
+ * - metalness: Metallic property
243
+ * - specular: Specular reflection intensity
244
+ * - specular_color: Specular reflection color
245
+ * - ior: Index of refraction
246
+ * - specular_anisotropy, specular_rotation: Anisotropic reflection
247
+ * - transmission, transmission_color: Transmission properties
248
+ * - thin_film_thickness, thin_film_ior: Thin film interference
249
+ * - sheen, sheen_color, sheen_roughness: Sheen properties
250
+ * - normal: Normal map
251
+ * - coat, coat_roughness, coat_color: Clearcoat properties
252
+ * - emission, emissionColor: Emission properties
253
+ *
223
254
  * @param {string} text - The raw MaterialX data as a string.
224
255
  * @return {Object<string,NodeMaterial>} A dictionary holding the parse node materials.
225
256
  */
@@ -235,6 +266,12 @@ class MaterialXNode {
235
266
 
236
267
  constructor( materialX, nodeXML, nodePath = '' ) {
237
268
 
269
+ if ( ! materialX || typeof materialX !== 'object' ) {
270
+
271
+ console.warn( 'MaterialXNode: materialX argument is not an object!', { materialX, nodeXML, nodePath } );
272
+
273
+ }
274
+
238
275
  this.materialX = materialX;
239
276
  this.nodeXML = nodeXML;
240
277
  this.nodePath = nodePath ? nodePath + '/' + this.name : this.name;
@@ -418,6 +455,37 @@ class MaterialXNode {
418
455
 
419
456
  }
420
457
 
458
+ // Handle <input name="texcoord" type="vector2" ... />
459
+ if (
460
+ this.element === 'input' &&
461
+ this.name === 'texcoord' &&
462
+ this.type === 'vector2'
463
+ ) {
464
+
465
+ // Try to get index from defaultgeomprop (e.g., "UV0" => 0)
466
+ let index = 0;
467
+ const defaultGeomProp = this.getAttribute( 'defaultgeomprop' );
468
+ if ( defaultGeomProp && /^UV(\d+)$/.test( defaultGeomProp ) ) {
469
+
470
+ index = parseInt( defaultGeomProp.match( /^UV(\d+)$/ )[ 1 ], 10 );
471
+
472
+ }
473
+
474
+ node = uv( index );
475
+
476
+ }
477
+
478
+ // Multi-output support for separate/separate3
479
+ if (
480
+ ( this.element === 'separate3' || this.element === 'separate2' || this.element === 'separate4' ) &&
481
+ out && typeof out === 'string' && out.startsWith( 'out' )
482
+ ) {
483
+
484
+ const inNode = this.getNodeByName( 'in' );
485
+ return mx_separate( inNode, out );
486
+
487
+ }
488
+
421
489
  //
422
490
 
423
491
  const type = this.type;
@@ -519,6 +587,18 @@ class MaterialXNode {
519
587
 
520
588
  const nodeElement = MtlXLibrary[ element ];
521
589
 
590
+ if ( ! nodeElement ) {
591
+
592
+ throw new Error( `THREE.MaterialXLoader: Unexpected node ${ new XMLSerializer().serializeToString( this.nodeXML ) }.` );
593
+
594
+ }
595
+
596
+ if ( ! nodeElement.nodeFunc ) {
597
+
598
+ throw new Error( `THREE.MaterialXLoader: Unexpected node 2 ${ new XMLSerializer().serializeToString( this.nodeXML ) }.` );
599
+
600
+ }
601
+
522
602
  if ( out !== null ) {
523
603
 
524
604
  node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ), out );
@@ -551,6 +631,11 @@ class MaterialXNode {
551
631
 
552
632
  node = nodeToTypeClass( node );
553
633
 
634
+ } else {
635
+
636
+ console.warn( `THREE.MaterialXLoader: Unexpected node ${ new XMLSerializer().serializeToString( this.nodeXML ) }.` );
637
+ node = float( 0 );
638
+
554
639
  }
555
640
 
556
641
  node.name = this.name;
@@ -673,6 +758,12 @@ class MaterialXNode {
673
758
 
674
759
  //
675
760
 
761
+ let opacityNode = null;
762
+
763
+ if ( inputs.opacity ) opacityNode = inputs.opacity;
764
+
765
+ //
766
+
676
767
  let roughnessNode = null;
677
768
 
678
769
  if ( inputs.specular_roughness ) roughnessNode = inputs.specular_roughness;
@@ -685,6 +776,64 @@ class MaterialXNode {
685
776
 
686
777
  //
687
778
 
779
+ let specularIntensityNode = null;
780
+
781
+ if ( inputs.specular ) specularIntensityNode = inputs.specular;
782
+
783
+ //
784
+
785
+ let specularColorNode = null;
786
+
787
+ if ( inputs.specular_color ) specularColorNode = inputs.specular_color;
788
+
789
+ //
790
+
791
+ let iorNode = null;
792
+
793
+ if ( inputs.ior ) iorNode = inputs.ior;
794
+
795
+ //
796
+
797
+ let anisotropyNode = null;
798
+ let anisotropyRotationNode = null;
799
+
800
+ if ( inputs.specular_anisotropy ) anisotropyNode = inputs.specular_anisotropy;
801
+ if ( inputs.specular_rotation ) anisotropyRotationNode = inputs.specular_rotation;
802
+
803
+ //
804
+
805
+ let transmissionNode = null;
806
+ let transmissionColorNode = null;
807
+
808
+ if ( inputs.transmission ) transmissionNode = inputs.transmission;
809
+ if ( inputs.transmission_color ) transmissionColorNode = inputs.transmission_color;
810
+
811
+ //
812
+
813
+ let thinFilmThicknessNode = null;
814
+ let thinFilmIorNode = null;
815
+
816
+ if ( inputs.thin_film_thickness ) thinFilmThicknessNode = inputs.thin_film_thickness;
817
+
818
+ if ( inputs.thin_film_ior ) {
819
+
820
+ // Clamp IOR to valid range for Three.js (1.0 to 2.333)
821
+ thinFilmIorNode = clamp( inputs.thin_film_ior, float( 1.0 ), float( 2.333 ) );
822
+
823
+ }
824
+
825
+ //
826
+
827
+ let sheenNode = null;
828
+ let sheenColorNode = null;
829
+ let sheenRoughnessNode = null;
830
+
831
+ if ( inputs.sheen ) sheenNode = inputs.sheen;
832
+ if ( inputs.sheen_color ) sheenColorNode = inputs.sheen_color;
833
+ if ( inputs.sheen_roughness ) sheenRoughnessNode = inputs.sheen_roughness;
834
+
835
+ //
836
+
688
837
  let clearcoatNode = null;
689
838
  let clearcoatRoughnessNode = null;
690
839
 
@@ -717,13 +866,46 @@ class MaterialXNode {
717
866
  //
718
867
 
719
868
  material.colorNode = colorNode || color( 0.8, 0.8, 0.8 );
869
+ material.opacityNode = opacityNode || float( 1.0 );
720
870
  material.roughnessNode = roughnessNode || float( 0.2 );
721
871
  material.metalnessNode = metalnessNode || float( 0 );
872
+ material.specularIntensityNode = specularIntensityNode || float( 0.5 );
873
+ material.specularColorNode = specularColorNode || color( 1.0, 1.0, 1.0 );
874
+ material.iorNode = iorNode || float( 1.5 );
875
+ material.anisotropyNode = anisotropyNode || float( 0 );
876
+ material.anisotropyRotationNode = anisotropyRotationNode || float( 0 );
877
+ material.transmissionNode = transmissionNode || float( 0 );
878
+ material.transmissionColorNode = transmissionColorNode || color( 1.0, 1.0, 1.0 );
879
+ material.thinFilmThicknessNode = thinFilmThicknessNode || float( 0 );
880
+ material.thinFilmIorNode = thinFilmIorNode || float( 1.5 );
881
+ material.sheenNode = sheenNode || float( 0 );
882
+ material.sheenColorNode = sheenColorNode || color( 1.0, 1.0, 1.0 );
883
+ material.sheenRoughnessNode = sheenRoughnessNode || float( 0.5 );
722
884
  material.clearcoatNode = clearcoatNode || float( 0 );
723
885
  material.clearcoatRoughnessNode = clearcoatRoughnessNode || float( 0 );
724
886
  if ( normalNode ) material.normalNode = normalNode;
725
887
  if ( emissiveNode ) material.emissiveNode = emissiveNode;
726
888
 
889
+ // Auto-enable iridescence when thin film parameters are present
890
+ if ( thinFilmThicknessNode && thinFilmThicknessNode.value !== undefined && thinFilmThicknessNode.value > 0 ) {
891
+
892
+ material.iridescence = 1.0;
893
+
894
+ }
895
+
896
+ if ( opacityNode !== null ) {
897
+
898
+ material.transparent = true;
899
+
900
+ }
901
+
902
+ if ( transmissionNode !== null ) {
903
+
904
+ material.side = DoubleSide;
905
+ material.transparent = true;
906
+
907
+ }
908
+
727
909
  }
728
910
 
729
911
  /*setGltfPBR( material ) {
@@ -152,7 +152,19 @@ class TTFLoader extends Loader {
152
152
 
153
153
  } );
154
154
 
155
- glyphs[ String.fromCodePoint( glyph.unicode ) ] = token;
155
+ if ( Array.isArray( glyph.unicodes ) && glyph.unicodes.length > 0 ) {
156
+
157
+ glyph.unicodes.forEach( function ( unicode ) {
158
+
159
+ glyphs[ String.fromCodePoint( unicode ) ] = token;
160
+
161
+ } );
162
+
163
+ } else {
164
+
165
+ glyphs[ String.fromCodePoint( glyph.unicode ) ] = token;
166
+
167
+ }
156
168
 
157
169
  }
158
170
 
@@ -0,0 +1,219 @@
1
+ import {
2
+ FileLoader,
3
+ Loader
4
+ } from 'three';
5
+
6
+ import * as fflate from '../libs/fflate.module.js';
7
+ import { USDAParser } from './usd/USDAParser.js';
8
+ import { USDCParser } from './usd/USDCParser.js';
9
+
10
+ /**
11
+ * A loader for the USDZ format.
12
+ *
13
+ * USDZ files that use USDC internally are not yet supported, only USDA.
14
+ *
15
+ * ```js
16
+ * const loader = new USDZLoader();
17
+ * const model = await loader.loadAsync( 'saeukkang.usdz' );
18
+ * scene.add( model );
19
+ * ```
20
+ *
21
+ * @augments Loader
22
+ * @three_import import { USDLoader } from 'three/addons/loaders/USDLoader.js';
23
+ */
24
+ class USDLoader extends Loader {
25
+
26
+ /**
27
+ * Constructs a new USDZ loader.
28
+ *
29
+ * @param {LoadingManager} [manager] - The loading manager.
30
+ */
31
+ constructor( manager ) {
32
+
33
+ super( manager );
34
+
35
+ }
36
+
37
+ /**
38
+ * Starts loading from the given URL and passes the loaded USDZ asset
39
+ * to the `onLoad()` callback.
40
+ *
41
+ * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
42
+ * @param {function(Group)} onLoad - Executed when the loading process has been finished.
43
+ * @param {onProgressCallback} onProgress - Executed while the loading is in progress.
44
+ * @param {onErrorCallback} onError - Executed when errors occur.
45
+ */
46
+ load( url, onLoad, onProgress, onError ) {
47
+
48
+ const scope = this;
49
+
50
+ const loader = new FileLoader( scope.manager );
51
+ loader.setPath( scope.path );
52
+ loader.setResponseType( 'arraybuffer' );
53
+ loader.setRequestHeader( scope.requestHeader );
54
+ loader.setWithCredentials( scope.withCredentials );
55
+ loader.load( url, function ( text ) {
56
+
57
+ try {
58
+
59
+ onLoad( scope.parse( text ) );
60
+
61
+ } catch ( e ) {
62
+
63
+ if ( onError ) {
64
+
65
+ onError( e );
66
+
67
+ } else {
68
+
69
+ console.error( e );
70
+
71
+ }
72
+
73
+ scope.manager.itemError( url );
74
+
75
+ }
76
+
77
+ }, onProgress, onError );
78
+
79
+ }
80
+
81
+ /**
82
+ * Parses the given USDZ data and returns the resulting group.
83
+ *
84
+ * @param {ArrayBuffer|string} buffer - The raw USDZ data as an array buffer.
85
+ * @return {Group} The parsed asset as a group.
86
+ */
87
+ parse( buffer ) {
88
+
89
+ const usda = new USDAParser();
90
+ const usdc = new USDCParser();
91
+
92
+ function parseAssets( zip ) {
93
+
94
+ const data = {};
95
+ const loader = new FileLoader();
96
+ loader.setResponseType( 'arraybuffer' );
97
+
98
+ for ( const filename in zip ) {
99
+
100
+ if ( filename.endsWith( 'png' ) ) {
101
+
102
+ const blob = new Blob( [ zip[ filename ] ], { type: 'image/png' } );
103
+ data[ filename ] = URL.createObjectURL( blob );
104
+
105
+ }
106
+
107
+ if ( filename.endsWith( 'usd' ) || filename.endsWith( 'usda' ) || filename.endsWith( 'usdc' ) ) {
108
+
109
+ if ( isCrateFile( zip[ filename ] ) ) {
110
+
111
+ data[ filename ] = usdc.parse( zip[ filename ].buffer, data );
112
+
113
+ } else {
114
+
115
+ const text = fflate.strFromU8( zip[ filename ] );
116
+ data[ filename ] = usda.parseText( text );
117
+
118
+ }
119
+
120
+ }
121
+
122
+ }
123
+
124
+ return data;
125
+
126
+ }
127
+
128
+ function isCrateFile( buffer ) {
129
+
130
+ const crateHeader = new Uint8Array( [ 0x50, 0x58, 0x52, 0x2D, 0x55, 0x53, 0x44, 0x43 ] ); // PXR-USDC
131
+
132
+ if ( buffer.byteLength < crateHeader.length ) return false;
133
+
134
+ const view = new Uint8Array( buffer, 0, crateHeader.length );
135
+
136
+ for ( let i = 0; i < crateHeader.length; i ++ ) {
137
+
138
+ if ( view[ i ] !== crateHeader[ i ] ) return false;
139
+
140
+ }
141
+
142
+ return true;
143
+
144
+ }
145
+
146
+ function findUSD( zip ) {
147
+
148
+ if ( zip.length < 1 ) return undefined;
149
+
150
+ const firstFileName = Object.keys( zip )[ 0 ];
151
+ let isCrate = false;
152
+
153
+ // As per the USD specification, the first entry in the zip archive is used as the main file ("UsdStage").
154
+ // ASCII files can end in either .usda or .usd.
155
+ // See https://openusd.org/release/spec_usdz.html#layout
156
+ if ( firstFileName.endsWith( 'usda' ) ) return zip[ firstFileName ];
157
+
158
+ if ( firstFileName.endsWith( 'usdc' ) ) {
159
+
160
+ isCrate = true;
161
+
162
+ } else if ( firstFileName.endsWith( 'usd' ) ) {
163
+
164
+ // If this is not a crate file, we assume it is a plain USDA file.
165
+ if ( ! isCrateFile( zip[ firstFileName ] ) ) {
166
+
167
+ return zip[ firstFileName ];
168
+
169
+ } else {
170
+
171
+ isCrate = true;
172
+
173
+ }
174
+
175
+ }
176
+
177
+ if ( isCrate ) {
178
+
179
+ return zip[ firstFileName ];
180
+
181
+ }
182
+
183
+ }
184
+
185
+ // USDA
186
+
187
+ if ( typeof buffer === 'string' ) {
188
+
189
+ return usda.parse( buffer, {} );
190
+
191
+ }
192
+
193
+ // USDC
194
+
195
+ if ( isCrateFile( buffer ) ) {
196
+
197
+ return usdc.parse( buffer );
198
+
199
+ }
200
+
201
+ // USDZ
202
+
203
+ const zip = fflate.unzipSync( new Uint8Array( buffer ) );
204
+
205
+ const assets = parseAssets( zip );
206
+
207
+ // console.log( assets );
208
+
209
+ const file = findUSD( zip );
210
+
211
+ const text = fflate.strFromU8( file );
212
+
213
+ return usda.parse( text, assets );
214
+
215
+ }
216
+
217
+ }
218
+
219
+ export { USDLoader };