@plastic-software/three 0.181.3 → 0.183.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 (437) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -4
  3. package/build/three.cjs +11330 -10017
  4. package/build/three.core.js +10011 -9493
  5. package/build/three.core.min.js +2 -2
  6. package/build/three.module.js +1414 -631
  7. package/build/three.module.min.js +2 -2
  8. package/build/three.tsl.js +21 -13
  9. package/build/three.tsl.min.js +2 -2
  10. package/build/three.webgpu.js +8007 -5427
  11. package/build/three.webgpu.min.js +2 -2
  12. package/build/three.webgpu.nodes.js +8005 -5426
  13. package/build/three.webgpu.nodes.min.js +2 -2
  14. package/examples/jsm/Addons.js +0 -3
  15. package/examples/jsm/animation/CCDIKSolver.js +2 -2
  16. package/examples/jsm/controls/ArcballControls.js +3 -3
  17. package/examples/jsm/controls/MapControls.js +55 -1
  18. package/examples/jsm/controls/OrbitControls.js +109 -6
  19. package/examples/jsm/controls/TrackballControls.js +6 -6
  20. package/examples/jsm/csm/CSM.js +2 -1
  21. package/examples/jsm/effects/AnaglyphEffect.js +102 -7
  22. package/examples/jsm/environments/ColorEnvironment.js +59 -0
  23. package/examples/jsm/environments/RoomEnvironment.js +3 -0
  24. package/examples/jsm/exporters/EXRExporter.js +1 -1
  25. package/examples/jsm/exporters/GLTFExporter.js +131 -4
  26. package/examples/jsm/exporters/USDZExporter.js +22 -3
  27. package/examples/jsm/geometries/DecalGeometry.js +1 -1
  28. package/examples/jsm/helpers/AnimationPathHelper.js +302 -0
  29. package/examples/jsm/helpers/LightProbeHelperGPU.js +1 -1
  30. package/examples/jsm/helpers/TextureHelperGPU.js +1 -1
  31. package/examples/jsm/helpers/ViewHelper.js +67 -8
  32. package/examples/jsm/inspector/Inspector.js +74 -14
  33. package/examples/jsm/inspector/RendererInspector.js +12 -2
  34. package/examples/jsm/inspector/tabs/Console.js +41 -7
  35. package/examples/jsm/inspector/tabs/Parameters.js +18 -2
  36. package/examples/jsm/inspector/tabs/Performance.js +2 -2
  37. package/examples/jsm/inspector/tabs/Viewer.js +4 -4
  38. package/examples/jsm/inspector/ui/Profiler.js +1836 -31
  39. package/examples/jsm/inspector/ui/Style.js +973 -14
  40. package/examples/jsm/inspector/ui/Tab.js +188 -1
  41. package/examples/jsm/inspector/ui/Values.js +17 -1
  42. package/examples/jsm/libs/meshopt_decoder.module.js +6 -5
  43. package/examples/jsm/lines/LineMaterial.js +6 -0
  44. package/examples/jsm/loaders/3DMLoader.js +5 -4
  45. package/examples/jsm/loaders/3MFLoader.js +2 -2
  46. package/examples/jsm/loaders/AMFLoader.js +2 -2
  47. package/examples/jsm/loaders/ColladaLoader.js +24 -4026
  48. package/examples/jsm/loaders/DRACOLoader.js +5 -5
  49. package/examples/jsm/loaders/EXRLoader.js +5 -5
  50. package/examples/jsm/loaders/FBXLoader.js +2 -4
  51. package/examples/jsm/loaders/GCodeLoader.js +34 -8
  52. package/examples/jsm/loaders/GLTFLoader.js +122 -171
  53. package/examples/jsm/loaders/HDRLoader.js +0 -1
  54. package/examples/jsm/loaders/KMZLoader.js +5 -5
  55. package/examples/jsm/loaders/KTX2Loader.js +19 -3
  56. package/examples/jsm/loaders/LDrawLoader.js +2 -3
  57. package/examples/jsm/loaders/LWOLoader.js +7 -39
  58. package/examples/jsm/loaders/NRRDLoader.js +2 -2
  59. package/examples/jsm/loaders/PCDLoader.js +4 -2
  60. package/examples/jsm/loaders/SVGLoader.js +1 -1
  61. package/examples/jsm/loaders/TDSLoader.js +0 -2
  62. package/examples/jsm/loaders/TGALoader.js +0 -2
  63. package/examples/jsm/loaders/USDLoader.js +100 -40
  64. package/examples/jsm/loaders/UltraHDRLoader.js +285 -160
  65. package/examples/jsm/loaders/VOXLoader.js +660 -117
  66. package/examples/jsm/loaders/VRMLLoader.js +79 -2
  67. package/examples/jsm/loaders/VTKLoader.js +37 -24
  68. package/examples/jsm/loaders/collada/ColladaComposer.js +2950 -0
  69. package/examples/jsm/loaders/collada/ColladaParser.js +1962 -0
  70. package/examples/jsm/loaders/usd/USDAParser.js +447 -366
  71. package/examples/jsm/loaders/usd/USDCParser.js +1841 -6
  72. package/examples/jsm/loaders/usd/USDComposer.js +4041 -0
  73. package/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +2 -2
  74. package/examples/jsm/materials/WoodNodeMaterial.js +11 -11
  75. package/examples/jsm/math/Octree.js +131 -1
  76. package/examples/jsm/misc/Volume.js +0 -1
  77. package/examples/jsm/misc/VolumeSlice.js +0 -1
  78. package/examples/jsm/objects/LensflareMesh.js +1 -1
  79. package/examples/jsm/objects/Sky.js +76 -4
  80. package/examples/jsm/objects/SkyMesh.js +127 -10
  81. package/examples/jsm/objects/Water.js +4 -3
  82. package/examples/jsm/objects/Water2.js +5 -3
  83. package/examples/jsm/objects/WaterMesh.js +5 -7
  84. package/examples/jsm/physics/AmmoPhysics.js +12 -7
  85. package/examples/jsm/physics/JoltPhysics.js +10 -6
  86. package/examples/jsm/physics/RapierPhysics.js +9 -5
  87. package/examples/jsm/postprocessing/EffectComposer.js +7 -5
  88. package/examples/jsm/postprocessing/OutputPass.js +9 -0
  89. package/examples/jsm/postprocessing/RenderPass.js +10 -0
  90. package/examples/jsm/postprocessing/RenderTransitionPass.js +1 -1
  91. package/examples/jsm/postprocessing/UnrealBloomPass.js +48 -18
  92. package/examples/jsm/renderers/CSS3DRenderer.js +1 -1
  93. package/examples/jsm/renderers/Projector.js +268 -30
  94. package/examples/jsm/renderers/SVGRenderer.js +193 -60
  95. package/examples/jsm/shaders/GTAOShader.js +19 -6
  96. package/examples/jsm/shaders/HalftoneShader.js +12 -1
  97. package/examples/jsm/shaders/PoissonDenoiseShader.js +6 -2
  98. package/examples/jsm/shaders/SAOShader.js +17 -4
  99. package/examples/jsm/shaders/SSAOShader.js +11 -1
  100. package/examples/jsm/shaders/SSRShader.js +6 -5
  101. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +2 -4
  102. package/examples/jsm/shaders/VignetteShader.js +1 -1
  103. package/examples/jsm/transpiler/AST.js +44 -0
  104. package/examples/jsm/transpiler/GLSLDecoder.js +61 -4
  105. package/examples/jsm/transpiler/ShaderToyDecoder.js +2 -0
  106. package/examples/jsm/transpiler/TSLEncoder.js +46 -3
  107. package/examples/jsm/transpiler/TranspilerUtils.js +3 -3
  108. package/examples/jsm/transpiler/WGSLEncoder.js +27 -0
  109. package/examples/jsm/tsl/display/AfterImageNode.js +1 -1
  110. package/examples/jsm/tsl/display/AnaglyphPassNode.js +458 -16
  111. package/examples/jsm/tsl/display/AnamorphicNode.js +1 -1
  112. package/examples/jsm/tsl/display/BilateralBlurNode.js +364 -0
  113. package/examples/jsm/tsl/display/BloomNode.js +16 -6
  114. package/examples/jsm/tsl/display/CRT.js +150 -0
  115. package/examples/jsm/tsl/display/DenoiseNode.js +1 -1
  116. package/examples/jsm/tsl/display/DepthOfFieldNode.js +1 -1
  117. package/examples/jsm/tsl/display/DotScreenNode.js +1 -1
  118. package/examples/jsm/tsl/display/FXAANode.js +2 -2
  119. package/examples/jsm/tsl/display/GTAONode.js +5 -4
  120. package/examples/jsm/tsl/display/GaussianBlurNode.js +11 -2
  121. package/examples/jsm/tsl/display/GodraysNode.js +624 -0
  122. package/examples/jsm/tsl/display/LensflareNode.js +1 -1
  123. package/examples/jsm/tsl/display/Lut3DNode.js +1 -1
  124. package/examples/jsm/tsl/display/OutlineNode.js +3 -3
  125. package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +2 -2
  126. package/examples/jsm/tsl/display/PixelationPassNode.js +7 -6
  127. package/examples/jsm/tsl/display/RGBShiftNode.js +2 -2
  128. package/examples/jsm/tsl/display/RetroPassNode.js +263 -0
  129. package/examples/jsm/tsl/display/SMAANode.js +2 -2
  130. package/examples/jsm/tsl/display/SSAAPassNode.js +2 -2
  131. package/examples/jsm/tsl/display/SSGINode.js +8 -20
  132. package/examples/jsm/tsl/display/SSRNode.js +8 -8
  133. package/examples/jsm/tsl/display/SSSNode.js +6 -4
  134. package/examples/jsm/tsl/display/Shape.js +29 -0
  135. package/examples/jsm/tsl/display/SobelOperatorNode.js +2 -2
  136. package/examples/jsm/tsl/display/StereoCompositePassNode.js +8 -1
  137. package/examples/jsm/tsl/display/StereoPassNode.js +1 -2
  138. package/examples/jsm/tsl/display/TRAANode.js +273 -125
  139. package/examples/jsm/tsl/display/TransitionNode.js +1 -1
  140. package/examples/jsm/tsl/display/depthAwareBlend.js +80 -0
  141. package/examples/jsm/tsl/display/radialBlur.js +68 -0
  142. package/examples/jsm/tsl/math/Bayer.js +40 -1
  143. package/examples/jsm/utils/LDrawUtils.js +1 -1
  144. package/examples/jsm/utils/ShadowMapViewer.js +24 -10
  145. package/examples/jsm/utils/ShadowMapViewerGPU.js +1 -1
  146. package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
  147. package/package.json +20 -26
  148. package/src/Three.Core.js +2 -1
  149. package/src/Three.TSL.js +19 -11
  150. package/src/Three.WebGPU.Nodes.js +2 -0
  151. package/src/Three.WebGPU.js +3 -0
  152. package/src/Three.js +1 -0
  153. package/src/animation/AnimationAction.js +1 -1
  154. package/src/animation/AnimationClip.js +1 -1
  155. package/src/animation/AnimationMixer.js +6 -0
  156. package/src/animation/AnimationUtils.js +1 -12
  157. package/src/animation/KeyframeTrack.js +47 -8
  158. package/src/animation/PropertyMixer.js +4 -4
  159. package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
  160. package/src/animation/tracks/ColorKeyframeTrack.js +1 -1
  161. package/src/animation/tracks/NumberKeyframeTrack.js +1 -1
  162. package/src/animation/tracks/QuaternionKeyframeTrack.js +1 -1
  163. package/src/animation/tracks/StringKeyframeTrack.js +1 -1
  164. package/src/animation/tracks/VectorKeyframeTrack.js +1 -1
  165. package/src/audio/Audio.js +1 -1
  166. package/src/audio/AudioListener.js +5 -3
  167. package/src/cameras/Camera.js +32 -2
  168. package/src/cameras/CubeCamera.js +20 -0
  169. package/src/constants.js +90 -5
  170. package/src/core/BufferGeometry.js +14 -2
  171. package/src/core/Clock.js +7 -0
  172. package/src/core/Object3D.js +56 -4
  173. package/src/core/Raycaster.js +2 -2
  174. package/src/core/RenderTarget.js +3 -4
  175. package/src/extras/PMREMGenerator.js +7 -18
  176. package/src/extras/TextureUtils.js +5 -1
  177. package/src/geometries/ExtrudeGeometry.js +2 -2
  178. package/src/geometries/PolyhedronGeometry.js +1 -1
  179. package/src/geometries/TorusGeometry.js +8 -3
  180. package/src/helpers/CameraHelper.js +3 -0
  181. package/src/helpers/DirectionalLightHelper.js +4 -1
  182. package/src/helpers/HemisphereLightHelper.js +3 -0
  183. package/src/helpers/PointLightHelper.js +1 -25
  184. package/src/helpers/SpotLightHelper.js +3 -0
  185. package/src/lights/DirectionalLight.js +13 -0
  186. package/src/lights/HemisphereLight.js +10 -0
  187. package/src/lights/Light.js +1 -11
  188. package/src/lights/LightProbe.js +0 -15
  189. package/src/lights/LightShadow.js +15 -6
  190. package/src/lights/PointLight.js +15 -0
  191. package/src/lights/PointLightShadow.js +0 -86
  192. package/src/lights/SpotLight.js +22 -1
  193. package/src/lights/webgpu/IESSpotLight.js +2 -1
  194. package/src/loaders/Cache.js +28 -0
  195. package/src/loaders/FileLoader.js +1 -1
  196. package/src/loaders/ImageBitmapLoader.js +8 -3
  197. package/src/loaders/Loader.js +6 -0
  198. package/src/loaders/MaterialLoader.js +2 -1
  199. package/src/loaders/ObjectLoader.js +21 -2
  200. package/src/loaders/nodes/NodeLoader.js +2 -2
  201. package/src/materials/Material.js +2 -0
  202. package/src/materials/MeshLambertMaterial.js +9 -0
  203. package/src/materials/MeshPhongMaterial.js +9 -0
  204. package/src/materials/ShaderMaterial.js +20 -1
  205. package/src/materials/nodes/Line2NodeMaterial.js +7 -7
  206. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +5 -2
  207. package/src/materials/nodes/MeshStandardNodeMaterial.js +5 -4
  208. package/src/materials/nodes/NodeMaterial.js +72 -25
  209. package/src/materials/nodes/manager/NodeMaterialObserver.js +10 -4
  210. package/src/math/Line3.js +3 -5
  211. package/src/math/MathUtils.js +10 -10
  212. package/src/math/Matrix4.js +74 -65
  213. package/src/math/Quaternion.js +3 -29
  214. package/src/math/Sphere.js +1 -1
  215. package/src/math/Vector3.js +3 -5
  216. package/src/math/interpolants/BezierInterpolant.js +108 -0
  217. package/src/nodes/Nodes.js +87 -68
  218. package/src/nodes/TSL.js +6 -6
  219. package/src/nodes/accessors/Arrays.js +1 -1
  220. package/src/nodes/accessors/BatchNode.js +10 -10
  221. package/src/nodes/accessors/Bitangent.js +5 -5
  222. package/src/nodes/accessors/BufferAttributeNode.js +98 -12
  223. package/src/nodes/accessors/BufferNode.js +29 -2
  224. package/src/nodes/accessors/Camera.js +149 -28
  225. package/src/nodes/accessors/ClippingNode.js +4 -4
  226. package/src/nodes/accessors/CubeTextureNode.js +20 -1
  227. package/src/nodes/accessors/InstanceNode.js +148 -43
  228. package/src/nodes/accessors/MaterialNode.js +9 -1
  229. package/src/nodes/accessors/MaterialReferenceNode.js +1 -2
  230. package/src/nodes/accessors/ModelNode.js +1 -1
  231. package/src/nodes/accessors/Normal.js +11 -11
  232. package/src/nodes/accessors/Position.js +34 -2
  233. package/src/nodes/accessors/ReferenceBaseNode.js +4 -4
  234. package/src/nodes/accessors/ReferenceNode.js +4 -4
  235. package/src/nodes/accessors/RendererReferenceNode.js +1 -2
  236. package/src/nodes/accessors/SceneProperties.js +53 -0
  237. package/src/nodes/accessors/SkinningNode.js +27 -26
  238. package/src/nodes/accessors/StorageBufferNode.js +4 -21
  239. package/src/nodes/accessors/StorageTextureNode.js +37 -1
  240. package/src/nodes/accessors/Tangent.js +4 -14
  241. package/src/nodes/accessors/Texture3DNode.js +32 -35
  242. package/src/nodes/accessors/TextureNode.js +58 -22
  243. package/src/nodes/accessors/UniformArrayNode.js +4 -2
  244. package/src/nodes/accessors/UserDataNode.js +1 -2
  245. package/src/nodes/accessors/VertexColorNode.js +1 -2
  246. package/src/nodes/code/FunctionNode.js +1 -2
  247. package/src/nodes/core/ArrayNode.js +20 -1
  248. package/src/nodes/core/AssignNode.js +2 -2
  249. package/src/nodes/core/AttributeNode.js +2 -2
  250. package/src/nodes/core/ContextNode.js +103 -4
  251. package/src/nodes/core/MRTNode.js +48 -2
  252. package/src/nodes/core/Node.js +29 -3
  253. package/src/nodes/core/NodeBuilder.js +170 -53
  254. package/src/nodes/core/NodeError.js +28 -0
  255. package/src/nodes/core/NodeFrame.js +12 -4
  256. package/src/nodes/core/NodeUtils.js +10 -8
  257. package/src/nodes/core/OutputStructNode.js +12 -10
  258. package/src/nodes/core/ParameterNode.js +3 -3
  259. package/src/nodes/core/PropertyNode.js +19 -3
  260. package/src/nodes/core/StackNode.js +65 -16
  261. package/src/nodes/core/StackTrace.js +139 -0
  262. package/src/nodes/core/StructNode.js +16 -2
  263. package/src/nodes/core/StructTypeNode.js +11 -17
  264. package/src/nodes/core/SubBuildNode.js +1 -1
  265. package/src/nodes/core/UniformNode.js +21 -5
  266. package/src/nodes/core/VarNode.js +47 -22
  267. package/src/nodes/core/VaryingNode.js +1 -18
  268. package/src/nodes/display/BlendModes.js +0 -64
  269. package/src/nodes/display/ColorAdjustment.js +17 -0
  270. package/src/nodes/display/ColorSpaceNode.js +3 -3
  271. package/src/nodes/display/NormalMapNode.js +39 -4
  272. package/src/nodes/display/PassNode.js +98 -9
  273. package/src/nodes/display/RenderOutputNode.js +3 -3
  274. package/src/nodes/display/ScreenNode.js +3 -1
  275. package/src/nodes/display/ToneMappingNode.js +1 -1
  276. package/src/nodes/display/ToonOutlinePassNode.js +2 -2
  277. package/src/nodes/display/ViewportDepthNode.js +52 -4
  278. package/src/nodes/display/ViewportTextureNode.js +21 -4
  279. package/src/nodes/fog/Fog.js +18 -35
  280. package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +3 -3
  281. package/src/nodes/functions/BSDF/DFGLUT.js +56 -0
  282. package/src/nodes/functions/BSDF/EnvironmentBRDF.js +2 -2
  283. package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +1 -1
  284. package/src/nodes/functions/PhysicalLightingModel.js +126 -45
  285. package/src/nodes/geometry/RangeNode.js +4 -2
  286. package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -2
  287. package/src/nodes/gpgpu/ComputeNode.js +5 -4
  288. package/src/nodes/gpgpu/SubgroupFunctionNode.js +1 -1
  289. package/src/nodes/gpgpu/WorkgroupInfoNode.js +4 -4
  290. package/src/nodes/lighting/AnalyticLightNode.js +53 -0
  291. package/src/nodes/lighting/EnvironmentNode.js +28 -3
  292. package/src/nodes/lighting/LightsNode.js +2 -2
  293. package/src/nodes/lighting/PointShadowNode.js +162 -149
  294. package/src/nodes/lighting/ShadowFilterNode.js +53 -65
  295. package/src/nodes/lighting/ShadowNode.js +97 -41
  296. package/src/nodes/math/BitcountNode.js +433 -0
  297. package/src/nodes/math/ConditionalNode.js +2 -2
  298. package/src/nodes/math/MathNode.js +3 -40
  299. package/src/nodes/math/OperatorNode.js +2 -1
  300. package/src/nodes/math/PackFloatNode.js +98 -0
  301. package/src/nodes/math/UnpackFloatNode.js +96 -0
  302. package/src/nodes/pmrem/PMREMNode.js +1 -1
  303. package/src/nodes/pmrem/PMREMUtils.js +9 -15
  304. package/src/nodes/tsl/TSLCore.js +17 -14
  305. package/src/nodes/utils/ArrayElementNode.js +13 -0
  306. package/src/nodes/utils/DebugNode.js +11 -11
  307. package/src/nodes/utils/EventNode.js +1 -2
  308. package/src/nodes/utils/JoinNode.js +2 -2
  309. package/src/nodes/utils/LoopNode.js +1 -1
  310. package/src/nodes/utils/MemberNode.js +1 -1
  311. package/src/nodes/utils/Packing.js +13 -1
  312. package/src/nodes/utils/PostProcessingUtils.js +33 -1
  313. package/src/nodes/utils/RTTNode.js +1 -1
  314. package/src/nodes/utils/ReflectorNode.js +3 -4
  315. package/src/nodes/utils/SampleNode.js +1 -1
  316. package/src/nodes/utils/SpriteSheetUV.js +35 -0
  317. package/src/nodes/utils/UVUtils.js +28 -0
  318. package/src/objects/BatchedMesh.js +27 -14
  319. package/src/objects/InstancedMesh.js +11 -0
  320. package/src/objects/Line.js +1 -1
  321. package/src/objects/Mesh.js +1 -1
  322. package/src/objects/Points.js +1 -1
  323. package/src/objects/Skeleton.js +9 -0
  324. package/src/renderers/WebGLRenderer.js +178 -92
  325. package/src/renderers/common/Backend.js +29 -0
  326. package/src/renderers/common/Background.js +24 -11
  327. package/src/renderers/common/BindGroup.js +1 -9
  328. package/src/renderers/common/Binding.js +11 -0
  329. package/src/renderers/common/Bindings.js +27 -12
  330. package/src/renderers/common/BlendMode.js +143 -0
  331. package/src/renderers/common/Buffer.js +40 -0
  332. package/src/renderers/common/BundleGroup.js +1 -1
  333. package/src/renderers/common/ChainMap.js +30 -6
  334. package/src/renderers/common/CubeRenderTarget.js +50 -6
  335. package/src/renderers/common/Geometries.js +29 -3
  336. package/src/renderers/common/Lighting.js +5 -21
  337. package/src/renderers/common/Pipelines.js +4 -4
  338. package/src/renderers/common/PostProcessing.js +8 -206
  339. package/src/renderers/common/RenderBundles.js +2 -1
  340. package/src/renderers/common/RenderContext.js +16 -0
  341. package/src/renderers/common/RenderContexts.js +33 -49
  342. package/src/renderers/common/RenderLists.js +2 -1
  343. package/src/renderers/common/RenderObject.js +15 -3
  344. package/src/renderers/common/RenderObjectPipeline.js +40 -0
  345. package/src/renderers/common/RenderObjects.js +18 -2
  346. package/src/renderers/common/RenderPipeline.js +203 -17
  347. package/src/renderers/common/Renderer.js +257 -72
  348. package/src/renderers/common/Sampler.js +4 -4
  349. package/src/renderers/common/StorageBuffer.js +13 -1
  350. package/src/renderers/common/Textures.js +17 -1
  351. package/src/renderers/common/TimestampQueryPool.js +5 -3
  352. package/src/renderers/common/Uniform.js +8 -0
  353. package/src/renderers/common/UniformsGroup.js +61 -0
  354. package/src/renderers/common/XRManager.js +3 -2
  355. package/src/renderers/common/extras/PMREMGenerator.js +2 -8
  356. package/src/renderers/common/nodes/NodeBuilderState.js +1 -1
  357. package/src/renderers/common/nodes/{Nodes.js → NodeManager.js} +18 -6
  358. package/src/renderers/common/nodes/NodeStorageBuffer.js +13 -2
  359. package/src/renderers/common/nodes/NodeUniformBuffer.js +52 -0
  360. package/src/renderers/shaders/DFGLUTData.js +19 -34
  361. package/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js +2 -2
  362. package/src/renderers/shaders/ShaderChunk/color_fragment.glsl.js +1 -5
  363. package/src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl.js +1 -5
  364. package/src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js +1 -5
  365. package/src/renderers/shaders/ShaderChunk/color_vertex.glsl.js +8 -10
  366. package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +7 -11
  367. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +5 -2
  368. package/src/renderers/shaders/ShaderChunk/lights_fragment_end.glsl.js +6 -0
  369. package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +6 -2
  370. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +8 -4
  371. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +112 -51
  372. package/src/renderers/shaders/ShaderChunk/packing.glsl.js +20 -4
  373. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +225 -186
  374. package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +1 -1
  375. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
  376. package/src/renderers/shaders/ShaderChunk.js +3 -3
  377. package/src/renderers/shaders/ShaderLib/depth.glsl.js +3 -0
  378. package/src/renderers/shaders/ShaderLib/{distanceRGBA.glsl.js → distance.glsl.js} +1 -2
  379. package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +2 -1
  380. package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +1 -2
  381. package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +2 -1
  382. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -9
  383. package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +0 -1
  384. package/src/renderers/shaders/ShaderLib/shadow.glsl.js +1 -1
  385. package/src/renderers/shaders/ShaderLib/vsm.glsl.js +4 -6
  386. package/src/renderers/shaders/ShaderLib.js +7 -5
  387. package/src/renderers/shaders/UniformsLib.js +0 -3
  388. package/src/renderers/webgl/WebGLBackground.js +2 -2
  389. package/src/renderers/webgl/WebGLBindingStates.js +99 -27
  390. package/src/renderers/webgl/WebGLCapabilities.js +3 -4
  391. package/src/renderers/webgl/WebGLEnvironments.js +228 -0
  392. package/src/renderers/webgl/WebGLGeometries.js +10 -7
  393. package/src/renderers/webgl/WebGLLights.js +18 -1
  394. package/src/renderers/webgl/WebGLMaterials.js +12 -0
  395. package/src/renderers/webgl/WebGLObjects.js +3 -1
  396. package/src/renderers/webgl/WebGLOutput.js +267 -0
  397. package/src/renderers/webgl/WebGLProgram.js +45 -109
  398. package/src/renderers/webgl/WebGLPrograms.js +45 -49
  399. package/src/renderers/webgl/WebGLRenderLists.js +15 -0
  400. package/src/renderers/webgl/WebGLShadowMap.js +188 -24
  401. package/src/renderers/webgl/WebGLState.js +32 -37
  402. package/src/renderers/webgl/WebGLTextures.js +89 -28
  403. package/src/renderers/webgl/WebGLUniforms.js +40 -3
  404. package/src/renderers/webgl/WebGLUtils.js +6 -2
  405. package/src/renderers/webgl-fallback/WebGLBackend.js +148 -18
  406. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +156 -35
  407. package/src/renderers/webgl-fallback/utils/WebGLState.js +181 -5
  408. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +5 -3
  409. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +9 -9
  410. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +6 -2
  411. package/src/renderers/webgpu/WebGPUBackend.js +119 -13
  412. package/src/renderers/webgpu/WebGPURenderer.js +2 -1
  413. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +322 -68
  414. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +4 -17
  415. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +357 -200
  416. package/src/renderers/webgpu/utils/WebGPUConstants.js +2 -0
  417. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +61 -23
  418. package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +152 -200
  419. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +65 -42
  420. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +7 -7
  421. package/src/renderers/webgpu/utils/WebGPUUtils.js +17 -11
  422. package/src/renderers/webxr/WebXRManager.js +2 -2
  423. package/src/textures/CubeDepthTexture.js +76 -0
  424. package/src/textures/Source.js +1 -1
  425. package/src/textures/Texture.js +3 -3
  426. package/src/utils.js +258 -3
  427. package/examples/jsm/materials/MeshGouraudMaterial.js +0 -434
  428. package/examples/jsm/materials/MeshPostProcessingMaterial.js +0 -167
  429. package/examples/jsm/shaders/GodRaysShader.js +0 -333
  430. package/src/nodes/accessors/SceneNode.js +0 -145
  431. package/src/nodes/code/ScriptableNode.js +0 -726
  432. package/src/nodes/code/ScriptableValueNode.js +0 -253
  433. package/src/nodes/display/PosterizeNode.js +0 -65
  434. package/src/nodes/functions/BSDF/DFGApprox.js +0 -71
  435. package/src/nodes/utils/SpriteSheetUVNode.js +0 -90
  436. package/src/renderers/webgl/WebGLCubeMaps.js +0 -99
  437. package/src/renderers/webgl/WebGLCubeUVMaps.js +0 -134
@@ -1,23 +1,15 @@
1
- import {
2
- BufferAttribute,
3
- BufferGeometry,
4
- ClampToEdgeWrapping,
5
- Group,
6
- NoColorSpace,
7
- Mesh,
8
- MeshPhysicalMaterial,
9
- MirroredRepeatWrapping,
10
- RepeatWrapping,
11
- SRGBColorSpace,
12
- TextureLoader,
13
- Object3D,
14
- Vector2
15
- } from 'three';
1
+ // Pre-compiled regex patterns for performance
2
+ const DEF_MATCH_REGEX = /^def\s+(?:(\w+)\s+)?"?([^"]+)"?$/;
3
+ const VARIANT_STRING_REGEX = /^string\s+(\w+)$/;
4
+ const ATTR_MATCH_REGEX = /^(?:uniform\s+)?(\w+(?:\[\])?)\s+(.+)$/;
16
5
 
17
6
  class USDAParser {
18
7
 
19
8
  parseText( text ) {
20
9
 
10
+ // Preprocess: strip comments and normalize multiline values
11
+ text = this._preprocess( text );
12
+
21
13
  const root = {};
22
14
 
23
15
  const lines = text.split( '\n' );
@@ -27,18 +19,22 @@ class USDAParser {
27
19
 
28
20
  const stack = [ root ];
29
21
 
30
- // Parse USDA file
31
-
32
22
  for ( const line of lines ) {
33
23
 
34
- // console.log( line );
35
-
36
24
  if ( line.includes( '=' ) ) {
37
25
 
38
- const assignment = line.split( '=' );
26
+ // Find the first '=' that's not inside quotes
27
+ const eqIdx = this._findAssignmentOperator( line );
28
+
29
+ if ( eqIdx === - 1 ) {
30
+
31
+ string = line.trim();
32
+ continue;
39
33
 
40
- const lhs = assignment[ 0 ].trim();
41
- const rhs = assignment[ 1 ].trim();
34
+ }
35
+
36
+ const lhs = line.slice( 0, eqIdx ).trim();
37
+ const rhs = line.slice( eqIdx + 1 ).trim();
42
38
 
43
39
  if ( rhs.endsWith( '{' ) ) {
44
40
 
@@ -66,6 +62,20 @@ class USDAParser {
66
62
 
67
63
  }
68
64
 
65
+ } else if ( line.includes( ':' ) && ! line.includes( '=' ) ) {
66
+
67
+ // Handle dictionary entries like "0: [(...)...]" for timeSamples
68
+ const colonIdx = line.indexOf( ':' );
69
+ const key = line.slice( 0, colonIdx ).trim();
70
+ const value = line.slice( colonIdx + 1 ).trim();
71
+
72
+ // Only process if key looks like a number (timeSamples frame)
73
+ if ( /^[\d.]+$/.test( key ) ) {
74
+
75
+ target[ key ] = value;
76
+
77
+ }
78
+
69
79
  } else if ( line.endsWith( '{' ) ) {
70
80
 
71
81
  const group = target[ string ] || {};
@@ -98,7 +108,7 @@ class USDAParser {
98
108
 
99
109
  target = stack[ stack.length - 1 ];
100
110
 
101
- } else {
111
+ } else if ( line.trim() ) {
102
112
 
103
113
  string = line.trim();
104
114
 
@@ -110,629 +120,700 @@ class USDAParser {
110
120
 
111
121
  }
112
122
 
113
- parse( text, assets ) {
123
+ _preprocess( text ) {
114
124
 
115
- const root = this.parseText( text );
125
+ // Remove block comments /* ... */
126
+ text = this._stripBlockComments( text );
116
127
 
117
- // Build scene graph
128
+ // Collapse triple-quoted strings into single lines
129
+ text = this._collapseTripleQuotedStrings( text );
118
130
 
119
- function findMeshGeometry( data ) {
120
-
121
- if ( ! data ) return undefined;
131
+ // Remove line comments # ... (but preserve #usda header)
132
+ // Only remove # comments that aren't at the start of a line or after whitespace
133
+ const lines = text.split( '\n' );
134
+ const processed = [];
122
135
 
123
- if ( 'prepend references' in data ) {
136
+ let inMultilineValue = false;
137
+ let bracketDepth = 0;
138
+ let parenDepth = 0;
139
+ let accumulated = '';
124
140
 
125
- const reference = data[ 'prepend references' ];
126
- const parts = reference.split( '@' );
127
- const path = parts[ 1 ].replace( /^.\//, '' );
128
- const id = parts[ 2 ].replace( /^<\//, '' ).replace( />$/, '' );
141
+ for ( let i = 0; i < lines.length; i ++ ) {
129
142
 
130
- return findGeometry( assets[ path ], id );
143
+ let line = lines[ i ];
131
144
 
132
- }
145
+ // Strip inline comments (but not inside strings)
146
+ line = this._stripInlineComment( line );
133
147
 
134
- return findGeometry( data );
148
+ // Track bracket/paren depth for multiline values
149
+ const trimmed = line.trim();
135
150
 
136
- }
151
+ if ( inMultilineValue ) {
137
152
 
138
- function findGeometry( data, id ) {
153
+ // Continue accumulating multiline value
154
+ accumulated += ' ' + trimmed;
139
155
 
140
- if ( ! data ) return undefined;
156
+ // Update depths
157
+ for ( const ch of trimmed ) {
141
158
 
142
- if ( id !== undefined ) {
159
+ if ( ch === '[' ) bracketDepth ++;
160
+ else if ( ch === ']' ) bracketDepth --;
161
+ else if ( ch === '(' && bracketDepth > 0 ) parenDepth ++;
162
+ else if ( ch === ')' && bracketDepth > 0 ) parenDepth --;
143
163
 
144
- const def = `def Mesh "${id}"`;
164
+ }
145
165
 
146
- if ( def in data ) {
166
+ // Check if multiline value is complete
167
+ if ( bracketDepth === 0 && parenDepth === 0 ) {
147
168
 
148
- return data[ def ];
169
+ processed.push( accumulated );
170
+ accumulated = '';
171
+ inMultilineValue = false;
149
172
 
150
173
  }
151
174
 
152
- }
153
-
154
- for ( const name in data ) {
175
+ } else {
155
176
 
156
- const object = data[ name ];
177
+ // Check if this line starts a multiline array value
178
+ // Look for patterns like "attr = [" or "attr = @path@[" without closing ]
179
+ if ( trimmed.includes( '=' ) ) {
157
180
 
158
- if ( name.startsWith( 'def Mesh' ) ) {
181
+ const eqIdx = this._findAssignmentOperator( trimmed );
159
182
 
160
- return object;
183
+ if ( eqIdx !== - 1 ) {
161
184
 
162
- }
185
+ const rhs = trimmed.slice( eqIdx + 1 ).trim();
163
186
 
187
+ // Count brackets in the value part
188
+ let openBrackets = 0;
189
+ let closeBrackets = 0;
164
190
 
165
- if ( typeof object === 'object' ) {
191
+ for ( const ch of rhs ) {
166
192
 
167
- const geometry = findGeometry( object );
193
+ if ( ch === '[' ) openBrackets ++;
194
+ else if ( ch === ']' ) closeBrackets ++;
168
195
 
169
- if ( geometry ) return geometry;
196
+ }
170
197
 
171
- }
198
+ if ( openBrackets > closeBrackets ) {
172
199
 
173
- }
200
+ // Multiline array detected
201
+ inMultilineValue = true;
202
+ bracketDepth = openBrackets - closeBrackets;
203
+ parenDepth = 0;
204
+ accumulated = trimmed;
205
+ continue;
174
206
 
175
- }
207
+ }
176
208
 
177
- function buildGeometry( data ) {
209
+ }
178
210
 
179
- if ( ! data ) return undefined;
211
+ }
180
212
 
181
- const geometry = new BufferGeometry();
182
- let indices = null;
183
- let counts = null;
184
- let uvs = null;
213
+ processed.push( trimmed );
185
214
 
186
- let positionsLength = - 1;
215
+ }
187
216
 
188
- // index
217
+ }
189
218
 
190
- if ( 'int[] faceVertexIndices' in data ) {
219
+ return processed.join( '\n' );
191
220
 
192
- indices = JSON.parse( data[ 'int[] faceVertexIndices' ] );
221
+ }
193
222
 
194
- }
223
+ _stripBlockComments( text ) {
195
224
 
196
- // face count
225
+ // Iteratively remove /* ... */ comments without regex backtracking
226
+ let result = '';
227
+ let i = 0;
197
228
 
198
- if ( 'int[] faceVertexCounts' in data ) {
229
+ while ( i < text.length ) {
199
230
 
200
- counts = JSON.parse( data[ 'int[] faceVertexCounts' ] );
201
- indices = toTriangleIndices( indices, counts );
231
+ // Check for block comment start
232
+ if ( text[ i ] === '/' && i + 1 < text.length && text[ i + 1 ] === '*' ) {
202
233
 
203
- }
234
+ // Find the closing */
235
+ let j = i + 2;
204
236
 
205
- // position
237
+ while ( j < text.length ) {
206
238
 
207
- if ( 'point3f[] points' in data ) {
239
+ if ( text[ j ] === '*' && j + 1 < text.length && text[ j + 1 ] === '/' ) {
208
240
 
209
- const positions = JSON.parse( data[ 'point3f[] points' ].replace( /[()]*/g, '' ) );
210
- positionsLength = positions.length;
211
- let attribute = new BufferAttribute( new Float32Array( positions ), 3 );
241
+ // Found closing, skip past it
242
+ j += 2;
243
+ break;
212
244
 
213
- if ( indices !== null ) attribute = toFlatBufferAttribute( attribute, indices );
245
+ }
214
246
 
215
- geometry.setAttribute( 'position', attribute );
247
+ j ++;
216
248
 
217
- }
249
+ }
218
250
 
219
- // uv
251
+ // Move past the comment (or to end if unclosed)
252
+ i = j;
220
253
 
221
- if ( 'float2[] primvars:st' in data ) {
254
+ } else {
222
255
 
223
- data[ 'texCoord2f[] primvars:st' ] = data[ 'float2[] primvars:st' ];
256
+ result += text[ i ];
257
+ i ++;
224
258
 
225
259
  }
226
260
 
227
- if ( 'texCoord2f[] primvars:st' in data ) {
261
+ }
228
262
 
229
- uvs = JSON.parse( data[ 'texCoord2f[] primvars:st' ].replace( /[()]*/g, '' ) );
230
- let attribute = new BufferAttribute( new Float32Array( uvs ), 2 );
263
+ return result;
231
264
 
232
- if ( indices !== null ) attribute = toFlatBufferAttribute( attribute, indices );
265
+ }
233
266
 
234
- geometry.setAttribute( 'uv', attribute );
267
+ _collapseTripleQuotedStrings( text ) {
235
268
 
236
- }
269
+ let result = '';
270
+ let i = 0;
237
271
 
238
- if ( 'int[] primvars:st:indices' in data && uvs !== null ) {
272
+ while ( i < text.length ) {
239
273
 
240
- // custom uv index, overwrite uvs with new data
274
+ if ( i + 2 < text.length ) {
241
275
 
242
- const attribute = new BufferAttribute( new Float32Array( uvs ), 2 );
243
- let indices = JSON.parse( data[ 'int[] primvars:st:indices' ] );
244
- indices = toTriangleIndices( indices, counts );
245
- geometry.setAttribute( 'uv', toFlatBufferAttribute( attribute, indices ) );
276
+ const triple = text.slice( i, i + 3 );
246
277
 
247
- }
278
+ if ( triple === '\'\'\'' || triple === '"""' ) {
248
279
 
249
- // normal
280
+ const quoteChar = triple;
281
+ result += quoteChar;
282
+ i += 3;
250
283
 
251
- if ( 'normal3f[] normals' in data ) {
284
+ while ( i < text.length ) {
252
285
 
253
- const normals = JSON.parse( data[ 'normal3f[] normals' ].replace( /[()]*/g, '' ) );
254
- let attribute = new BufferAttribute( new Float32Array( normals ), 3 );
286
+ if ( i + 2 < text.length && text.slice( i, i + 3 ) === quoteChar ) {
255
287
 
256
- // normals require a special treatment in USD
288
+ result += quoteChar;
289
+ i += 3;
290
+ break;
257
291
 
258
- if ( normals.length === positionsLength ) {
292
+ } else {
259
293
 
260
- // raw normal and position data have equal length (like produced by USDZExporter)
294
+ if ( text[ i ] === '\n' ) {
261
295
 
262
- if ( indices !== null ) attribute = toFlatBufferAttribute( attribute, indices );
296
+ result += '\\n';
263
297
 
264
- } else {
298
+ } else if ( text[ i ] !== '\r' ) {
265
299
 
266
- // unequal length, normals are independent of faceVertexIndices
300
+ result += text[ i ];
267
301
 
268
- let indices = Array.from( Array( normals.length / 3 ).keys() ); // [ 0, 1, 2, 3 ... ]
269
- indices = toTriangleIndices( indices, counts );
270
- attribute = toFlatBufferAttribute( attribute, indices );
302
+ }
271
303
 
272
- }
304
+ i ++;
273
305
 
274
- geometry.setAttribute( 'normal', attribute );
306
+ }
275
307
 
276
- } else {
308
+ }
277
309
 
278
- // compute flat vertex normals
310
+ continue;
279
311
 
280
- geometry.computeVertexNormals();
312
+ }
281
313
 
282
314
  }
283
315
 
284
- return geometry;
316
+ result += text[ i ];
317
+ i ++;
285
318
 
286
319
  }
287
320
 
288
- function toTriangleIndices( rawIndices, counts ) {
289
-
290
- const indices = [];
291
-
292
- for ( let i = 0; i < counts.length; i ++ ) {
293
-
294
- const count = counts[ i ];
321
+ return result;
295
322
 
296
- const stride = i * count;
297
-
298
- if ( count === 3 ) {
323
+ }
299
324
 
300
- const a = rawIndices[ stride + 0 ];
301
- const b = rawIndices[ stride + 1 ];
302
- const c = rawIndices[ stride + 2 ];
325
+ _stripInlineComment( line ) {
303
326
 
304
- indices.push( a, b, c );
327
+ // Don't strip if line starts with #usda
328
+ if ( line.trim().startsWith( '#usda' ) ) return line;
305
329
 
306
- } else if ( count === 4 ) {
330
+ // Find # that's not inside a string
331
+ let inString = false;
332
+ let stringChar = null;
333
+ let escaped = false;
307
334
 
308
- const a = rawIndices[ stride + 0 ];
309
- const b = rawIndices[ stride + 1 ];
310
- const c = rawIndices[ stride + 2 ];
311
- const d = rawIndices[ stride + 3 ];
335
+ for ( let i = 0; i < line.length; i ++ ) {
312
336
 
313
- indices.push( a, b, c );
314
- indices.push( a, c, d );
337
+ const ch = line[ i ];
315
338
 
316
- } else {
339
+ if ( escaped ) {
317
340
 
318
- console.warn( 'THREE.USDZLoader: Face vertex count of %s unsupported.', count );
319
-
320
- }
341
+ escaped = false;
342
+ continue;
321
343
 
322
344
  }
323
345
 
324
- return indices;
325
-
326
- }
346
+ if ( ch === '\\' ) {
327
347
 
328
- function toFlatBufferAttribute( attribute, indices ) {
348
+ escaped = true;
349
+ continue;
329
350
 
330
- const array = attribute.array;
331
- const itemSize = attribute.itemSize;
351
+ }
332
352
 
333
- const array2 = new array.constructor( indices.length * itemSize );
353
+ if ( ! inString && ( ch === '"' || ch === '\'' ) ) {
334
354
 
335
- let index = 0, index2 = 0;
355
+ inString = true;
356
+ stringChar = ch;
336
357
 
337
- for ( let i = 0, l = indices.length; i < l; i ++ ) {
358
+ } else if ( inString && ch === stringChar ) {
338
359
 
339
- index = indices[ i ] * itemSize;
360
+ inString = false;
361
+ stringChar = null;
340
362
 
341
- for ( let j = 0; j < itemSize; j ++ ) {
363
+ } else if ( ! inString && ch === '#' ) {
342
364
 
343
- array2[ index2 ++ ] = array[ index ++ ];
344
-
345
- }
365
+ // Found comment start outside of string
366
+ return line.slice( 0, i ).trimEnd();
346
367
 
347
368
  }
348
369
 
349
- return new BufferAttribute( array2, itemSize );
350
-
351
370
  }
352
371
 
353
- function findMeshMaterial( data ) {
372
+ return line;
354
373
 
355
- if ( ! data ) return undefined;
374
+ }
356
375
 
357
- if ( 'rel material:binding' in data ) {
376
+ _findAssignmentOperator( line ) {
358
377
 
359
- const reference = data[ 'rel material:binding' ];
360
- const id = reference.replace( /^<\//, '' ).replace( />$/, '' );
361
- const parts = id.split( '/' );
378
+ // Find the first '=' that's not inside quotes
379
+ let inString = false;
380
+ let stringChar = null;
381
+ let escaped = false;
362
382
 
363
- return findMaterial( root, ` "${ parts[ 1 ] }"` );
383
+ for ( let i = 0; i < line.length; i ++ ) {
364
384
 
365
- }
385
+ const ch = line[ i ];
366
386
 
367
- return findMaterial( data );
387
+ if ( escaped ) {
368
388
 
369
- }
389
+ escaped = false;
390
+ continue;
370
391
 
371
- function findMaterial( data, id = '' ) {
392
+ }
372
393
 
373
- for ( const name in data ) {
394
+ if ( ch === '\\' ) {
374
395
 
375
- const object = data[ name ];
396
+ escaped = true;
397
+ continue;
376
398
 
377
- if ( name.startsWith( 'def Material' + id ) ) {
399
+ }
378
400
 
379
- return object;
401
+ if ( ! inString && ( ch === '"' || ch === '\'' ) ) {
380
402
 
381
- }
403
+ inString = true;
404
+ stringChar = ch;
382
405
 
383
- if ( typeof object === 'object' ) {
406
+ } else if ( inString && ch === stringChar ) {
384
407
 
385
- const material = findMaterial( object, id );
408
+ inString = false;
409
+ stringChar = null;
386
410
 
387
- if ( material ) return material;
411
+ } else if ( ! inString && ch === '=' ) {
388
412
 
389
- }
413
+ return i;
390
414
 
391
415
  }
392
416
 
393
417
  }
394
418
 
395
- function setTextureParams( map, data_value ) {
419
+ return - 1;
396
420
 
397
- // rotation, scale and translation
421
+ }
422
+
423
+ /**
424
+ * Parse USDA text and return raw spec data in specsByPath format.
425
+ * Used by USDComposer for unified scene composition.
426
+ */
427
+ parseData( text ) {
398
428
 
399
- if ( data_value[ 'float inputs:rotation' ] ) {
429
+ const root = this.parseText( text );
430
+ const specsByPath = {};
400
431
 
401
- map.rotation = parseFloat( data_value[ 'float inputs:rotation' ] );
432
+ // Spec types (must match USDCParser/USDComposer)
433
+ const SpecType = {
434
+ Attribute: 1,
435
+ Prim: 6,
436
+ Relationship: 8
437
+ };
402
438
 
403
- }
439
+ // Parse root metadata
440
+ const rootFields = {};
441
+ if ( '#usda 1.0' in root ) {
404
442
 
405
- if ( data_value[ 'float2 inputs:scale' ] ) {
443
+ const header = root[ '#usda 1.0' ];
406
444
 
407
- map.repeat = new Vector2().fromArray( JSON.parse( '[' + data_value[ 'float2 inputs:scale' ].replace( /[()]*/g, '' ) + ']' ) );
445
+ if ( header.upAxis ) {
446
+
447
+ rootFields.upAxis = header.upAxis.replace( /"/g, '' );
408
448
 
409
449
  }
410
450
 
411
- if ( data_value[ 'float2 inputs:translation' ] ) {
451
+ if ( header.defaultPrim ) {
412
452
 
413
- map.offset = new Vector2().fromArray( JSON.parse( '[' + data_value[ 'float2 inputs:translation' ].replace( /[()]*/g, '' ) + ']' ) );
453
+ rootFields.defaultPrim = header.defaultPrim.replace( /"/g, '' );
414
454
 
415
455
  }
416
456
 
417
457
  }
418
458
 
419
- function buildMaterial( data ) {
459
+ specsByPath[ '/' ] = { specType: SpecType.Prim, fields: rootFields };
420
460
 
421
- const material = new MeshPhysicalMaterial();
461
+ // Walk the tree and build specsByPath
462
+ const walkTree = ( data, parentPath ) => {
422
463
 
423
- if ( data !== undefined ) {
464
+ const primChildren = [];
424
465
 
425
- let surface = undefined;
466
+ for ( const key in data ) {
426
467
 
427
- const surfaceConnection = data[ 'token outputs:surface.connect' ];
468
+ // Skip metadata
469
+ if ( key === '#usda 1.0' ) continue;
470
+ if ( key === 'variants' ) continue;
428
471
 
429
- if ( surfaceConnection ) {
472
+ // Check for primitive definitions
473
+ // Matches both 'def TypeName "name"' and 'def "name"' (no type)
474
+ const defMatch = key.match( DEF_MATCH_REGEX );
475
+ if ( defMatch ) {
430
476
 
431
- const match = /(\w+)\.output/.exec( surfaceConnection );
477
+ const typeName = defMatch[ 1 ] || '';
478
+ const name = defMatch[ 2 ];
479
+ const path = parentPath === '/' ? '/' + name : parentPath + '/' + name;
432
480
 
433
- if ( match ) {
481
+ primChildren.push( name );
434
482
 
435
- const surfaceName = match[ 1 ];
436
- surface = data[ `def Shader "${surfaceName}"` ];
483
+ const primFields = { typeName };
484
+ const primData = data[ key ];
437
485
 
438
- }
486
+ // Extract attributes and relationships from this prim
487
+ this._extractPrimData( primData, path, primFields, specsByPath, SpecType );
439
488
 
440
- }
489
+ specsByPath[ path ] = { specType: SpecType.Prim, fields: primFields };
441
490
 
442
- if ( surface !== undefined ) {
491
+ // Recurse into children
492
+ walkTree( primData, path );
443
493
 
444
- if ( 'color3f inputs:diffuseColor.connect' in surface ) {
494
+ }
445
495
 
446
- const path = surface[ 'color3f inputs:diffuseColor.connect' ];
447
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
496
+ }
448
497
 
449
- material.map = buildTexture( sampler );
450
- material.map.colorSpace = SRGBColorSpace;
498
+ // Add primChildren to parent spec
499
+ if ( primChildren.length > 0 && specsByPath[ parentPath ] ) {
451
500
 
452
- if ( 'def Shader "Transform2d_diffuse"' in data ) {
501
+ specsByPath[ parentPath ].fields.primChildren = primChildren;
453
502
 
454
- setTextureParams( material.map, data[ 'def Shader "Transform2d_diffuse"' ] );
503
+ }
455
504
 
456
- }
505
+ };
457
506
 
458
- } else if ( 'color3f inputs:diffuseColor' in surface ) {
507
+ walkTree( root, '/' );
459
508
 
460
- const color = surface[ 'color3f inputs:diffuseColor' ].replace( /[()]*/g, '' );
461
- material.color.fromArray( JSON.parse( '[' + color + ']' ) );
509
+ return { specsByPath };
462
510
 
463
- }
511
+ }
464
512
 
465
- if ( 'color3f inputs:emissiveColor.connect' in surface ) {
513
+ _extractPrimData( data, path, primFields, specsByPath, SpecType ) {
466
514
 
467
- const path = surface[ 'color3f inputs:emissiveColor.connect' ];
468
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
515
+ if ( ! data || typeof data !== 'object' ) return;
469
516
 
470
- material.emissiveMap = buildTexture( sampler );
471
- material.emissiveMap.colorSpace = SRGBColorSpace;
472
- material.emissive.set( 0xffffff );
517
+ for ( const key in data ) {
473
518
 
474
- if ( 'def Shader "Transform2d_emissive"' in data ) {
519
+ // Skip nested defs (handled by walkTree)
520
+ if ( key.startsWith( 'def ' ) ) continue;
475
521
 
476
- setTextureParams( material.emissiveMap, data[ 'def Shader "Transform2d_emissive"' ] );
522
+ if ( key === 'prepend references' ) {
477
523
 
478
- }
524
+ primFields.references = [ data[ key ] ];
525
+ continue;
479
526
 
480
- } else if ( 'color3f inputs:emissiveColor' in surface ) {
527
+ }
481
528
 
482
- const color = surface[ 'color3f inputs:emissiveColor' ].replace( /[()]*/g, '' );
483
- material.emissive.fromArray( JSON.parse( '[' + color + ']' ) );
529
+ if ( key === 'payload' ) {
484
530
 
485
- }
531
+ primFields.payload = data[ key ];
532
+ continue;
486
533
 
487
- if ( 'normal3f inputs:normal.connect' in surface ) {
534
+ }
488
535
 
489
- const path = surface[ 'normal3f inputs:normal.connect' ];
490
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
536
+ if ( key === 'variants' ) {
491
537
 
492
- material.normalMap = buildTexture( sampler );
493
- material.normalMap.colorSpace = NoColorSpace;
538
+ const variantSelection = {};
539
+ const variants = data[ key ];
494
540
 
495
- if ( 'def Shader "Transform2d_normal"' in data ) {
541
+ for ( const vKey in variants ) {
496
542
 
497
- setTextureParams( material.normalMap, data[ 'def Shader "Transform2d_normal"' ] );
543
+ const match = vKey.match( VARIANT_STRING_REGEX );
544
+ if ( match ) {
498
545
 
499
- }
546
+ const variantSetName = match[ 1 ];
547
+ const variantValue = variants[ vKey ].replace( /"/g, '' );
548
+ variantSelection[ variantSetName ] = variantValue;
500
549
 
501
550
  }
502
551
 
503
- if ( 'float inputs:roughness.connect' in surface ) {
504
-
505
- const path = surface[ 'float inputs:roughness.connect' ];
506
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
507
-
508
- material.roughness = 1.0;
509
- material.roughnessMap = buildTexture( sampler );
510
- material.roughnessMap.colorSpace = NoColorSpace;
511
-
512
- if ( 'def Shader "Transform2d_roughness"' in data ) {
513
-
514
- setTextureParams( material.roughnessMap, data[ 'def Shader "Transform2d_roughness"' ] );
515
-
516
- }
517
-
518
- } else if ( 'float inputs:roughness' in surface ) {
519
-
520
- material.roughness = parseFloat( surface[ 'float inputs:roughness' ] );
552
+ }
521
553
 
522
- }
554
+ if ( Object.keys( variantSelection ).length > 0 ) {
523
555
 
524
- if ( 'float inputs:metallic.connect' in surface ) {
556
+ primFields.variantSelection = variantSelection;
525
557
 
526
- const path = surface[ 'float inputs:metallic.connect' ];
527
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
558
+ }
528
559
 
529
- material.metalness = 1.0;
530
- material.metalnessMap = buildTexture( sampler );
531
- material.metalnessMap.colorSpace = NoColorSpace;
560
+ continue;
532
561
 
533
- if ( 'def Shader "Transform2d_metallic"' in data ) {
562
+ }
534
563
 
535
- setTextureParams( material.metalnessMap, data[ 'def Shader "Transform2d_metallic"' ] );
564
+ if ( key.startsWith( 'rel ' ) ) {
536
565
 
537
- }
566
+ const relName = key.slice( 4 );
567
+ const relPath = path + '.' + relName;
568
+ const target = data[ key ].replace( /[<>]/g, '' );
569
+ specsByPath[ relPath ] = {
570
+ specType: SpecType.Relationship,
571
+ fields: { targetPaths: [ target ] }
572
+ };
573
+ continue;
538
574
 
539
- } else if ( 'float inputs:metallic' in surface ) {
575
+ }
540
576
 
541
- material.metalness = parseFloat( surface[ 'float inputs:metallic' ] );
577
+ // Handle xformOpOrder
578
+ if ( key.includes( 'xformOpOrder' ) ) {
542
579
 
543
- }
580
+ const ops = data[ key ]
581
+ .replace( /[\[\]]/g, '' )
582
+ .split( ',' )
583
+ .map( s => s.trim().replace( /"/g, '' ) );
584
+ primFields.xformOpOrder = ops;
585
+ continue;
544
586
 
545
- if ( 'float inputs:clearcoat.connect' in surface ) {
587
+ }
546
588
 
547
- const path = surface[ 'float inputs:clearcoat.connect' ];
548
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
589
+ // Handle typed attributes
590
+ // Format: [qualifier] type attrName (e.g., "uniform token[] joints", "float3 position")
591
+ const attrMatch = key.match( ATTR_MATCH_REGEX );
592
+ if ( attrMatch ) {
549
593
 
550
- material.clearcoat = 1.0;
551
- material.clearcoatMap = buildTexture( sampler );
552
- material.clearcoatMap.colorSpace = NoColorSpace;
594
+ const valueType = attrMatch[ 1 ];
595
+ const attrName = attrMatch[ 2 ];
596
+ const rawValue = data[ key ];
553
597
 
554
- if ( 'def Shader "Transform2d_clearcoat"' in data ) {
598
+ // Handle connection attributes (e.g., "inputs:normal.connect = </path>")
599
+ if ( attrName.endsWith( '.connect' ) ) {
555
600
 
556
- setTextureParams( material.clearcoatMap, data[ 'def Shader "Transform2d_clearcoat"' ] );
601
+ const baseAttrName = attrName.slice( 0, - 8 ); // Remove '.connect'
602
+ const attrPath = path + '.' + baseAttrName;
557
603
 
558
- }
604
+ // Parse connection path - extract from <path> format
605
+ let connPath = String( rawValue ).trim();
606
+ if ( connPath.startsWith( '<' ) ) connPath = connPath.slice( 1 );
607
+ if ( connPath.endsWith( '>' ) ) connPath = connPath.slice( 0, - 1 );
559
608
 
560
- } else if ( 'float inputs:clearcoat' in surface ) {
609
+ // Get or create the attribute spec
610
+ if ( ! specsByPath[ attrPath ] ) {
561
611
 
562
- material.clearcoat = parseFloat( surface[ 'float inputs:clearcoat' ] );
612
+ specsByPath[ attrPath ] = {
613
+ specType: SpecType.Attribute,
614
+ fields: { typeName: valueType }
615
+ };
563
616
 
564
617
  }
565
618
 
566
- if ( 'float inputs:clearcoatRoughness.connect' in surface ) {
567
-
568
- const path = surface[ 'float inputs:clearcoatRoughness.connect' ];
569
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
570
-
571
- material.clearcoatRoughness = 1.0;
572
- material.clearcoatRoughnessMap = buildTexture( sampler );
573
- material.clearcoatRoughnessMap.colorSpace = NoColorSpace;
574
-
575
- if ( 'def Shader "Transform2d_clearcoatRoughness"' in data ) {
619
+ specsByPath[ attrPath ].fields.connectionPaths = [ connPath ];
620
+ continue;
576
621
 
577
- setTextureParams( material.clearcoatRoughnessMap, data[ 'def Shader "Transform2d_clearcoatRoughness"' ] );
622
+ }
578
623
 
579
- }
624
+ // Handle timeSamples attributes specially
625
+ if ( attrName.endsWith( '.timeSamples' ) && typeof rawValue === 'object' ) {
580
626
 
581
- } else if ( 'float inputs:clearcoatRoughness' in surface ) {
627
+ const baseAttrName = attrName.slice( 0, - 12 ); // Remove '.timeSamples'
628
+ const attrPath = path + '.' + baseAttrName;
582
629
 
583
- material.clearcoatRoughness = parseFloat( surface[ 'float inputs:clearcoatRoughness' ] );
630
+ // Parse timeSamples dictionary into times and values arrays
631
+ const times = [];
632
+ const values = [];
584
633
 
585
- }
634
+ for ( const frameKey in rawValue ) {
586
635
 
587
- if ( 'float inputs:ior' in surface ) {
636
+ const frame = parseFloat( frameKey );
637
+ if ( isNaN( frame ) ) continue;
588
638
 
589
- material.ior = parseFloat( surface[ 'float inputs:ior' ] );
639
+ times.push( frame );
640
+ values.push( this._parseAttributeValue( valueType, rawValue[ frameKey ] ) );
590
641
 
591
642
  }
592
643
 
593
- if ( 'float inputs:occlusion.connect' in surface ) {
594
-
595
- const path = surface[ 'float inputs:occlusion.connect' ];
596
- const sampler = findTexture( root, /(\w+).output/.exec( path )[ 1 ] );
597
-
598
- material.aoMap = buildTexture( sampler );
599
- material.aoMap.colorSpace = NoColorSpace;
644
+ // Sort by time
645
+ const sorted = times.map( ( t, i ) => ( { t, v: values[ i ] } ) ).sort( ( a, b ) => a.t - b.t );
600
646
 
601
- if ( 'def Shader "Transform2d_occlusion"' in data ) {
647
+ specsByPath[ attrPath ] = {
648
+ specType: SpecType.Attribute,
649
+ fields: {
650
+ timeSamples: { times: sorted.map( s => s.t ), values: sorted.map( s => s.v ) },
651
+ typeName: valueType
652
+ }
653
+ };
602
654
 
603
- setTextureParams( material.aoMap, data[ 'def Shader "Transform2d_occlusion"' ] );
655
+ } else {
604
656
 
605
- }
657
+ // Parse value based on type
658
+ const parsedValue = this._parseAttributeValue( valueType, rawValue );
606
659
 
607
- }
660
+ // Store as attribute spec
661
+ const attrPath = path + '.' + attrName;
662
+ specsByPath[ attrPath ] = {
663
+ specType: SpecType.Attribute,
664
+ fields: { default: parsedValue, typeName: valueType }
665
+ };
608
666
 
609
667
  }
610
668
 
611
669
  }
612
670
 
613
- return material;
614
-
615
671
  }
616
672
 
617
- function findTexture( data, id ) {
673
+ }
618
674
 
619
- for ( const name in data ) {
675
+ _parseAttributeValue( valueType, rawValue ) {
620
676
 
621
- const object = data[ name ];
677
+ if ( rawValue === undefined || rawValue === null ) return undefined;
622
678
 
623
- if ( name.startsWith( `def Shader "${ id }"` ) ) {
679
+ const str = String( rawValue ).trim();
624
680
 
625
- return object;
681
+ // Array types
682
+ if ( valueType.endsWith( '[]' ) ) {
626
683
 
627
- }
684
+ // Parse JSON-like arrays
685
+ try {
628
686
 
629
- if ( typeof object === 'object' ) {
687
+ // Handle arrays with parentheses like [(1,2,3), (4,5,6)]
688
+ // Remove trailing comma (valid in USDA but not JSON)
689
+ let cleaned = str.replace( /\(/g, '[' ).replace( /\)/g, ']' );
690
+ if ( cleaned.endsWith( ',' ) ) cleaned = cleaned.slice( 0, - 1 );
691
+ const parsed = JSON.parse( cleaned );
630
692
 
631
- const texture = findTexture( object, id );
693
+ // Flatten nested arrays for types like point3f[]
694
+ if ( Array.isArray( parsed ) && Array.isArray( parsed[ 0 ] ) ) {
632
695
 
633
- if ( texture ) return texture;
696
+ return parsed.flat();
634
697
 
635
698
  }
636
699
 
637
- }
638
-
639
- }
700
+ return parsed;
640
701
 
641
- function buildTexture( data ) {
702
+ } catch ( e ) {
642
703
 
643
- if ( 'asset inputs:file' in data ) {
704
+ // Try simple array parsing
705
+ const cleaned = str.replace( /[\[\]]/g, '' );
706
+ return cleaned.split( ',' ).map( s => {
644
707
 
645
- const path = data[ 'asset inputs:file' ].replace( /@*/g, '' ).trim();
708
+ const trimmed = s.trim();
709
+ const num = parseFloat( trimmed );
710
+ return isNaN( num ) ? trimmed.replace( /"/g, '' ) : num;
646
711
 
647
- const loader = new TextureLoader();
712
+ } );
648
713
 
649
- const texture = loader.load( assets[ path ] );
714
+ }
650
715
 
651
- const map = {
652
- '"clamp"': ClampToEdgeWrapping,
653
- '"mirror"': MirroredRepeatWrapping,
654
- '"repeat"': RepeatWrapping
655
- };
716
+ }
656
717
 
657
- if ( 'token inputs:wrapS' in data ) {
718
+ // Vector types (double3, float3, point3f, etc.)
719
+ if ( valueType.includes( '3' ) || valueType.includes( '2' ) || valueType.includes( '4' ) ) {
658
720
 
659
- texture.wrapS = map[ data[ 'token inputs:wrapS' ] ];
721
+ // Parse (x, y, z) format
722
+ const cleaned = str.replace( /[()]/g, '' );
723
+ const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
724
+ return values;
660
725
 
661
- }
662
-
663
- if ( 'token inputs:wrapT' in data ) {
726
+ }
664
727
 
665
- texture.wrapT = map[ data[ 'token inputs:wrapT' ] ];
728
+ // Quaternion types (quatf, quatd, quath)
729
+ // Text format is (w, x, y, z), convert to (x, y, z, w)
730
+ if ( valueType.startsWith( 'quat' ) ) {
666
731
 
667
- }
732
+ const cleaned = str.replace( /[()]/g, '' );
733
+ const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
734
+ return [ values[ 1 ], values[ 2 ], values[ 3 ], values[ 0 ] ];
668
735
 
669
- return texture;
736
+ }
670
737
 
671
- }
738
+ // Matrix types
739
+ if ( valueType.includes( 'matrix' ) ) {
672
740
 
673
- return null;
741
+ const cleaned = str.replace( /[()]/g, '' );
742
+ const values = cleaned.split( ',' ).map( s => parseFloat( s.trim() ) );
743
+ return values;
674
744
 
675
745
  }
676
746
 
677
- function buildObject( data ) {
747
+ // Scalar numeric types
748
+ if ( valueType === 'float' || valueType === 'double' || valueType === 'int' ) {
678
749
 
679
- const geometry = buildGeometry( findMeshGeometry( data ) );
680
- const material = buildMaterial( findMeshMaterial( data ) );
750
+ return parseFloat( str );
681
751
 
682
- const mesh = geometry ? new Mesh( geometry, material ) : new Object3D();
752
+ }
683
753
 
684
- if ( 'matrix4d xformOp:transform' in data ) {
754
+ // String/token types
755
+ if ( valueType === 'string' || valueType === 'token' ) {
685
756
 
686
- const array = JSON.parse( '[' + data[ 'matrix4d xformOp:transform' ].replace( /[()]*/g, '' ) + ']' );
757
+ return this._parseString( str );
687
758
 
688
- mesh.matrix.fromArray( array );
689
- mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
759
+ }
690
760
 
691
- }
761
+ // Asset path
762
+ if ( valueType === 'asset' ) {
692
763
 
693
- return mesh;
764
+ return str.replace( /@/g, '' ).replace( /"/g, '' );
694
765
 
695
766
  }
696
767
 
697
- function buildHierarchy( data, group ) {
698
-
699
- for ( const name in data ) {
768
+ // Default: return as string with quotes removed
769
+ return this._parseString( str );
700
770
 
701
- if ( name.startsWith( 'def Scope' ) ) {
771
+ }
702
772
 
703
- buildHierarchy( data[ name ], group );
773
+ _parseString( str ) {
704
774
 
705
- } else if ( name.startsWith( 'def Xform' ) ) {
775
+ // Remove surrounding quotes
776
+ if ( ( str.startsWith( '"' ) && str.endsWith( '"' ) ) ||
777
+ ( str.startsWith( '\'' ) && str.endsWith( '\'' ) ) ) {
706
778
 
707
- const mesh = buildObject( data[ name ] );
779
+ str = str.slice( 1, - 1 );
708
780
 
709
- if ( /def Xform "(\w+)"/.test( name ) ) {
781
+ }
710
782
 
711
- mesh.name = /def Xform "(\w+)"/.exec( name )[ 1 ];
783
+ // Handle escape sequences
784
+ let result = '';
785
+ let i = 0;
712
786
 
713
- }
787
+ while ( i < str.length ) {
714
788
 
715
- group.add( mesh );
789
+ if ( str[ i ] === '\\' && i + 1 < str.length ) {
716
790
 
717
- buildHierarchy( data[ name ], mesh );
791
+ const next = str[ i + 1 ];
718
792
 
719
- }
793
+ switch ( next ) {
720
794
 
721
- }
795
+ case 'n': result += '\n'; break;
796
+ case 't': result += '\t'; break;
797
+ case 'r': result += '\r'; break;
798
+ case '\\': result += '\\'; break;
799
+ case '"': result += '"'; break;
800
+ case '\'': result += '\''; break;
801
+ default: result += next; break;
722
802
 
723
- }
803
+ }
724
804
 
725
- function buildGroup( data ) {
805
+ i += 2;
726
806
 
727
- const group = new Group();
807
+ } else {
728
808
 
729
- buildHierarchy( data, group );
809
+ result += str[ i ];
810
+ i ++;
730
811
 
731
- return group;
812
+ }
732
813
 
733
814
  }
734
815
 
735
- return buildGroup( root );
816
+ return result;
736
817
 
737
818
  }
738
819