@needle-tools/three 0.154.2 → 0.160.2

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 (957) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +86 -84
  3. package/build/three.cjs +53679 -51654
  4. package/build/three.module.js +53263 -51253
  5. package/build/three.module.min.js +6 -6
  6. package/examples/fonts/LICENSE +13 -13
  7. package/examples/fonts/README.md +11 -11
  8. package/examples/fonts/droid/NOTICE +190 -190
  9. package/examples/fonts/droid/README.txt +18 -18
  10. package/examples/fonts/ttf/README.md +9 -9
  11. package/examples/jsm/Addons.js +294 -0
  12. package/examples/jsm/animation/AnimationClipCreator.js +116 -116
  13. package/examples/jsm/animation/CCDIKSolver.js +482 -482
  14. package/examples/jsm/animation/MMDAnimationHelper.js +1207 -1207
  15. package/examples/jsm/animation/MMDPhysics.js +1406 -1406
  16. package/examples/jsm/cameras/CinematicCamera.js +208 -208
  17. package/examples/jsm/capabilities/WebGL.js +108 -91
  18. package/examples/jsm/capabilities/WebGPU.js +57 -53
  19. package/examples/jsm/controls/ArcballControls.js +3224 -3224
  20. package/examples/jsm/controls/DragControls.js +221 -220
  21. package/examples/jsm/controls/FirstPersonControls.js +325 -325
  22. package/examples/jsm/controls/FlyControls.js +326 -300
  23. package/examples/jsm/controls/MapControls.js +28 -28
  24. package/examples/jsm/controls/OrbitControls.js +1521 -1279
  25. package/examples/jsm/controls/PointerLockControls.js +162 -162
  26. package/examples/jsm/controls/TrackballControls.js +828 -828
  27. package/examples/jsm/controls/TransformControls.js +1573 -1557
  28. package/examples/jsm/csm/CSM.js +384 -384
  29. package/examples/jsm/csm/CSMFrustum.js +152 -152
  30. package/examples/jsm/csm/CSMHelper.js +193 -193
  31. package/examples/jsm/csm/CSMShader.js +295 -252
  32. package/examples/jsm/curves/CurveExtras.js +422 -422
  33. package/examples/jsm/curves/NURBSCurve.js +80 -80
  34. package/examples/jsm/curves/NURBSSurface.js +52 -52
  35. package/examples/jsm/curves/NURBSUtils.js +487 -487
  36. package/examples/jsm/effects/AnaglyphEffect.js +154 -154
  37. package/examples/jsm/effects/AsciiEffect.js +263 -263
  38. package/examples/jsm/effects/OutlineEffect.js +539 -539
  39. package/examples/jsm/effects/ParallaxBarrierEffect.js +119 -119
  40. package/examples/jsm/effects/PeppersGhostEffect.js +153 -153
  41. package/examples/jsm/effects/StereoEffect.js +55 -55
  42. package/examples/jsm/environments/DebugEnvironment.js +52 -52
  43. package/examples/jsm/environments/RoomEnvironment.js +148 -148
  44. package/examples/jsm/exporters/DRACOExporter.js +267 -267
  45. package/examples/jsm/exporters/EXRExporter.js +579 -501
  46. package/examples/jsm/exporters/GLTFExporter.js +3311 -3163
  47. package/examples/jsm/exporters/KTX2Exporter.js +292 -292
  48. package/examples/jsm/exporters/MMDExporter.js +217 -217
  49. package/examples/jsm/exporters/OBJExporter.js +284 -284
  50. package/examples/jsm/exporters/PLYExporter.js +528 -528
  51. package/examples/jsm/exporters/STLExporter.js +199 -199
  52. package/examples/jsm/exporters/USDZExporter.js +720 -710
  53. package/examples/jsm/geometries/BoxLineGeometry.js +69 -69
  54. package/examples/jsm/geometries/ConvexGeometry.js +53 -53
  55. package/examples/jsm/geometries/DecalGeometry.js +356 -356
  56. package/examples/jsm/geometries/InstancedPointsGeometry.js +174 -0
  57. package/examples/jsm/geometries/ParametricGeometries.js +254 -254
  58. package/examples/jsm/geometries/ParametricGeometry.js +139 -139
  59. package/examples/jsm/geometries/RoundedBoxGeometry.js +155 -155
  60. package/examples/jsm/geometries/SDFGeometryGenerator.js +144 -0
  61. package/examples/jsm/geometries/TeapotGeometry.js +704 -704
  62. package/examples/jsm/geometries/TextGeometry.js +57 -57
  63. package/examples/jsm/helpers/LightProbeHelper.js +130 -130
  64. package/examples/jsm/helpers/OctreeHelper.js +73 -73
  65. package/examples/jsm/helpers/PositionalAudioHelper.js +109 -109
  66. package/examples/jsm/helpers/RectAreaLightHelper.js +85 -85
  67. package/examples/jsm/helpers/TextureHelper.js +237 -0
  68. package/examples/jsm/helpers/VertexNormalsHelper.js +96 -96
  69. package/examples/jsm/helpers/VertexTangentsHelper.js +88 -88
  70. package/examples/jsm/helpers/ViewHelper.js +333 -333
  71. package/examples/jsm/interactive/HTMLMesh.js +572 -565
  72. package/examples/jsm/interactive/InteractiveGroup.js +116 -116
  73. package/examples/jsm/interactive/SelectionBox.js +227 -227
  74. package/examples/jsm/interactive/SelectionHelper.js +104 -97
  75. package/examples/jsm/libs/ammo.wasm.js +822 -822
  76. package/examples/jsm/libs/basis/README.md +46 -46
  77. package/examples/jsm/libs/basis/basis_transcoder.js +21 -21
  78. package/examples/jsm/libs/chevrotain.module.min.js +141 -141
  79. package/examples/jsm/libs/draco/README.md +32 -32
  80. package/examples/jsm/libs/draco/draco_decoder.js +34 -34
  81. package/examples/jsm/libs/draco/draco_encoder.js +33 -33
  82. package/examples/jsm/libs/draco/draco_wasm_wrapper.js +117 -117
  83. package/examples/jsm/libs/draco/gltf/draco_decoder.js +33 -33
  84. package/examples/jsm/libs/draco/gltf/draco_encoder.js +33 -33
  85. package/examples/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -116
  86. package/examples/jsm/libs/ecsy.module.js +1792 -1792
  87. package/examples/jsm/libs/fflate.module.js +2474 -2474
  88. package/examples/jsm/libs/ktx-parse.module.js +1 -1
  89. package/examples/jsm/libs/lil-gui.module.min.js +8 -8
  90. package/examples/jsm/libs/lottie_canvas.module.js +14849 -14844
  91. package/examples/jsm/libs/meshopt_decoder.module.js +178 -178
  92. package/examples/jsm/libs/mikktspace.module.js +128 -128
  93. package/examples/jsm/libs/mmdparser.module.js +11530 -11530
  94. package/examples/jsm/libs/motion-controllers.module.js +397 -397
  95. package/examples/jsm/libs/opentype.module.js +14506 -14568
  96. package/examples/jsm/libs/potpack.module.js +124 -124
  97. package/examples/jsm/libs/rhino3dm/rhino3dm.js +8743 -21
  98. package/examples/jsm/libs/rhino3dm/rhino3dm.module.js +8748 -15
  99. package/examples/jsm/libs/rhino3dm/rhino3dm.wasm +0 -0
  100. package/examples/jsm/libs/stats.module.js +167 -167
  101. package/examples/jsm/libs/surfaceNet.js +201 -0
  102. package/examples/jsm/libs/tween.module.js +858 -803
  103. package/examples/jsm/libs/utif.module.js +1664 -1578
  104. package/examples/jsm/libs/zstddec.module.js +1 -1
  105. package/examples/jsm/lights/IESSpotLight.js +25 -25
  106. package/examples/jsm/lights/LightProbeGenerator.js +286 -252
  107. package/examples/jsm/lights/RectAreaLightUniformsLib.js +79 -79
  108. package/examples/jsm/lines/Line2.js +19 -19
  109. package/examples/jsm/lines/LineGeometry.js +79 -79
  110. package/examples/jsm/lines/LineMaterial.js +619 -702
  111. package/examples/jsm/lines/LineSegments2.js +361 -361
  112. package/examples/jsm/lines/LineSegmentsGeometry.js +241 -241
  113. package/examples/jsm/lines/Wireframe.js +56 -56
  114. package/examples/jsm/lines/WireframeGeometry2.js +24 -24
  115. package/examples/jsm/loaders/3DMLoader.js +1772 -1497
  116. package/examples/jsm/loaders/3MFLoader.js +1478 -1478
  117. package/examples/jsm/loaders/AMFLoader.js +521 -521
  118. package/examples/jsm/loaders/BVHLoader.js +437 -437
  119. package/examples/jsm/loaders/ColladaLoader.js +4116 -4122
  120. package/examples/jsm/loaders/DDSLoader.js +318 -274
  121. package/examples/jsm/loaders/DRACOLoader.js +613 -612
  122. package/examples/jsm/loaders/EXRLoader.js +2309 -2309
  123. package/examples/jsm/loaders/FBXLoader.js +4314 -4142
  124. package/examples/jsm/loaders/FontLoader.js +183 -183
  125. package/examples/jsm/loaders/GCodeLoader.js +261 -261
  126. package/examples/jsm/loaders/GLTFLoader.js +4666 -4579
  127. package/examples/jsm/loaders/GLTFLoaderAnimationPointer.js +719 -683
  128. package/examples/jsm/loaders/HDRCubeTextureLoader.js +115 -115
  129. package/examples/jsm/loaders/IESLoader.js +337 -337
  130. package/examples/jsm/loaders/KMZLoader.js +130 -130
  131. package/examples/jsm/loaders/KTX2Loader.js +932 -868
  132. package/examples/jsm/loaders/KTXLoader.js +176 -176
  133. package/examples/jsm/loaders/LDrawLoader.js +2470 -2464
  134. package/examples/jsm/loaders/LUT3dlLoader.js +183 -151
  135. package/examples/jsm/loaders/LUTCubeLoader.js +167 -153
  136. package/examples/jsm/loaders/LUTImageLoader.js +163 -0
  137. package/examples/jsm/loaders/LWOLoader.js +1052 -1052
  138. package/examples/jsm/loaders/LogLuvLoader.js +606 -606
  139. package/examples/jsm/loaders/LottieLoader.js +77 -77
  140. package/examples/jsm/loaders/MD2Loader.js +399 -399
  141. package/examples/jsm/loaders/MDDLoader.js +102 -102
  142. package/examples/jsm/loaders/MMDLoader.js +2276 -2273
  143. package/examples/jsm/loaders/MTLLoader.js +567 -567
  144. package/examples/jsm/loaders/MaterialXLoader.js +852 -734
  145. package/examples/jsm/loaders/NRRDLoader.js +686 -699
  146. package/examples/jsm/loaders/OBJLoader.js +905 -905
  147. package/examples/jsm/loaders/PCDLoader.js +467 -467
  148. package/examples/jsm/loaders/PDBLoader.js +232 -232
  149. package/examples/jsm/loaders/PLYLoader.js +771 -771
  150. package/examples/jsm/loaders/PVRLoader.js +251 -251
  151. package/examples/jsm/loaders/RGBELoader.js +450 -468
  152. package/examples/jsm/loaders/RGBMLoader.js +1065 -1065
  153. package/examples/jsm/loaders/STLLoader.js +410 -403
  154. package/examples/jsm/loaders/SVGLoader.js +3173 -3172
  155. package/examples/jsm/loaders/TDSLoader.js +1124 -1124
  156. package/examples/jsm/loaders/TGALoader.js +517 -517
  157. package/examples/jsm/loaders/TIFFLoader.js +36 -36
  158. package/examples/jsm/loaders/TTFLoader.js +214 -214
  159. package/examples/jsm/loaders/TiltLoader.js +520 -520
  160. package/examples/jsm/loaders/USDZLoader.js +822 -633
  161. package/examples/jsm/loaders/VOXLoader.js +311 -311
  162. package/examples/jsm/loaders/VRMLLoader.js +3533 -3533
  163. package/examples/jsm/loaders/VTKLoader.js +1163 -1163
  164. package/examples/jsm/loaders/XYZLoader.js +106 -106
  165. package/examples/jsm/loaders/lwo/IFFParser.js +1214 -1218
  166. package/examples/jsm/loaders/lwo/LWO2Parser.js +414 -414
  167. package/examples/jsm/loaders/lwo/LWO3Parser.js +373 -373
  168. package/examples/jsm/materials/MeshGouraudMaterial.js +426 -420
  169. package/examples/jsm/materials/MeshPostProcessingMaterial.js +144 -0
  170. package/examples/jsm/math/Capsule.js +82 -137
  171. package/examples/jsm/math/ColorConverter.js +36 -36
  172. package/examples/jsm/math/ConvexHull.js +1271 -1271
  173. package/examples/jsm/math/ImprovedNoise.js +71 -71
  174. package/examples/jsm/math/Lut.js +204 -204
  175. package/examples/jsm/math/MeshSurfaceSampler.js +250 -250
  176. package/examples/jsm/math/OBB.js +423 -423
  177. package/examples/jsm/math/Octree.js +540 -462
  178. package/examples/jsm/math/SimplexNoise.js +444 -444
  179. package/examples/jsm/misc/ConvexObjectBreaker.js +519 -519
  180. package/examples/jsm/misc/GPUComputationRenderer.js +446 -455
  181. package/examples/jsm/misc/Gyroscope.js +66 -66
  182. package/examples/jsm/misc/MD2Character.js +276 -276
  183. package/examples/jsm/misc/MD2CharacterComplex.js +576 -576
  184. package/examples/jsm/misc/MorphAnimMesh.js +75 -75
  185. package/examples/jsm/misc/MorphBlendMesh.js +322 -322
  186. package/examples/jsm/misc/ProgressiveLightMap.js +323 -323
  187. package/examples/jsm/misc/RollerCoaster.js +566 -566
  188. package/examples/jsm/misc/Timer.js +119 -0
  189. package/examples/jsm/misc/TubePainter.js +202 -205
  190. package/examples/jsm/misc/Volume.js +473 -475
  191. package/examples/jsm/misc/VolumeSlice.js +229 -229
  192. package/examples/jsm/modifiers/CurveModifier.js +344 -326
  193. package/examples/jsm/modifiers/EdgeSplitModifier.js +279 -279
  194. package/examples/jsm/modifiers/SimplifyModifier.js +617 -525
  195. package/examples/jsm/modifiers/TessellateModifier.js +307 -307
  196. package/examples/jsm/nodes/Nodes.js +189 -172
  197. package/examples/jsm/nodes/accessors/BitangentNode.js +89 -89
  198. package/examples/jsm/nodes/accessors/BufferAttributeNode.js +127 -99
  199. package/examples/jsm/nodes/accessors/BufferNode.js +30 -30
  200. package/examples/jsm/nodes/accessors/CameraNode.js +120 -98
  201. package/examples/jsm/nodes/accessors/CubeTextureNode.js +61 -101
  202. package/examples/jsm/nodes/accessors/InstanceNode.js +71 -71
  203. package/examples/jsm/nodes/accessors/InstancedPointsMaterialNode.js +21 -0
  204. package/examples/jsm/nodes/accessors/MaterialNode.js +314 -277
  205. package/examples/jsm/nodes/accessors/MaterialReferenceNode.js +51 -39
  206. package/examples/jsm/nodes/accessors/ModelNode.js +33 -34
  207. package/examples/jsm/nodes/accessors/ModelViewProjectionNode.js +39 -29
  208. package/examples/jsm/nodes/accessors/MorphNode.js +245 -70
  209. package/examples/jsm/nodes/accessors/NormalNode.js +96 -96
  210. package/examples/jsm/nodes/accessors/Object3DNode.js +150 -150
  211. package/examples/jsm/nodes/accessors/PointUVNode.js +26 -26
  212. package/examples/jsm/nodes/accessors/PositionNode.js +104 -104
  213. package/examples/jsm/nodes/accessors/ReferenceNode.js +102 -72
  214. package/examples/jsm/nodes/accessors/ReflectVectorNode.js +35 -35
  215. package/examples/jsm/nodes/accessors/SceneNode.js +52 -46
  216. package/examples/jsm/nodes/accessors/SkinningNode.js +103 -93
  217. package/examples/jsm/nodes/accessors/StorageBufferNode.js +54 -27
  218. package/examples/jsm/nodes/accessors/TangentNode.js +103 -103
  219. package/examples/jsm/nodes/accessors/TextureBicubicNode.js +94 -94
  220. package/examples/jsm/nodes/accessors/TextureNode.js +367 -230
  221. package/examples/jsm/nodes/accessors/TextureSizeNode.js +35 -35
  222. package/examples/jsm/nodes/accessors/TextureStoreNode.js +82 -0
  223. package/examples/jsm/nodes/accessors/UVNode.js +47 -47
  224. package/examples/jsm/nodes/accessors/UserDataNode.js +29 -29
  225. package/examples/jsm/nodes/accessors/VertexColorNode.js +70 -0
  226. package/examples/jsm/nodes/code/CodeNode.js +78 -78
  227. package/examples/jsm/nodes/code/ExpressionNode.js +37 -37
  228. package/examples/jsm/nodes/code/FunctionCallNode.js +96 -96
  229. package/examples/jsm/nodes/code/FunctionNode.js +138 -127
  230. package/examples/jsm/nodes/code/ScriptableNode.js +488 -488
  231. package/examples/jsm/nodes/code/ScriptableValueNode.js +167 -167
  232. package/examples/jsm/nodes/core/ArrayUniformNode.js +26 -26
  233. package/examples/jsm/nodes/core/AssignNode.js +72 -0
  234. package/examples/jsm/nodes/core/AttributeNode.js +108 -102
  235. package/examples/jsm/nodes/core/BypassNode.js +45 -45
  236. package/examples/jsm/nodes/core/CacheNode.js +49 -46
  237. package/examples/jsm/nodes/core/ConstNode.js +32 -32
  238. package/examples/jsm/nodes/core/ContextNode.js +61 -61
  239. package/examples/jsm/nodes/core/IndexNode.js +66 -66
  240. package/examples/jsm/nodes/core/InputNode.js +83 -83
  241. package/examples/jsm/nodes/core/LightingModel.js +17 -17
  242. package/examples/jsm/nodes/core/Node.js +483 -445
  243. package/examples/jsm/nodes/core/NodeAttribute.js +15 -15
  244. package/examples/jsm/nodes/core/NodeBuilder.js +1267 -1016
  245. package/examples/jsm/nodes/core/NodeCache.js +26 -26
  246. package/examples/jsm/nodes/core/NodeCode.js +15 -15
  247. package/examples/jsm/nodes/core/NodeFrame.js +135 -110
  248. package/examples/jsm/nodes/core/NodeFunction.js +22 -22
  249. package/examples/jsm/nodes/core/NodeFunctionInput.js +17 -17
  250. package/examples/jsm/nodes/core/NodeKeywords.js +80 -80
  251. package/examples/jsm/nodes/core/NodeParser.js +11 -11
  252. package/examples/jsm/nodes/core/NodeUniform.js +40 -28
  253. package/examples/jsm/nodes/core/NodeUtils.js +210 -212
  254. package/examples/jsm/nodes/core/NodeVar.js +14 -14
  255. package/examples/jsm/nodes/core/NodeVarying.js +17 -17
  256. package/examples/jsm/nodes/core/OutputStructNode.js +62 -0
  257. package/examples/jsm/nodes/core/ParameterNode.js +33 -0
  258. package/examples/jsm/nodes/core/PropertyNode.js +72 -57
  259. package/examples/jsm/nodes/core/StackNode.js +89 -99
  260. package/examples/jsm/nodes/core/StructTypeNode.js +24 -0
  261. package/examples/jsm/nodes/core/TempNode.js +58 -58
  262. package/examples/jsm/nodes/core/UniformGroup.js +13 -0
  263. package/examples/jsm/nodes/core/UniformGroupNode.js +36 -0
  264. package/examples/jsm/nodes/core/UniformNode.js +80 -61
  265. package/examples/jsm/nodes/core/VarNode.js +60 -87
  266. package/examples/jsm/nodes/core/VaryingNode.js +65 -69
  267. package/examples/jsm/nodes/core/constants.js +27 -27
  268. package/examples/jsm/nodes/display/AfterImageNode.js +134 -0
  269. package/examples/jsm/nodes/display/BlendModeNode.js +99 -99
  270. package/examples/jsm/nodes/display/BumpMapNode.js +99 -0
  271. package/examples/jsm/nodes/display/ColorAdjustmentNode.js +96 -100
  272. package/examples/jsm/nodes/display/ColorSpaceNode.js +108 -108
  273. package/examples/jsm/nodes/display/FrontFacingNode.js +27 -27
  274. package/examples/jsm/nodes/display/GaussianBlurNode.js +177 -0
  275. package/examples/jsm/nodes/display/NormalMapNode.js +108 -106
  276. package/examples/jsm/nodes/display/PassNode.js +182 -0
  277. package/examples/jsm/nodes/display/PosterizeNode.js +32 -32
  278. package/examples/jsm/nodes/display/ToneMappingNode.js +184 -141
  279. package/examples/jsm/nodes/display/ViewportDepthNode.js +97 -69
  280. package/examples/jsm/nodes/display/ViewportDepthTextureNode.js +31 -34
  281. package/examples/jsm/nodes/display/ViewportNode.js +134 -115
  282. package/examples/jsm/nodes/display/ViewportSharedTextureNode.js +31 -31
  283. package/examples/jsm/nodes/display/ViewportTextureNode.js +75 -75
  284. package/examples/jsm/nodes/fog/FogExp2Node.js +35 -35
  285. package/examples/jsm/nodes/fog/FogNode.js +38 -37
  286. package/examples/jsm/nodes/fog/FogRangeNode.js +34 -34
  287. package/examples/jsm/nodes/functions/BSDF/BRDF_GGX.js +40 -32
  288. package/examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js +9 -9
  289. package/examples/jsm/nodes/functions/BSDF/BRDF_Sheen.js +57 -43
  290. package/examples/jsm/nodes/functions/BSDF/DFGApprox.js +30 -29
  291. package/examples/jsm/nodes/functions/BSDF/D_GGX.js +23 -18
  292. package/examples/jsm/nodes/functions/BSDF/EnvironmentBRDF.js +13 -13
  293. package/examples/jsm/nodes/functions/BSDF/F_Schlick.js +16 -16
  294. package/examples/jsm/nodes/functions/BSDF/Schlick_to_F0.js +21 -0
  295. package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +28 -20
  296. package/examples/jsm/nodes/functions/PhongLightingModel.js +67 -28
  297. package/examples/jsm/nodes/functions/PhysicalLightingModel.js +393 -204
  298. package/examples/jsm/nodes/functions/material/getGeometryRoughness.js +13 -13
  299. package/examples/jsm/nodes/functions/material/getRoughness.js +18 -18
  300. package/examples/jsm/nodes/geometry/RangeNode.js +104 -104
  301. package/examples/jsm/nodes/gpgpu/ComputeNode.js +85 -72
  302. package/examples/jsm/nodes/lighting/AONode.js +27 -27
  303. package/examples/jsm/nodes/lighting/AmbientLightNode.js +27 -27
  304. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +238 -146
  305. package/examples/jsm/nodes/lighting/DirectionalLightNode.js +40 -43
  306. package/examples/jsm/nodes/lighting/EnvironmentNode.js +181 -181
  307. package/examples/jsm/nodes/lighting/HemisphereLightNode.js +55 -55
  308. package/examples/jsm/nodes/lighting/IESSpotLightNode.js +39 -39
  309. package/examples/jsm/nodes/lighting/LightNode.js +57 -57
  310. package/examples/jsm/nodes/lighting/LightUtils.js +17 -17
  311. package/examples/jsm/nodes/lighting/LightingContextNode.js +66 -99
  312. package/examples/jsm/nodes/lighting/LightingNode.js +21 -21
  313. package/examples/jsm/nodes/lighting/LightsNode.js +188 -128
  314. package/examples/jsm/nodes/lighting/PointLightNode.js +68 -71
  315. package/examples/jsm/nodes/lighting/SpotLightNode.js +89 -92
  316. package/examples/jsm/nodes/loaders/NodeLoader.js +108 -108
  317. package/examples/jsm/nodes/loaders/NodeMaterialLoader.js +59 -59
  318. package/examples/jsm/nodes/loaders/NodeObjectLoader.js +70 -70
  319. package/examples/jsm/nodes/materials/InstancedPointsNodeMaterial.js +162 -0
  320. package/examples/jsm/nodes/materials/Line2NodeMaterial.js +436 -0
  321. package/examples/jsm/nodes/materials/LineBasicNodeMaterial.js +28 -28
  322. package/examples/jsm/nodes/materials/LineDashedNodeMaterial.js +54 -0
  323. package/examples/jsm/nodes/materials/Materials.js +16 -11
  324. package/examples/jsm/nodes/materials/MeshBasicNodeMaterial.js +28 -27
  325. package/examples/jsm/nodes/materials/MeshLambertNodeMaterial.js +34 -0
  326. package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +40 -38
  327. package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +65 -65
  328. package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +155 -111
  329. package/examples/jsm/nodes/materials/MeshSSSNodeMaterial.js +84 -0
  330. package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +80 -80
  331. package/examples/jsm/nodes/materials/NodeMaterial.js +568 -510
  332. package/examples/jsm/nodes/materials/PointsNodeMaterial.js +39 -49
  333. package/examples/jsm/nodes/materials/SpriteNodeMaterial.js +96 -103
  334. package/examples/jsm/nodes/materialx/DISCLAIMER.md +199 -199
  335. package/examples/jsm/nodes/materialx/MaterialXNodes.js +68 -68
  336. package/examples/jsm/nodes/materialx/lib/mx_hsv.js +130 -56
  337. package/examples/jsm/nodes/materialx/lib/mx_noise.js +1430 -618
  338. package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +29 -19
  339. package/examples/jsm/nodes/math/CondNode.js +86 -86
  340. package/examples/jsm/nodes/math/HashNode.js +34 -0
  341. package/examples/jsm/nodes/math/MathNode.js +382 -359
  342. package/examples/jsm/nodes/math/OperatorNode.js +266 -269
  343. package/examples/jsm/nodes/math/TriNoise3D.js +71 -0
  344. package/examples/jsm/nodes/parsers/GLSLNodeFunction.js +152 -152
  345. package/examples/jsm/nodes/parsers/GLSLNodeParser.js +14 -14
  346. package/examples/jsm/nodes/procedural/CheckerNode.js +42 -42
  347. package/examples/jsm/nodes/shadernode/ShaderNode.js +625 -420
  348. package/examples/jsm/nodes/utils/ArrayElementNode.js +41 -33
  349. package/examples/jsm/nodes/utils/ConvertNode.js +65 -65
  350. package/examples/jsm/nodes/utils/DiscardNode.js +27 -26
  351. package/examples/jsm/nodes/utils/EquirectUVNode.js +33 -33
  352. package/examples/jsm/nodes/utils/FunctionOverloadingNode.js +95 -0
  353. package/examples/jsm/nodes/utils/JoinNode.js +61 -51
  354. package/examples/jsm/nodes/utils/LoopNode.js +198 -186
  355. package/examples/jsm/nodes/utils/MatcapUVNode.js +30 -30
  356. package/examples/jsm/nodes/utils/MaxMipLevelNode.js +46 -46
  357. package/examples/jsm/nodes/utils/OscNode.js +81 -81
  358. package/examples/jsm/nodes/utils/PackingNode.js +55 -55
  359. package/examples/jsm/nodes/utils/RemapNode.js +42 -42
  360. package/examples/jsm/nodes/utils/RotateNode.js +43 -0
  361. package/examples/jsm/nodes/utils/RotateUVNode.js +43 -43
  362. package/examples/jsm/nodes/utils/SetNode.js +62 -0
  363. package/examples/jsm/nodes/utils/SpecularMIPLevelNode.js +37 -37
  364. package/examples/jsm/nodes/utils/SplitNode.js +112 -104
  365. package/examples/jsm/nodes/utils/SpriteSheetUVNode.js +41 -41
  366. package/examples/jsm/nodes/utils/TimerNode.js +94 -94
  367. package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +62 -62
  368. package/examples/jsm/objects/GroundedSkybox.js +50 -0
  369. package/examples/jsm/objects/InstancedPoints.js +21 -0
  370. package/examples/jsm/objects/Lensflare.js +397 -377
  371. package/examples/jsm/objects/MarchingCubes.js +1176 -1176
  372. package/examples/jsm/objects/QuadMesh.js +66 -0
  373. package/examples/jsm/objects/Reflector.js +264 -272
  374. package/examples/jsm/objects/ReflectorForSSRPass.js +352 -349
  375. package/examples/jsm/objects/Refractor.js +327 -332
  376. package/examples/jsm/objects/ShadowMesh.js +80 -80
  377. package/examples/jsm/objects/Sky.js +219 -219
  378. package/examples/jsm/objects/Water.js +333 -330
  379. package/examples/jsm/objects/Water2.js +361 -358
  380. package/examples/jsm/offscreen/jank.js +45 -45
  381. package/examples/jsm/offscreen/offscreen.js +8 -8
  382. package/examples/jsm/offscreen/scene.js +86 -87
  383. package/examples/jsm/physics/AmmoPhysics.js +306 -285
  384. package/examples/jsm/physics/RapierPhysics.js +220 -199
  385. package/examples/jsm/postprocessing/AfterimagePass.js +104 -104
  386. package/examples/jsm/postprocessing/BloomPass.js +172 -172
  387. package/examples/jsm/postprocessing/BokehPass.js +141 -140
  388. package/examples/jsm/postprocessing/ClearPass.js +46 -46
  389. package/examples/jsm/postprocessing/CubeTexturePass.js +85 -85
  390. package/examples/jsm/postprocessing/DotScreenPass.js +65 -65
  391. package/examples/jsm/postprocessing/EffectComposer.js +231 -231
  392. package/examples/jsm/postprocessing/FilmPass.js +64 -66
  393. package/examples/jsm/postprocessing/GTAOPass.js +582 -0
  394. package/examples/jsm/postprocessing/GlitchPass.js +128 -128
  395. package/examples/jsm/postprocessing/HalftonePass.js +79 -79
  396. package/examples/jsm/postprocessing/LUTPass.js +174 -173
  397. package/examples/jsm/postprocessing/MaskPass.js +104 -101
  398. package/examples/jsm/postprocessing/OutlinePass.js +654 -654
  399. package/examples/jsm/postprocessing/OutputPass.js +95 -72
  400. package/examples/jsm/postprocessing/Pass.js +95 -84
  401. package/examples/jsm/postprocessing/RenderPass.js +99 -81
  402. package/examples/jsm/postprocessing/RenderPixelatedPass.js +235 -235
  403. package/examples/jsm/postprocessing/SAOPass.js +335 -411
  404. package/examples/jsm/postprocessing/SMAAPass.js +199 -201
  405. package/examples/jsm/postprocessing/SSAARenderPass.js +228 -228
  406. package/examples/jsm/postprocessing/SSAOPass.js +420 -440
  407. package/examples/jsm/postprocessing/SSRPass.js +641 -641
  408. package/examples/jsm/postprocessing/SavePass.js +79 -79
  409. package/examples/jsm/postprocessing/ShaderPass.js +77 -77
  410. package/examples/jsm/postprocessing/TAARenderPass.js +188 -189
  411. package/examples/jsm/postprocessing/TexturePass.js +67 -67
  412. package/examples/jsm/postprocessing/UnrealBloomPass.js +415 -411
  413. package/examples/jsm/renderers/CSS2DRenderer.js +215 -215
  414. package/examples/jsm/renderers/CSS3DRenderer.js +329 -335
  415. package/examples/jsm/renderers/Projector.js +918 -918
  416. package/examples/jsm/renderers/SVGRenderer.js +556 -553
  417. package/examples/jsm/renderers/common/Animation.js +47 -58
  418. package/examples/jsm/renderers/common/Attributes.js +75 -75
  419. package/examples/jsm/renderers/common/Backend.js +193 -162
  420. package/examples/jsm/renderers/common/Background.js +134 -134
  421. package/examples/jsm/renderers/common/Binding.js +25 -11
  422. package/examples/jsm/renderers/common/Bindings.js +173 -169
  423. package/examples/jsm/renderers/common/Buffer.js +38 -38
  424. package/examples/jsm/renderers/common/BufferUtils.js +33 -33
  425. package/examples/jsm/renderers/common/ChainMap.js +89 -89
  426. package/examples/jsm/renderers/common/Color4.js +37 -0
  427. package/examples/jsm/renderers/common/ComputePipeline.js +17 -17
  428. package/examples/jsm/renderers/common/Constants.js +14 -14
  429. package/examples/jsm/renderers/common/CubeRenderTarget.js +65 -65
  430. package/examples/jsm/renderers/common/DataMap.js +54 -54
  431. package/examples/jsm/renderers/common/Geometries.js +215 -215
  432. package/examples/jsm/renderers/common/Info.js +107 -73
  433. package/examples/jsm/renderers/common/Pipeline.js +13 -13
  434. package/examples/jsm/renderers/common/Pipelines.js +322 -321
  435. package/examples/jsm/renderers/common/PostProcessing.js +25 -0
  436. package/examples/jsm/renderers/common/ProgrammableStage.js +20 -18
  437. package/examples/jsm/renderers/common/RenderContext.js +41 -37
  438. package/examples/jsm/renderers/common/RenderContexts.js +74 -38
  439. package/examples/jsm/renderers/common/RenderList.js +186 -178
  440. package/examples/jsm/renderers/common/RenderLists.js +38 -38
  441. package/examples/jsm/renderers/common/RenderObject.js +178 -113
  442. package/examples/jsm/renderers/common/RenderObjects.js +91 -92
  443. package/examples/jsm/renderers/common/RenderPipeline.js +16 -16
  444. package/examples/jsm/renderers/common/Renderer.js +1062 -864
  445. package/examples/jsm/renderers/common/SampledTexture.js +83 -80
  446. package/examples/jsm/renderers/common/Sampler.js +18 -18
  447. package/examples/jsm/renderers/common/StorageBuffer.js +17 -17
  448. package/examples/jsm/renderers/common/StorageBufferAttribute.js +21 -0
  449. package/examples/jsm/renderers/common/StorageTexture.js +20 -0
  450. package/examples/jsm/renderers/common/Textures.js +354 -206
  451. package/examples/jsm/renderers/common/Uniform.js +140 -140
  452. package/examples/jsm/renderers/common/UniformBuffer.js +15 -15
  453. package/examples/jsm/renderers/common/UniformsGroup.js +299 -299
  454. package/examples/jsm/renderers/common/nodes/NodeBuilderState.js +44 -0
  455. package/examples/jsm/renderers/common/nodes/NodeSampledTexture.js +49 -39
  456. package/examples/jsm/renderers/common/nodes/NodeSampler.js +15 -21
  457. package/examples/jsm/renderers/common/nodes/NodeUniform.js +135 -135
  458. package/examples/jsm/renderers/common/nodes/NodeUniformsGroup.js +44 -0
  459. package/examples/jsm/renderers/common/nodes/Nodes.js +495 -319
  460. package/examples/jsm/renderers/webgl/WebGLBackend.js +1290 -0
  461. package/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +679 -340
  462. package/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js +252 -0
  463. package/examples/jsm/renderers/webgl/utils/WebGLCapabilities.js +36 -0
  464. package/examples/jsm/renderers/webgl/utils/WebGLConstants.js +11 -0
  465. package/examples/jsm/renderers/webgl/utils/WebGLExtensions.js +36 -0
  466. package/examples/jsm/renderers/webgl/utils/WebGLState.js +738 -0
  467. package/examples/jsm/renderers/webgl/utils/WebGLTextureUtils.js +647 -0
  468. package/examples/jsm/renderers/webgl/utils/WebGLUtils.js +284 -0
  469. package/examples/jsm/renderers/webgl-legacy/nodes/GLSL1NodeBuilder.js +320 -0
  470. package/examples/jsm/renderers/{webgl → webgl-legacy}/nodes/SlotNode.js +26 -26
  471. package/examples/jsm/renderers/{webgl → webgl-legacy}/nodes/WebGLNodeBuilder.js +794 -764
  472. package/examples/jsm/renderers/{webgl → webgl-legacy}/nodes/WebGLNodes.js +51 -49
  473. package/examples/jsm/renderers/webgpu/WebGPUBackend.js +1321 -847
  474. package/examples/jsm/renderers/webgpu/WebGPURenderer.js +53 -32
  475. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +1098 -878
  476. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js +104 -104
  477. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeParser.js +14 -14
  478. package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +287 -255
  479. package/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +244 -145
  480. package/examples/jsm/renderers/webgpu/utils/WebGPUConstants.js +324 -322
  481. package/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js +570 -580
  482. package/examples/jsm/renderers/webgpu/utils/WebGPUTexturePassUtils.js +285 -0
  483. package/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +1040 -937
  484. package/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js +93 -92
  485. package/examples/jsm/shaders/ACESFilmicToneMappingShader.js +89 -87
  486. package/examples/jsm/shaders/AfterimageShader.js +58 -56
  487. package/examples/jsm/shaders/BasicShader.js +29 -27
  488. package/examples/jsm/shaders/BleachBypassShader.js +62 -62
  489. package/examples/jsm/shaders/BlendShader.js +49 -47
  490. package/examples/jsm/shaders/BokehShader.js +145 -143
  491. package/examples/jsm/shaders/BokehShader2.js +397 -393
  492. package/examples/jsm/shaders/BrightnessContrastShader.js +56 -54
  493. package/examples/jsm/shaders/ColorCorrectionShader.js +52 -50
  494. package/examples/jsm/shaders/ColorifyShader.js +51 -51
  495. package/examples/jsm/shaders/ConvolutionShader.js +103 -103
  496. package/examples/jsm/shaders/CopyShader.js +45 -45
  497. package/examples/jsm/shaders/DOFMipMapShader.js +56 -54
  498. package/examples/jsm/shaders/DepthLimitedBlurShader.js +171 -166
  499. package/examples/jsm/shaders/DigitalGlitch.js +101 -101
  500. package/examples/jsm/shaders/DotScreenShader.js +70 -70
  501. package/examples/jsm/shaders/ExposureShader.js +44 -44
  502. package/examples/jsm/shaders/FXAAShader.js +288 -286
  503. package/examples/jsm/shaders/FilmShader.js +59 -102
  504. package/examples/jsm/shaders/FocusShader.js +89 -87
  505. package/examples/jsm/shaders/FreiChenShader.js +96 -94
  506. package/examples/jsm/shaders/GTAOShader.js +424 -0
  507. package/examples/jsm/shaders/GammaCorrectionShader.js +43 -43
  508. package/examples/jsm/shaders/GodRaysShader.js +321 -313
  509. package/examples/jsm/shaders/HalftoneShader.js +312 -310
  510. package/examples/jsm/shaders/HorizontalBlurShader.js +59 -59
  511. package/examples/jsm/shaders/HorizontalTiltShiftShader.js +63 -61
  512. package/examples/jsm/shaders/HueSaturationShader.js +67 -65
  513. package/examples/jsm/shaders/KaleidoShader.js +58 -56
  514. package/examples/jsm/shaders/LuminosityHighPassShader.js +66 -64
  515. package/examples/jsm/shaders/LuminosityShader.js +48 -46
  516. package/examples/jsm/shaders/MMDToonShader.js +134 -132
  517. package/examples/jsm/shaders/MirrorShader.js +56 -54
  518. package/examples/jsm/shaders/NormalMapShader.js +55 -53
  519. package/examples/jsm/shaders/OutputShader.js +81 -61
  520. package/examples/jsm/shaders/PoissonDenoiseShader.js +226 -0
  521. package/examples/jsm/shaders/RGBShiftShader.js +54 -54
  522. package/examples/jsm/shaders/SAOShader.js +179 -188
  523. package/examples/jsm/shaders/SMAAShader.js +466 -460
  524. package/examples/jsm/shaders/SSAOShader.js +300 -288
  525. package/examples/jsm/shaders/SSRShader.js +370 -364
  526. package/examples/jsm/shaders/SepiaShader.js +52 -52
  527. package/examples/jsm/shaders/SobelOperatorShader.js +92 -90
  528. package/examples/jsm/shaders/SubsurfaceScatteringShader.js +90 -88
  529. package/examples/jsm/shaders/TechnicolorShader.js +45 -43
  530. package/examples/jsm/shaders/ToonShader.js +326 -326
  531. package/examples/jsm/shaders/TriangleBlurShader.js +74 -72
  532. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +47 -45
  533. package/examples/jsm/shaders/VelocityShader.js +130 -128
  534. package/examples/jsm/shaders/VerticalBlurShader.js +59 -59
  535. package/examples/jsm/shaders/VerticalTiltShiftShader.js +63 -61
  536. package/examples/jsm/shaders/VignetteShader.js +51 -51
  537. package/examples/jsm/shaders/VolumeShader.js +289 -289
  538. package/examples/jsm/shaders/WaterRefractionShader.js +95 -93
  539. package/examples/jsm/textures/FlakesTexture.js +40 -40
  540. package/examples/jsm/transpiler/AST.js +270 -0
  541. package/examples/jsm/transpiler/GLSLDecoder.js +941 -0
  542. package/examples/jsm/transpiler/ShaderToyDecoder.js +49 -0
  543. package/examples/jsm/transpiler/TSLEncoder.js +715 -0
  544. package/examples/jsm/transpiler/Transpiler.js +18 -0
  545. package/examples/jsm/utils/BufferGeometryUtils.js +1371 -1364
  546. package/examples/jsm/utils/CameraUtils.js +73 -73
  547. package/examples/jsm/utils/GPUStatsPanel.js +128 -128
  548. package/examples/jsm/utils/GeometryCompressionUtils.js +639 -639
  549. package/examples/jsm/utils/GeometryUtils.js +221 -221
  550. package/examples/jsm/utils/LDrawUtils.js +202 -202
  551. package/examples/jsm/utils/PackedPhongMaterial.js +178 -178
  552. package/examples/jsm/utils/SceneUtils.js +254 -254
  553. package/examples/jsm/utils/ShadowMapViewer.js +210 -210
  554. package/examples/jsm/utils/SkeletonUtils.js +413 -413
  555. package/examples/jsm/utils/SortUtils.js +160 -0
  556. package/examples/jsm/utils/TextureUtils.js +98 -86
  557. package/examples/jsm/utils/UVsDebug.js +165 -165
  558. package/examples/jsm/utils/WorkerPool.js +102 -102
  559. package/examples/jsm/webxr/ARButton.js +232 -208
  560. package/examples/jsm/webxr/OculusHandModel.js +109 -109
  561. package/examples/jsm/webxr/OculusHandPointerModel.js +416 -415
  562. package/examples/jsm/webxr/Text2D.js +38 -38
  563. package/examples/jsm/webxr/VRButton.js +225 -200
  564. package/examples/jsm/webxr/XRButton.js +224 -198
  565. package/examples/jsm/webxr/XRControllerModelFactory.js +315 -310
  566. package/examples/jsm/webxr/XREstimatedLight.js +223 -223
  567. package/examples/jsm/webxr/XRHandMeshModel.js +116 -113
  568. package/examples/jsm/webxr/XRHandModelFactory.js +105 -105
  569. package/examples/jsm/webxr/XRHandPrimitiveModel.js +105 -104
  570. package/examples/jsm/webxr/XRPlanes.js +100 -100
  571. package/package.json +129 -126
  572. package/src/Three.Legacy.js +1 -1
  573. package/src/Three.js +184 -182
  574. package/src/animation/AnimationAction.js +700 -700
  575. package/src/animation/AnimationClip.js +473 -473
  576. package/src/animation/AnimationMixer.js +770 -770
  577. package/src/animation/AnimationObjectGroup.js +387 -387
  578. package/src/animation/AnimationUtils.js +356 -373
  579. package/src/animation/KeyframeTrack.js +462 -462
  580. package/src/animation/PropertyBinding.js +719 -719
  581. package/src/animation/PropertyMixer.js +318 -318
  582. package/src/animation/tracks/BooleanKeyframeTrack.js +19 -19
  583. package/src/animation/tracks/ColorKeyframeTrack.js +15 -15
  584. package/src/animation/tracks/NumberKeyframeTrack.js +12 -12
  585. package/src/animation/tracks/QuaternionKeyframeTrack.js +23 -23
  586. package/src/animation/tracks/StringKeyframeTrack.js +15 -15
  587. package/src/animation/tracks/VectorKeyframeTrack.js +12 -12
  588. package/src/audio/Audio.js +400 -396
  589. package/src/audio/AudioAnalyser.js +40 -40
  590. package/src/audio/AudioContext.js +25 -25
  591. package/src/audio/AudioListener.js +140 -137
  592. package/src/audio/PositionalAudio.js +146 -146
  593. package/src/cameras/ArrayCamera.js +17 -17
  594. package/src/cameras/Camera.js +69 -73
  595. package/src/cameras/CubeCamera.js +173 -170
  596. package/src/cameras/OrthographicCamera.js +136 -136
  597. package/src/cameras/PerspectiveCamera.js +268 -233
  598. package/src/cameras/StereoCamera.js +100 -100
  599. package/src/constants.js +216 -201
  600. package/src/core/BufferAttribute.js +650 -610
  601. package/src/core/BufferGeometry.js +1079 -1079
  602. package/src/core/Clock.js +74 -74
  603. package/src/core/EventDispatcher.js +87 -87
  604. package/src/core/GLBufferAttribute.js +60 -60
  605. package/src/core/InstancedBufferAttribute.js +39 -39
  606. package/src/core/InstancedBufferGeometry.js +40 -40
  607. package/src/core/InstancedInterleavedBuffer.js +48 -48
  608. package/src/core/InterleavedBuffer.js +166 -145
  609. package/src/core/InterleavedBufferAttribute.js +351 -331
  610. package/src/core/Layers.js +60 -60
  611. package/src/core/Object3D.js +1008 -973
  612. package/src/core/Raycaster.js +110 -110
  613. package/src/core/RenderTarget.js +131 -0
  614. package/src/core/Uniform.js +17 -17
  615. package/src/core/UniformsGroup.js +98 -92
  616. package/src/extras/DataUtils.js +176 -176
  617. package/src/extras/Earcut.js +789 -789
  618. package/src/extras/ImageUtils.js +129 -129
  619. package/src/extras/PMREMGenerator.js +910 -903
  620. package/src/extras/ShapeUtils.js +92 -92
  621. package/src/extras/core/Curve.js +416 -416
  622. package/src/extras/core/CurvePath.js +255 -252
  623. package/src/extras/core/Interpolations.js +79 -79
  624. package/src/extras/core/Path.js +196 -196
  625. package/src/extras/core/Shape.js +102 -102
  626. package/src/extras/core/ShapePath.js +291 -291
  627. package/src/extras/curves/ArcCurve.js +17 -17
  628. package/src/extras/curves/CatmullRomCurve3.js +255 -255
  629. package/src/extras/curves/CubicBezierCurve.js +78 -78
  630. package/src/extras/curves/CubicBezierCurve3.js +79 -79
  631. package/src/extras/curves/Curves.js +10 -10
  632. package/src/extras/curves/EllipseCurve.js +156 -156
  633. package/src/extras/curves/LineCurve.js +92 -92
  634. package/src/extras/curves/LineCurve3.js +92 -88
  635. package/src/extras/curves/QuadraticBezierCurve.js +74 -74
  636. package/src/extras/curves/QuadraticBezierCurve3.js +75 -75
  637. package/src/extras/curves/SplineCurve.js +97 -97
  638. package/src/geometries/BoxGeometry.js +180 -180
  639. package/src/geometries/CapsuleGeometry.js +33 -33
  640. package/src/geometries/CircleGeometry.js +101 -101
  641. package/src/geometries/ConeGeometry.js +31 -31
  642. package/src/geometries/CylinderGeometry.js +286 -286
  643. package/src/geometries/DodecahedronGeometry.js +66 -66
  644. package/src/geometries/EdgesGeometry.js +152 -152
  645. package/src/geometries/ExtrudeGeometry.js +814 -814
  646. package/src/geometries/Geometries.js +21 -21
  647. package/src/geometries/IcosahedronGeometry.js +42 -42
  648. package/src/geometries/LatheGeometry.js +189 -189
  649. package/src/geometries/OctahedronGeometry.js +37 -37
  650. package/src/geometries/PlaneGeometry.js +98 -98
  651. package/src/geometries/PolyhedronGeometry.js +319 -319
  652. package/src/geometries/RingGeometry.js +128 -128
  653. package/src/geometries/ShapeGeometry.js +195 -195
  654. package/src/geometries/SphereGeometry.js +137 -137
  655. package/src/geometries/TetrahedronGeometry.js +34 -34
  656. package/src/geometries/TorusGeometry.js +120 -120
  657. package/src/geometries/TorusKnotGeometry.js +167 -167
  658. package/src/geometries/TubeGeometry.js +203 -203
  659. package/src/geometries/WireframeGeometry.js +147 -147
  660. package/src/helpers/ArrowHelper.js +114 -114
  661. package/src/helpers/AxesHelper.js +68 -68
  662. package/src/helpers/Box3Helper.js +55 -55
  663. package/src/helpers/BoxHelper.js +113 -113
  664. package/src/helpers/CameraHelper.js +269 -269
  665. package/src/helpers/DirectionalLightHelper.js +93 -93
  666. package/src/helpers/GridHelper.js +56 -56
  667. package/src/helpers/HemisphereLightHelper.js +88 -88
  668. package/src/helpers/PlaneHelper.js +63 -63
  669. package/src/helpers/PointLightHelper.js +92 -92
  670. package/src/helpers/PolarGridHelper.js +96 -96
  671. package/src/helpers/SkeletonHelper.js +128 -128
  672. package/src/helpers/SpotLightHelper.js +94 -94
  673. package/src/lights/AmbientLight.js +17 -17
  674. package/src/lights/DirectionalLight.js +43 -43
  675. package/src/lights/DirectionalLightShadow.js +16 -16
  676. package/src/lights/HemisphereLight.js +34 -34
  677. package/src/lights/Light.js +58 -58
  678. package/src/lights/LightProbe.js +47 -47
  679. package/src/lights/LightShadow.js +147 -147
  680. package/src/lights/PointLight.js +57 -57
  681. package/src/lights/PointLightShadow.js +96 -96
  682. package/src/lights/RectAreaLight.js +56 -56
  683. package/src/lights/SpotLight.js +71 -71
  684. package/src/lights/SpotLightShadow.js +50 -50
  685. package/src/loaders/AnimationLoader.js +66 -66
  686. package/src/loaders/AudioLoader.js +66 -66
  687. package/src/loaders/BufferGeometryLoader.js +217 -224
  688. package/src/loaders/Cache.js +42 -42
  689. package/src/loaders/CompressedTextureLoader.js +134 -134
  690. package/src/loaders/CubeTextureLoader.js +58 -58
  691. package/src/loaders/DataTextureLoader.js +135 -118
  692. package/src/loaders/FileLoader.js +284 -284
  693. package/src/loaders/ImageBitmapLoader.js +123 -99
  694. package/src/loaders/ImageLoader.js +91 -91
  695. package/src/loaders/Loader.js +72 -72
  696. package/src/loaders/LoaderUtils.js +75 -75
  697. package/src/loaders/LoadingManager.js +142 -142
  698. package/src/loaders/MaterialLoader.js +372 -364
  699. package/src/loaders/ObjectLoader.js +1148 -1093
  700. package/src/loaders/TextureLoader.js +41 -41
  701. package/src/materials/LineBasicMaterial.js +53 -49
  702. package/src/materials/LineDashedMaterial.js +35 -35
  703. package/src/materials/Material.js +522 -508
  704. package/src/materials/Materials.js +39 -39
  705. package/src/materials/MeshBasicMaterial.js +85 -81
  706. package/src/materials/MeshDepthMaterial.js +54 -54
  707. package/src/materials/MeshDistanceMaterial.js +43 -43
  708. package/src/materials/MeshLambertMaterial.js +120 -116
  709. package/src/materials/MeshMatcapMaterial.js +85 -81
  710. package/src/materials/MeshNormalMaterial.js +61 -61
  711. package/src/materials/MeshPhongMaterial.js +124 -120
  712. package/src/materials/MeshPhysicalMaterial.js +224 -224
  713. package/src/materials/MeshStandardMaterial.js +128 -124
  714. package/src/materials/MeshToonMaterial.js +106 -102
  715. package/src/materials/PointsMaterial.js +54 -50
  716. package/src/materials/RawShaderMaterial.js +17 -17
  717. package/src/materials/ShaderMaterial.js +190 -187
  718. package/src/materials/ShadowMaterial.js +37 -37
  719. package/src/materials/SpriteMaterial.js +54 -54
  720. package/src/math/Box2.js +204 -204
  721. package/src/math/Box3.js +534 -517
  722. package/src/math/Color.js +623 -627
  723. package/src/math/ColorManagement.js +139 -133
  724. package/src/math/Cylindrical.js +61 -61
  725. package/src/math/Euler.js +315 -315
  726. package/src/math/Frustum.js +186 -186
  727. package/src/math/Interpolant.js +241 -241
  728. package/src/math/Line3.js +115 -115
  729. package/src/math/MathUtils.js +363 -363
  730. package/src/math/Matrix3.js +388 -388
  731. package/src/math/Matrix4.js +915 -915
  732. package/src/math/Plane.js +205 -205
  733. package/src/math/Quaternion.js +685 -684
  734. package/src/math/Ray.js +493 -493
  735. package/src/math/Sphere.js +245 -243
  736. package/src/math/Spherical.js +86 -86
  737. package/src/math/SphericalHarmonics3.js +243 -243
  738. package/src/math/Triangle.js +311 -329
  739. package/src/math/Vector2.js +480 -480
  740. package/src/math/Vector3.js +724 -725
  741. package/src/math/Vector4.js +644 -644
  742. package/src/math/interpolants/CubicInterpolant.js +150 -150
  743. package/src/math/interpolants/DiscreteInterpolant.js +26 -26
  744. package/src/math/interpolants/LinearInterpolant.js +38 -38
  745. package/src/math/interpolants/QuaternionLinearInterpolant.js +39 -39
  746. package/src/objects/BatchedMesh.js +1019 -0
  747. package/src/objects/Bone.js +17 -17
  748. package/src/objects/Group.js +17 -17
  749. package/src/objects/InstancedMesh.js +214 -214
  750. package/src/objects/LOD.js +214 -214
  751. package/src/objects/Line.js +222 -222
  752. package/src/objects/LineLoop.js +17 -17
  753. package/src/objects/LineSegments.js +55 -55
  754. package/src/objects/Mesh.js +429 -429
  755. package/src/objects/Points.js +166 -166
  756. package/src/objects/Skeleton.js +277 -279
  757. package/src/objects/SkinnedMesh.js +257 -266
  758. package/src/objects/Sprite.js +181 -181
  759. package/src/renderers/WebGL1Renderer.js +7 -7
  760. package/src/renderers/WebGL3DRenderTarget.js +22 -22
  761. package/src/renderers/WebGLArrayRenderTarget.js +22 -22
  762. package/src/renderers/WebGLCubeRenderTarget.js +155 -155
  763. package/src/renderers/WebGLMultipleRenderTargets.js +82 -84
  764. package/src/renderers/WebGLRenderTarget.js +15 -122
  765. package/src/renderers/WebGLRenderer.js +2631 -2439
  766. package/src/renderers/shaders/ShaderChunk/alphahash_fragment.glsl.js +7 -7
  767. package/src/renderers/shaders/ShaderChunk/alphahash_pars_fragment.glsl.js +68 -68
  768. package/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl.js +7 -7
  769. package/src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl.js +7 -7
  770. package/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl.js +16 -7
  771. package/src/renderers/shaders/ShaderChunk/alphatest_pars_fragment.glsl.js +5 -5
  772. package/src/renderers/shaders/ShaderChunk/aomap_fragment.glsl.js +26 -18
  773. package/src/renderers/shaders/ShaderChunk/aomap_pars_fragment.glsl.js +8 -8
  774. package/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js +19 -0
  775. package/src/renderers/shaders/ShaderChunk/batching_vertex.glsl.js +5 -0
  776. package/src/renderers/shaders/ShaderChunk/begin_vertex.glsl.js +9 -9
  777. package/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl.js +9 -9
  778. package/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +33 -33
  779. package/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl.js +43 -42
  780. package/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js +7 -7
  781. package/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js +10 -10
  782. package/src/renderers/shaders/ShaderChunk/clearcoat_pars_fragment.glsl.js +21 -21
  783. package/src/renderers/shaders/ShaderChunk/clipping_planes_fragment.glsl.js +78 -33
  784. package/src/renderers/shaders/ShaderChunk/clipping_planes_pars_fragment.glsl.js +9 -9
  785. package/src/renderers/shaders/ShaderChunk/clipping_planes_pars_vertex.glsl.js +7 -7
  786. package/src/renderers/shaders/ShaderChunk/clipping_planes_vertex.glsl.js +7 -7
  787. package/src/renderers/shaders/ShaderChunk/color_fragment.glsl.js +11 -11
  788. package/src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl.js +11 -11
  789. package/src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js +11 -11
  790. package/src/renderers/shaders/ShaderChunk/color_vertex.glsl.js +23 -23
  791. package/src/renderers/shaders/ShaderChunk/colorspace_fragment.glsl.js +3 -3
  792. package/src/renderers/shaders/ShaderChunk/colorspace_pars_fragment.glsl.js +44 -11
  793. package/src/renderers/shaders/ShaderChunk/common.glsl.js +147 -156
  794. package/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +186 -191
  795. package/src/renderers/shaders/ShaderChunk/default_fragment.glsl.js +5 -5
  796. package/src/renderers/shaders/ShaderChunk/default_vertex.glsl.js +5 -5
  797. package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +63 -36
  798. package/src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl.js +9 -9
  799. package/src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl.js +7 -7
  800. package/src/renderers/shaders/ShaderChunk/dithering_fragment.glsl.js +7 -7
  801. package/src/renderers/shaders/ShaderChunk/dithering_pars_fragment.glsl.js +20 -20
  802. package/src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl.js +9 -9
  803. package/src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl.js +7 -7
  804. package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +14 -14
  805. package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +62 -62
  806. package/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js +21 -21
  807. package/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js +22 -22
  808. package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +69 -69
  809. package/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js +37 -37
  810. package/src/renderers/shaders/ShaderChunk/fog_fragment.glsl.js +17 -17
  811. package/src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl.js +19 -19
  812. package/src/renderers/shaders/ShaderChunk/fog_pars_vertex.glsl.js +7 -7
  813. package/src/renderers/shaders/ShaderChunk/fog_vertex.glsl.js +7 -7
  814. package/src/renderers/shaders/ShaderChunk/gradientmap_pars_fragment.glsl.js +27 -27
  815. package/src/renderers/shaders/ShaderChunk/iridescence_fragment.glsl.js +120 -121
  816. package/src/renderers/shaders/ShaderChunk/iridescence_pars_fragment.glsl.js +14 -14
  817. package/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl.js +10 -10
  818. package/src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl.js +8 -8
  819. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +202 -198
  820. package/src/renderers/shaders/ShaderChunk/lights_fragment_end.glsl.js +13 -13
  821. package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +40 -40
  822. package/src/renderers/shaders/ShaderChunk/lights_lambert_fragment.glsl.js +5 -5
  823. package/src/renderers/shaders/ShaderChunk/lights_lambert_pars_fragment.glsl.js +28 -28
  824. package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +228 -223
  825. package/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl.js +7 -7
  826. package/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl.js +32 -32
  827. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +151 -146
  828. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +562 -560
  829. package/src/renderers/shaders/ShaderChunk/lights_toon_fragment.glsl.js +4 -4
  830. package/src/renderers/shaders/ShaderChunk/lights_toon_pars_fragment.glsl.js +26 -26
  831. package/src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl.js +9 -9
  832. package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl.js +9 -9
  833. package/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl.js +16 -16
  834. package/src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl.js +22 -22
  835. package/src/renderers/shaders/ShaderChunk/map_fragment.glsl.js +21 -13
  836. package/src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl.js +11 -11
  837. package/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl.js +27 -27
  838. package/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl.js +27 -27
  839. package/src/renderers/shaders/ShaderChunk/metalnessmap_fragment.glsl.js +12 -12
  840. package/src/renderers/shaders/ShaderChunk/metalnessmap_pars_fragment.glsl.js +7 -7
  841. package/src/renderers/shaders/ShaderChunk/morphcolor_vertex.glsl.js +24 -24
  842. package/src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl.js +27 -27
  843. package/src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl.js +38 -38
  844. package/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl.js +36 -36
  845. package/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js +76 -76
  846. package/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js +33 -33
  847. package/src/renderers/shaders/ShaderChunk/normal_pars_fragment.glsl.js +14 -14
  848. package/src/renderers/shaders/ShaderChunk/normal_pars_vertex.glsl.js +14 -14
  849. package/src/renderers/shaders/ShaderChunk/normal_vertex.glsl.js +14 -14
  850. package/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js +43 -43
  851. package/src/renderers/shaders/ShaderChunk/occlusion_fragment.glsl.js +20 -0
  852. package/src/renderers/shaders/ShaderChunk/occlusion_pars_fragment.glsl.js +97 -0
  853. package/src/renderers/shaders/ShaderChunk/opaque_fragment.glsl.js +11 -11
  854. package/src/renderers/shaders/ShaderChunk/packing.glsl.js +68 -68
  855. package/src/renderers/shaders/ShaderChunk/premultiplied_alpha_fragment.glsl.js +8 -8
  856. package/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js +19 -13
  857. package/src/renderers/shaders/ShaderChunk/roughnessmap_fragment.glsl.js +12 -12
  858. package/src/renderers/shaders/ShaderChunk/roughnessmap_pars_fragment.glsl.js +7 -7
  859. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +314 -314
  860. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js +68 -68
  861. package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +68 -68
  862. package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +66 -66
  863. package/src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl.js +10 -10
  864. package/src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl.js +25 -33
  865. package/src/renderers/shaders/ShaderChunk/skinning_vertex.glsl.js +15 -15
  866. package/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl.js +20 -20
  867. package/src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl.js +14 -14
  868. package/src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl.js +7 -7
  869. package/src/renderers/shaders/ShaderChunk/tonemapping_fragment.glsl.js +7 -7
  870. package/src/renderers/shaders/ShaderChunk/tonemapping_pars_fragment.glsl.js +169 -77
  871. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +36 -36
  872. package/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js +201 -201
  873. package/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js +119 -119
  874. package/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js +145 -145
  875. package/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js +122 -122
  876. package/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js +21 -15
  877. package/src/renderers/shaders/ShaderChunk.js +274 -266
  878. package/src/renderers/shaders/ShaderLib/background.glsl.js +40 -32
  879. package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +62 -62
  880. package/src/renderers/shaders/ShaderLib/cube.glsl.js +36 -36
  881. package/src/renderers/shaders/ShaderLib/depth.glsl.js +95 -94
  882. package/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js +76 -75
  883. package/src/renderers/shaders/ShaderLib/equirect.glsl.js +35 -35
  884. package/src/renderers/shaders/ShaderLib/linedashed.glsl.js +77 -75
  885. package/src/renderers/shaders/ShaderLib/meshbasic.glsl.js +117 -114
  886. package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +126 -122
  887. package/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js +113 -109
  888. package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +89 -82
  889. package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +128 -124
  890. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +226 -222
  891. package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +120 -116
  892. package/src/renderers/shaders/ShaderLib/points.glsl.js +88 -86
  893. package/src/renderers/shaders/ShaderLib/shadow.glsl.js +57 -54
  894. package/src/renderers/shaders/ShaderLib/sprite.glsl.js +81 -81
  895. package/src/renderers/shaders/ShaderLib/vsm.glsl.js +53 -53
  896. package/src/renderers/shaders/ShaderLib.js +367 -359
  897. package/src/renderers/shaders/UniformsLib.js +236 -230
  898. package/src/renderers/shaders/UniformsUtils.js +104 -104
  899. package/src/renderers/webgl/WebGLAnimation.js +53 -53
  900. package/src/renderers/webgl/WebGLAttributes.js +229 -195
  901. package/src/renderers/webgl/WebGLBackground.js +239 -247
  902. package/src/renderers/webgl/WebGLBindingStates.js +631 -631
  903. package/src/renderers/webgl/WebGLBufferRenderer.js +92 -61
  904. package/src/renderers/webgl/WebGLCapabilities.js +120 -120
  905. package/src/renderers/webgl/WebGLClipping.js +171 -171
  906. package/src/renderers/webgl/WebGLCubeMaps.js +99 -99
  907. package/src/renderers/webgl/WebGLCubeUVMaps.js +132 -130
  908. package/src/renderers/webgl/WebGLExtensions.js +97 -96
  909. package/src/renderers/webgl/WebGLGeometries.js +211 -207
  910. package/src/renderers/webgl/WebGLIndexedBufferRenderer.js +102 -71
  911. package/src/renderers/webgl/WebGLInfo.js +71 -71
  912. package/src/renderers/webgl/WebGLLights.js +590 -570
  913. package/src/renderers/webgl/WebGLMaterials.js +576 -567
  914. package/src/renderers/webgl/WebGLMorphtargets.js +300 -300
  915. package/src/renderers/webgl/WebGLObjects.js +92 -92
  916. package/src/renderers/webgl/WebGLProgram.js +1112 -1002
  917. package/src/renderers/webgl/WebGLPrograms.js +663 -625
  918. package/src/renderers/webgl/WebGLProperties.js +48 -48
  919. package/src/renderers/webgl/WebGLRenderLists.js +238 -238
  920. package/src/renderers/webgl/WebGLRenderStates.js +107 -107
  921. package/src/renderers/webgl/WebGLShader.js +12 -12
  922. package/src/renderers/webgl/WebGLShaderCache.js +124 -124
  923. package/src/renderers/webgl/WebGLShadowMap.js +424 -389
  924. package/src/renderers/webgl/WebGLState.js +1328 -1307
  925. package/src/renderers/webgl/WebGLTextures.js +2117 -2017
  926. package/src/renderers/webgl/WebGLUniforms.js +1156 -1146
  927. package/src/renderers/webgl/WebGLUniformsGroups.js +392 -413
  928. package/src/renderers/webgl/WebGLUtils.js +283 -278
  929. package/src/renderers/webxr/WebXRController.js +343 -343
  930. package/src/renderers/webxr/WebXRManager.js +840 -770
  931. package/src/scenes/Fog.js +38 -37
  932. package/src/scenes/FogExp2.js +35 -34
  933. package/src/scenes/Scene.js +63 -63
  934. package/src/textures/CanvasTexture.js +17 -17
  935. package/src/textures/CompressedArrayTexture.js +18 -18
  936. package/src/textures/CompressedCubeTexture.js +19 -0
  937. package/src/textures/CompressedTexture.js +28 -28
  938. package/src/textures/CubeTexture.js +33 -33
  939. package/src/textures/Data3DTexture.js +35 -35
  940. package/src/textures/DataArrayTexture.js +27 -27
  941. package/src/textures/DataTexture.js +22 -22
  942. package/src/textures/DepthTexture.js +58 -58
  943. package/src/textures/FramebufferTexture.js +23 -23
  944. package/src/textures/Source.js +127 -127
  945. package/src/textures/Texture.js +338 -338
  946. package/src/textures/VideoTexture.js +55 -55
  947. package/src/utils.js +91 -83
  948. package/build/three.js +0 -51661
  949. package/build/three.min.js +0 -7
  950. package/examples/jsm/nodes/accessors/ExtendedMaterialNode.js +0 -64
  951. package/examples/jsm/nodes/functions/BSDF/BRDF_BlinnPhong.js +0 -30
  952. package/examples/jsm/objects/GroundProjectedSkybox.js +0 -172
  953. package/examples/jsm/renderers/common/RenderTarget.js +0 -15
  954. package/examples/jsm/renderers/common/nodes/NodeRender.js +0 -302
  955. package/examples/jsm/renderers/webgpu/utils/WebGPUTextureMipmapUtils.js +0 -163
  956. package/src/lights/AmbientLightProbe.js +0 -21
  957. package/src/lights/HemisphereLightProbe.js +0 -30
@@ -1,2464 +1,2470 @@
1
- import {
2
- BufferAttribute,
3
- BufferGeometry,
4
- Color,
5
- FileLoader,
6
- Group,
7
- LineBasicMaterial,
8
- LineSegments,
9
- Loader,
10
- Matrix4,
11
- Mesh,
12
- MeshStandardMaterial,
13
- ShaderMaterial,
14
- SRGBColorSpace,
15
- UniformsLib,
16
- UniformsUtils,
17
- Vector3,
18
- Ray
19
- } from 'three';
20
-
21
- // Special surface finish tag types.
22
- // Note: "MATERIAL" tag (e.g. GLITTER, SPECKLE) is not implemented
23
- const FINISH_TYPE_DEFAULT = 0;
24
- const FINISH_TYPE_CHROME = 1;
25
- const FINISH_TYPE_PEARLESCENT = 2;
26
- const FINISH_TYPE_RUBBER = 3;
27
- const FINISH_TYPE_MATTE_METALLIC = 4;
28
- const FINISH_TYPE_METAL = 5;
29
-
30
- // State machine to search a subobject path.
31
- // The LDraw standard establishes these various possible subfolders.
32
- const FILE_LOCATION_TRY_PARTS = 0;
33
- const FILE_LOCATION_TRY_P = 1;
34
- const FILE_LOCATION_TRY_MODELS = 2;
35
- const FILE_LOCATION_AS_IS = 3;
36
- const FILE_LOCATION_TRY_RELATIVE = 4;
37
- const FILE_LOCATION_TRY_ABSOLUTE = 5;
38
- const FILE_LOCATION_NOT_FOUND = 6;
39
-
40
- const MAIN_COLOUR_CODE = '16';
41
- const MAIN_EDGE_COLOUR_CODE = '24';
42
-
43
- const COLOR_SPACE_LDRAW = SRGBColorSpace;
44
-
45
- const _tempVec0 = new Vector3();
46
- const _tempVec1 = new Vector3();
47
-
48
- class LDrawConditionalLineMaterial extends ShaderMaterial {
49
-
50
- constructor( parameters ) {
51
-
52
- super( {
53
-
54
- uniforms: UniformsUtils.merge( [
55
- UniformsLib.fog,
56
- {
57
- diffuse: {
58
- value: new Color()
59
- },
60
- opacity: {
61
- value: 1.0
62
- }
63
- }
64
- ] ),
65
-
66
- vertexShader: /* glsl */`
67
- attribute vec3 control0;
68
- attribute vec3 control1;
69
- attribute vec3 direction;
70
- varying float discardFlag;
71
-
72
- #include <common>
73
- #include <color_pars_vertex>
74
- #include <fog_pars_vertex>
75
- #include <logdepthbuf_pars_vertex>
76
- #include <clipping_planes_pars_vertex>
77
- void main() {
78
- #include <color_vertex>
79
-
80
- vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
81
- gl_Position = projectionMatrix * mvPosition;
82
-
83
- // Transform the line segment ends and control points into camera clip space
84
- vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 );
85
- vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 );
86
- vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
87
- vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 );
88
-
89
- c0.xy /= c0.w;
90
- c1.xy /= c1.w;
91
- p0.xy /= p0.w;
92
- p1.xy /= p1.w;
93
-
94
- // Get the direction of the segment and an orthogonal vector
95
- vec2 dir = p1.xy - p0.xy;
96
- vec2 norm = vec2( -dir.y, dir.x );
97
-
98
- // Get control point directions from the line
99
- vec2 c0dir = c0.xy - p1.xy;
100
- vec2 c1dir = c1.xy - p1.xy;
101
-
102
- // If the vectors to the controls points are pointed in different directions away
103
- // from the line segment then the line should not be drawn.
104
- float d0 = dot( normalize( norm ), normalize( c0dir ) );
105
- float d1 = dot( normalize( norm ), normalize( c1dir ) );
106
- discardFlag = float( sign( d0 ) != sign( d1 ) );
107
-
108
- #include <logdepthbuf_vertex>
109
- #include <clipping_planes_vertex>
110
- #include <fog_vertex>
111
- }
112
- `,
113
-
114
- fragmentShader: /* glsl */`
115
- uniform vec3 diffuse;
116
- uniform float opacity;
117
- varying float discardFlag;
118
-
119
- #include <common>
120
- #include <color_pars_fragment>
121
- #include <fog_pars_fragment>
122
- #include <logdepthbuf_pars_fragment>
123
- #include <clipping_planes_pars_fragment>
124
- void main() {
125
-
126
- if ( discardFlag > 0.5 ) discard;
127
-
128
- #include <clipping_planes_fragment>
129
- vec3 outgoingLight = vec3( 0.0 );
130
- vec4 diffuseColor = vec4( diffuse, opacity );
131
- #include <logdepthbuf_fragment>
132
- #include <color_fragment>
133
- outgoingLight = diffuseColor.rgb; // simple shader
134
- gl_FragColor = vec4( outgoingLight, diffuseColor.a );
135
- #include <tonemapping_fragment>
136
- #include <colorspace_fragment>
137
- #include <fog_fragment>
138
- #include <premultiplied_alpha_fragment>
139
- }
140
- `,
141
-
142
- } );
143
-
144
- Object.defineProperties( this, {
145
-
146
- opacity: {
147
- get: function () {
148
-
149
- return this.uniforms.opacity.value;
150
-
151
- },
152
-
153
- set: function ( value ) {
154
-
155
- this.uniforms.opacity.value = value;
156
-
157
- }
158
- },
159
-
160
- color: {
161
- get: function () {
162
-
163
- return this.uniforms.diffuse.value;
164
-
165
- }
166
- }
167
-
168
- } );
169
-
170
- this.setValues( parameters );
171
- this.isLDrawConditionalLineMaterial = true;
172
-
173
- }
174
-
175
- }
176
-
177
- class ConditionalLineSegments extends LineSegments {
178
-
179
- constructor( geometry, material ) {
180
-
181
- super( geometry, material );
182
- this.isConditionalLine = true;
183
-
184
- }
185
-
186
- }
187
-
188
- function generateFaceNormals( faces ) {
189
-
190
- for ( let i = 0, l = faces.length; i < l; i ++ ) {
191
-
192
- const face = faces[ i ];
193
- const vertices = face.vertices;
194
- const v0 = vertices[ 0 ];
195
- const v1 = vertices[ 1 ];
196
- const v2 = vertices[ 2 ];
197
-
198
- _tempVec0.subVectors( v1, v0 );
199
- _tempVec1.subVectors( v2, v1 );
200
- face.faceNormal = new Vector3()
201
- .crossVectors( _tempVec0, _tempVec1 )
202
- .normalize();
203
-
204
- }
205
-
206
- }
207
-
208
- const _ray = new Ray();
209
- function smoothNormals( faces, lineSegments, checkSubSegments = false ) {
210
-
211
- // NOTE: 1e2 is pretty coarse but was chosen to quantize the resulting value because
212
- // it allows edges to be smoothed as expected (see minifig arms).
213
- // --
214
- // And the vector values are initialize multiplied by 1 + 1e-10 to account for floating
215
- // point errors on vertices along quantization boundaries. Ie after matrix multiplication
216
- // vertices that should be merged might be set to "1.7" and "1.6999..." meaning they won't
217
- // get merged. This added epsilon attempts to push these error values to the same quantized
218
- // value for the sake of hashing. See "AT-ST mini" dishes. See mrdoob/three#23169.
219
-
220
- const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
221
- function hashVertex( v ) {
222
-
223
- const x = ~ ~ ( v.x * hashMultiplier );
224
- const y = ~ ~ ( v.y * hashMultiplier );
225
- const z = ~ ~ ( v.z * hashMultiplier );
226
-
227
- return `${ x },${ y },${ z }`;
228
-
229
- }
230
-
231
- function hashEdge( v0, v1 ) {
232
-
233
- return `${ hashVertex( v0 ) }_${ hashVertex( v1 ) }`;
234
-
235
- }
236
-
237
- // converts the two vertices to a ray with a normalized direction and origin of 0, 0, 0 projected
238
- // onto the original line.
239
- function toNormalizedRay( v0, v1, targetRay ) {
240
-
241
- targetRay.direction.subVectors( v1, v0 ).normalize();
242
-
243
- const scalar = v0.dot( targetRay.direction );
244
- targetRay.origin.copy( v0 ).addScaledVector( targetRay.direction, - scalar );
245
-
246
- return targetRay;
247
-
248
- }
249
-
250
- function hashRay( ray ) {
251
-
252
- return hashEdge( ray.origin, ray.direction );
253
-
254
- }
255
-
256
- const hardEdges = new Set();
257
- const hardEdgeRays = new Map();
258
- const halfEdgeList = {};
259
- const normals = [];
260
-
261
- // Save the list of hard edges by hash
262
- for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
263
-
264
- const ls = lineSegments[ i ];
265
- const vertices = ls.vertices;
266
- const v0 = vertices[ 0 ];
267
- const v1 = vertices[ 1 ];
268
- hardEdges.add( hashEdge( v0, v1 ) );
269
- hardEdges.add( hashEdge( v1, v0 ) );
270
-
271
- // only generate the hard edge ray map if we're checking subsegments because it's more expensive to check
272
- // and requires more memory.
273
- if ( checkSubSegments ) {
274
-
275
- // add both ray directions to the map
276
- const ray = toNormalizedRay( v0, v1, new Ray() );
277
- const rh1 = hashRay( ray );
278
- if ( ! hardEdgeRays.has( rh1 ) ) {
279
-
280
- toNormalizedRay( v1, v0, ray );
281
- const rh2 = hashRay( ray );
282
-
283
- const info = {
284
- ray,
285
- distances: [],
286
- };
287
-
288
- hardEdgeRays.set( rh1, info );
289
- hardEdgeRays.set( rh2, info );
290
-
291
- }
292
-
293
- // store both segments ends in min, max order in the distances array to check if a face edge is a
294
- // subsegment later.
295
- const info = hardEdgeRays.get( rh1 );
296
- let d0 = info.ray.direction.dot( v0 );
297
- let d1 = info.ray.direction.dot( v1 );
298
- if ( d0 > d1 ) {
299
-
300
- [ d0, d1 ] = [ d1, d0 ];
301
-
302
- }
303
-
304
- info.distances.push( d0, d1 );
305
-
306
- }
307
-
308
- }
309
-
310
- // track the half edges associated with each triangle
311
- for ( let i = 0, l = faces.length; i < l; i ++ ) {
312
-
313
- const tri = faces[ i ];
314
- const vertices = tri.vertices;
315
- const vertCount = vertices.length;
316
- for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
317
-
318
- const index = i2;
319
- const next = ( i2 + 1 ) % vertCount;
320
- const v0 = vertices[ index ];
321
- const v1 = vertices[ next ];
322
- const hash = hashEdge( v0, v1 );
323
-
324
- // don't add the triangle if the edge is supposed to be hard
325
- if ( hardEdges.has( hash ) ) {
326
-
327
- continue;
328
-
329
- }
330
-
331
- // if checking subsegments then check to see if this edge lies on a hard edge ray and whether its within any ray bounds
332
- if ( checkSubSegments ) {
333
-
334
- toNormalizedRay( v0, v1, _ray );
335
-
336
- const rayHash = hashRay( _ray );
337
- if ( hardEdgeRays.has( rayHash ) ) {
338
-
339
- const info = hardEdgeRays.get( rayHash );
340
- const { ray, distances } = info;
341
- let d0 = ray.direction.dot( v0 );
342
- let d1 = ray.direction.dot( v1 );
343
-
344
- if ( d0 > d1 ) {
345
-
346
- [ d0, d1 ] = [ d1, d0 ];
347
-
348
- }
349
-
350
- // return early if the face edge is found to be a subsegment of a line edge meaning the edge will have "hard" normals
351
- let found = false;
352
- for ( let i = 0, l = distances.length; i < l; i += 2 ) {
353
-
354
- if ( d0 >= distances[ i ] && d1 <= distances[ i + 1 ] ) {
355
-
356
- found = true;
357
- break;
358
-
359
- }
360
-
361
- }
362
-
363
- if ( found ) {
364
-
365
- continue;
366
-
367
- }
368
-
369
- }
370
-
371
- }
372
-
373
- const info = {
374
- index: index,
375
- tri: tri
376
- };
377
- halfEdgeList[ hash ] = info;
378
-
379
- }
380
-
381
- }
382
-
383
- // Iterate until we've tried to connect all faces to share normals
384
- while ( true ) {
385
-
386
- // Stop if there are no more faces left
387
- let halfEdge = null;
388
- for ( const key in halfEdgeList ) {
389
-
390
- halfEdge = halfEdgeList[ key ];
391
- break;
392
-
393
- }
394
-
395
- if ( halfEdge === null ) {
396
-
397
- break;
398
-
399
- }
400
-
401
- // Exhaustively find all connected faces
402
- const queue = [ halfEdge ];
403
- while ( queue.length > 0 ) {
404
-
405
- // initialize all vertex normals in this triangle
406
- const tri = queue.pop().tri;
407
- const vertices = tri.vertices;
408
- const vertNormals = tri.normals;
409
- const faceNormal = tri.faceNormal;
410
-
411
- // Check if any edge is connected to another triangle edge
412
- const vertCount = vertices.length;
413
- for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
414
-
415
- const index = i2;
416
- const next = ( i2 + 1 ) % vertCount;
417
- const v0 = vertices[ index ];
418
- const v1 = vertices[ next ];
419
-
420
- // delete this triangle from the list so it won't be found again
421
- const hash = hashEdge( v0, v1 );
422
- delete halfEdgeList[ hash ];
423
-
424
- const reverseHash = hashEdge( v1, v0 );
425
- const otherInfo = halfEdgeList[ reverseHash ];
426
- if ( otherInfo ) {
427
-
428
- const otherTri = otherInfo.tri;
429
- const otherIndex = otherInfo.index;
430
- const otherNormals = otherTri.normals;
431
- const otherVertCount = otherNormals.length;
432
- const otherFaceNormal = otherTri.faceNormal;
433
-
434
- // NOTE: If the angle between faces is > 67.5 degrees then assume it's
435
- // hard edge. There are some cases where the line segments do not line up exactly
436
- // with or span multiple triangle edges (see Lunar Vehicle wheels).
437
- if ( Math.abs( otherTri.faceNormal.dot( tri.faceNormal ) ) < 0.25 ) {
438
-
439
- continue;
440
-
441
- }
442
-
443
- // if this triangle has already been traversed then it won't be in
444
- // the halfEdgeList. If it has not then add it to the queue and delete
445
- // it so it won't be found again.
446
- if ( reverseHash in halfEdgeList ) {
447
-
448
- queue.push( otherInfo );
449
- delete halfEdgeList[ reverseHash ];
450
-
451
- }
452
-
453
- // share the first normal
454
- const otherNext = ( otherIndex + 1 ) % otherVertCount;
455
- if (
456
- vertNormals[ index ] && otherNormals[ otherNext ] &&
457
- vertNormals[ index ] !== otherNormals[ otherNext ]
458
- ) {
459
-
460
- otherNormals[ otherNext ].norm.add( vertNormals[ index ].norm );
461
- vertNormals[ index ].norm = otherNormals[ otherNext ].norm;
462
-
463
- }
464
-
465
- let sharedNormal1 = vertNormals[ index ] || otherNormals[ otherNext ];
466
- if ( sharedNormal1 === null ) {
467
-
468
- // it's possible to encounter an edge of a triangle that has already been traversed meaning
469
- // both edges already have different normals defined and shared. To work around this we create
470
- // a wrapper object so when those edges are merged the normals can be updated everywhere.
471
- sharedNormal1 = { norm: new Vector3() };
472
- normals.push( sharedNormal1.norm );
473
-
474
- }
475
-
476
- if ( vertNormals[ index ] === null ) {
477
-
478
- vertNormals[ index ] = sharedNormal1;
479
- sharedNormal1.norm.add( faceNormal );
480
-
481
- }
482
-
483
- if ( otherNormals[ otherNext ] === null ) {
484
-
485
- otherNormals[ otherNext ] = sharedNormal1;
486
- sharedNormal1.norm.add( otherFaceNormal );
487
-
488
- }
489
-
490
- // share the second normal
491
- if (
492
- vertNormals[ next ] && otherNormals[ otherIndex ] &&
493
- vertNormals[ next ] !== otherNormals[ otherIndex ]
494
- ) {
495
-
496
- otherNormals[ otherIndex ].norm.add( vertNormals[ next ].norm );
497
- vertNormals[ next ].norm = otherNormals[ otherIndex ].norm;
498
-
499
- }
500
-
501
- let sharedNormal2 = vertNormals[ next ] || otherNormals[ otherIndex ];
502
- if ( sharedNormal2 === null ) {
503
-
504
- sharedNormal2 = { norm: new Vector3() };
505
- normals.push( sharedNormal2.norm );
506
-
507
- }
508
-
509
- if ( vertNormals[ next ] === null ) {
510
-
511
- vertNormals[ next ] = sharedNormal2;
512
- sharedNormal2.norm.add( faceNormal );
513
-
514
- }
515
-
516
- if ( otherNormals[ otherIndex ] === null ) {
517
-
518
- otherNormals[ otherIndex ] = sharedNormal2;
519
- sharedNormal2.norm.add( otherFaceNormal );
520
-
521
- }
522
-
523
- }
524
-
525
- }
526
-
527
- }
528
-
529
- }
530
-
531
- // The normals of each face have been added up so now we average them by normalizing the vector.
532
- for ( let i = 0, l = normals.length; i < l; i ++ ) {
533
-
534
- normals[ i ].normalize();
535
-
536
- }
537
-
538
- }
539
-
540
- function isPartType( type ) {
541
-
542
- return type === 'Part' || type === 'Unofficial_Part';
543
-
544
- }
545
-
546
- function isPrimitiveType( type ) {
547
-
548
- return /primitive/i.test( type ) || type === 'Subpart';
549
-
550
- }
551
-
552
- class LineParser {
553
-
554
- constructor( line, lineNumber ) {
555
-
556
- this.line = line;
557
- this.lineLength = line.length;
558
- this.currentCharIndex = 0;
559
- this.currentChar = ' ';
560
- this.lineNumber = lineNumber;
561
-
562
- }
563
-
564
- seekNonSpace() {
565
-
566
- while ( this.currentCharIndex < this.lineLength ) {
567
-
568
- this.currentChar = this.line.charAt( this.currentCharIndex );
569
-
570
- if ( this.currentChar !== ' ' && this.currentChar !== '\t' ) {
571
-
572
- return;
573
-
574
- }
575
-
576
- this.currentCharIndex ++;
577
-
578
- }
579
-
580
- }
581
-
582
- getToken() {
583
-
584
- const pos0 = this.currentCharIndex ++;
585
-
586
- // Seek space
587
- while ( this.currentCharIndex < this.lineLength ) {
588
-
589
- this.currentChar = this.line.charAt( this.currentCharIndex );
590
-
591
- if ( this.currentChar === ' ' || this.currentChar === '\t' ) {
592
-
593
- break;
594
-
595
- }
596
-
597
- this.currentCharIndex ++;
598
-
599
- }
600
-
601
- const pos1 = this.currentCharIndex;
602
-
603
- this.seekNonSpace();
604
-
605
- return this.line.substring( pos0, pos1 );
606
-
607
- }
608
-
609
- getVector() {
610
-
611
- return new Vector3( parseFloat( this.getToken() ), parseFloat( this.getToken() ), parseFloat( this.getToken() ) );
612
-
613
- }
614
-
615
- getRemainingString() {
616
-
617
- return this.line.substring( this.currentCharIndex, this.lineLength );
618
-
619
- }
620
-
621
- isAtTheEnd() {
622
-
623
- return this.currentCharIndex >= this.lineLength;
624
-
625
- }
626
-
627
- setToEnd() {
628
-
629
- this.currentCharIndex = this.lineLength;
630
-
631
- }
632
-
633
- getLineNumberString() {
634
-
635
- return this.lineNumber >= 0 ? ' at line ' + this.lineNumber : '';
636
-
637
- }
638
-
639
- }
640
-
641
- // Fetches and parses an intermediate representation of LDraw parts files.
642
- class LDrawParsedCache {
643
-
644
- constructor( loader ) {
645
-
646
- this.loader = loader;
647
- this._cache = {};
648
-
649
- }
650
-
651
- cloneResult( original ) {
652
-
653
- const result = {};
654
-
655
- // vertices are transformed and normals computed before being converted to geometry
656
- // so these pieces must be cloned.
657
- result.faces = original.faces.map( face => {
658
-
659
- return {
660
- colorCode: face.colorCode,
661
- material: face.material,
662
- vertices: face.vertices.map( v => v.clone() ),
663
- normals: face.normals.map( () => null ),
664
- faceNormal: null
665
- };
666
-
667
- } );
668
-
669
- result.conditionalSegments = original.conditionalSegments.map( face => {
670
-
671
- return {
672
- colorCode: face.colorCode,
673
- material: face.material,
674
- vertices: face.vertices.map( v => v.clone() ),
675
- controlPoints: face.controlPoints.map( v => v.clone() )
676
- };
677
-
678
- } );
679
-
680
- result.lineSegments = original.lineSegments.map( face => {
681
-
682
- return {
683
- colorCode: face.colorCode,
684
- material: face.material,
685
- vertices: face.vertices.map( v => v.clone() )
686
- };
687
-
688
- } );
689
-
690
- // none if this is subsequently modified
691
- result.type = original.type;
692
- result.category = original.category;
693
- result.keywords = original.keywords;
694
- result.author = original.author;
695
- result.subobjects = original.subobjects;
696
- result.fileName = original.fileName;
697
- result.totalFaces = original.totalFaces;
698
- result.startingBuildingStep = original.startingBuildingStep;
699
- result.materials = original.materials;
700
- result.group = null;
701
- return result;
702
-
703
- }
704
-
705
- async fetchData( fileName ) {
706
-
707
- let triedLowerCase = false;
708
- let locationState = FILE_LOCATION_TRY_PARTS;
709
- while ( locationState !== FILE_LOCATION_NOT_FOUND ) {
710
-
711
- let subobjectURL = fileName;
712
- switch ( locationState ) {
713
-
714
- case FILE_LOCATION_AS_IS:
715
- locationState = locationState + 1;
716
- break;
717
-
718
- case FILE_LOCATION_TRY_PARTS:
719
- subobjectURL = 'parts/' + subobjectURL;
720
- locationState = locationState + 1;
721
- break;
722
-
723
- case FILE_LOCATION_TRY_P:
724
- subobjectURL = 'p/' + subobjectURL;
725
- locationState = locationState + 1;
726
- break;
727
-
728
- case FILE_LOCATION_TRY_MODELS:
729
- subobjectURL = 'models/' + subobjectURL;
730
- locationState = locationState + 1;
731
- break;
732
-
733
- case FILE_LOCATION_TRY_RELATIVE:
734
- subobjectURL = fileName.substring( 0, fileName.lastIndexOf( '/' ) + 1 ) + subobjectURL;
735
- locationState = locationState + 1;
736
- break;
737
-
738
- case FILE_LOCATION_TRY_ABSOLUTE:
739
-
740
- if ( triedLowerCase ) {
741
-
742
- // Try absolute path
743
- locationState = FILE_LOCATION_NOT_FOUND;
744
-
745
- } else {
746
-
747
- // Next attempt is lower case
748
- fileName = fileName.toLowerCase();
749
- subobjectURL = fileName;
750
- triedLowerCase = true;
751
- locationState = FILE_LOCATION_TRY_PARTS;
752
-
753
- }
754
-
755
- break;
756
-
757
- }
758
-
759
- const loader = this.loader;
760
- const fileLoader = new FileLoader( loader.manager );
761
- fileLoader.setPath( loader.partsLibraryPath );
762
- fileLoader.setRequestHeader( loader.requestHeader );
763
- fileLoader.setWithCredentials( loader.withCredentials );
764
-
765
- try {
766
-
767
- const text = await fileLoader.loadAsync( subobjectURL );
768
- return text;
769
-
770
- } catch {
771
-
772
- continue;
773
-
774
- }
775
-
776
- }
777
-
778
- throw new Error( 'LDrawLoader: Subobject "' + fileName + '" could not be loaded.' );
779
-
780
- }
781
-
782
- parse( text, fileName = null ) {
783
-
784
- const loader = this.loader;
785
-
786
- // final results
787
- const faces = [];
788
- const lineSegments = [];
789
- const conditionalSegments = [];
790
- const subobjects = [];
791
- const materials = {};
792
-
793
- const getLocalMaterial = colorCode => {
794
-
795
- return materials[ colorCode ] || null;
796
-
797
- };
798
-
799
- let type = 'Model';
800
- let category = null;
801
- let keywords = null;
802
- let author = null;
803
- let totalFaces = 0;
804
-
805
- // split into lines
806
- if ( text.indexOf( '\r\n' ) !== - 1 ) {
807
-
808
- // This is faster than String.split with regex that splits on both
809
- text = text.replace( /\r\n/g, '\n' );
810
-
811
- }
812
-
813
- const lines = text.split( '\n' );
814
- const numLines = lines.length;
815
-
816
- let parsingEmbeddedFiles = false;
817
- let currentEmbeddedFileName = null;
818
- let currentEmbeddedText = null;
819
-
820
- let bfcCertified = false;
821
- let bfcCCW = true;
822
- let bfcInverted = false;
823
- let bfcCull = true;
824
-
825
- let startingBuildingStep = false;
826
-
827
- // Parse all line commands
828
- for ( let lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
829
-
830
- const line = lines[ lineIndex ];
831
-
832
- if ( line.length === 0 ) continue;
833
-
834
- if ( parsingEmbeddedFiles ) {
835
-
836
- if ( line.startsWith( '0 FILE ' ) ) {
837
-
838
- // Save previous embedded file in the cache
839
- this.setData( currentEmbeddedFileName, currentEmbeddedText );
840
-
841
- // New embedded text file
842
- currentEmbeddedFileName = line.substring( 7 );
843
- currentEmbeddedText = '';
844
-
845
- } else {
846
-
847
- currentEmbeddedText += line + '\n';
848
-
849
- }
850
-
851
- continue;
852
-
853
- }
854
-
855
- const lp = new LineParser( line, lineIndex + 1 );
856
- lp.seekNonSpace();
857
-
858
- if ( lp.isAtTheEnd() ) {
859
-
860
- // Empty line
861
- continue;
862
-
863
- }
864
-
865
- // Parse the line type
866
- const lineType = lp.getToken();
867
-
868
- let material;
869
- let colorCode;
870
- let segment;
871
- let ccw;
872
- let doubleSided;
873
- let v0, v1, v2, v3, c0, c1;
874
-
875
- switch ( lineType ) {
876
-
877
- // Line type 0: Comment or META
878
- case '0':
879
-
880
- // Parse meta directive
881
- const meta = lp.getToken();
882
-
883
- if ( meta ) {
884
-
885
- switch ( meta ) {
886
-
887
- case '!LDRAW_ORG':
888
-
889
- type = lp.getToken();
890
- break;
891
-
892
- case '!COLOUR':
893
-
894
- material = loader.parseColorMetaDirective( lp );
895
- if ( material ) {
896
-
897
- materials[ material.userData.code ] = material;
898
-
899
- } else {
900
-
901
- console.warn( 'LDrawLoader: Error parsing material' + lp.getLineNumberString() );
902
-
903
- }
904
-
905
- break;
906
-
907
- case '!CATEGORY':
908
-
909
- category = lp.getToken();
910
- break;
911
-
912
- case '!KEYWORDS':
913
-
914
- const newKeywords = lp.getRemainingString().split( ',' );
915
- if ( newKeywords.length > 0 ) {
916
-
917
- if ( ! keywords ) {
918
-
919
- keywords = [];
920
-
921
- }
922
-
923
- newKeywords.forEach( function ( keyword ) {
924
-
925
- keywords.push( keyword.trim() );
926
-
927
- } );
928
-
929
- }
930
-
931
- break;
932
-
933
- case 'FILE':
934
-
935
- if ( lineIndex > 0 ) {
936
-
937
- // Start embedded text files parsing
938
- parsingEmbeddedFiles = true;
939
- currentEmbeddedFileName = lp.getRemainingString();
940
- currentEmbeddedText = '';
941
-
942
- bfcCertified = false;
943
- bfcCCW = true;
944
-
945
- }
946
-
947
- break;
948
-
949
- case 'BFC':
950
-
951
- // Changes to the backface culling state
952
- while ( ! lp.isAtTheEnd() ) {
953
-
954
- const token = lp.getToken();
955
-
956
- switch ( token ) {
957
-
958
- case 'CERTIFY':
959
- case 'NOCERTIFY':
960
-
961
- bfcCertified = token === 'CERTIFY';
962
- bfcCCW = true;
963
-
964
- break;
965
-
966
- case 'CW':
967
- case 'CCW':
968
-
969
- bfcCCW = token === 'CCW';
970
-
971
- break;
972
-
973
- case 'INVERTNEXT':
974
-
975
- bfcInverted = true;
976
-
977
- break;
978
-
979
- case 'CLIP':
980
- case 'NOCLIP':
981
-
982
- bfcCull = token === 'CLIP';
983
-
984
- break;
985
-
986
- default:
987
-
988
- console.warn( 'THREE.LDrawLoader: BFC directive "' + token + '" is unknown.' );
989
-
990
- break;
991
-
992
- }
993
-
994
- }
995
-
996
- break;
997
-
998
- case 'STEP':
999
-
1000
- startingBuildingStep = true;
1001
-
1002
- break;
1003
-
1004
- case 'Author:':
1005
-
1006
- author = lp.getToken();
1007
-
1008
- break;
1009
-
1010
- default:
1011
- // Other meta directives are not implemented
1012
- break;
1013
-
1014
- }
1015
-
1016
- }
1017
-
1018
- break;
1019
-
1020
- // Line type 1: Sub-object file
1021
- case '1':
1022
-
1023
- colorCode = lp.getToken();
1024
- material = getLocalMaterial( colorCode );
1025
-
1026
- const posX = parseFloat( lp.getToken() );
1027
- const posY = parseFloat( lp.getToken() );
1028
- const posZ = parseFloat( lp.getToken() );
1029
- const m0 = parseFloat( lp.getToken() );
1030
- const m1 = parseFloat( lp.getToken() );
1031
- const m2 = parseFloat( lp.getToken() );
1032
- const m3 = parseFloat( lp.getToken() );
1033
- const m4 = parseFloat( lp.getToken() );
1034
- const m5 = parseFloat( lp.getToken() );
1035
- const m6 = parseFloat( lp.getToken() );
1036
- const m7 = parseFloat( lp.getToken() );
1037
- const m8 = parseFloat( lp.getToken() );
1038
-
1039
- const matrix = new Matrix4().set(
1040
- m0, m1, m2, posX,
1041
- m3, m4, m5, posY,
1042
- m6, m7, m8, posZ,
1043
- 0, 0, 0, 1
1044
- );
1045
-
1046
- let fileName = lp.getRemainingString().trim().replace( /\\/g, '/' );
1047
-
1048
- if ( loader.fileMap[ fileName ] ) {
1049
-
1050
- // Found the subobject path in the preloaded file path map
1051
- fileName = loader.fileMap[ fileName ];
1052
-
1053
- } else {
1054
-
1055
- // Standardized subfolders
1056
- if ( fileName.startsWith( 's/' ) ) {
1057
-
1058
- fileName = 'parts/' + fileName;
1059
-
1060
- } else if ( fileName.startsWith( '48/' ) ) {
1061
-
1062
- fileName = 'p/' + fileName;
1063
-
1064
- }
1065
-
1066
- }
1067
-
1068
- subobjects.push( {
1069
- material: material,
1070
- colorCode: colorCode,
1071
- matrix: matrix,
1072
- fileName: fileName,
1073
- inverted: bfcInverted,
1074
- startingBuildingStep: startingBuildingStep
1075
- } );
1076
-
1077
- startingBuildingStep = false;
1078
- bfcInverted = false;
1079
-
1080
- break;
1081
-
1082
- // Line type 2: Line segment
1083
- case '2':
1084
-
1085
- colorCode = lp.getToken();
1086
- material = getLocalMaterial( colorCode );
1087
- v0 = lp.getVector();
1088
- v1 = lp.getVector();
1089
-
1090
- segment = {
1091
- material: material,
1092
- colorCode: colorCode,
1093
- vertices: [ v0, v1 ],
1094
- };
1095
-
1096
- lineSegments.push( segment );
1097
-
1098
- break;
1099
-
1100
- // Line type 5: Conditional Line segment
1101
- case '5':
1102
-
1103
- colorCode = lp.getToken();
1104
- material = getLocalMaterial( colorCode );
1105
- v0 = lp.getVector();
1106
- v1 = lp.getVector();
1107
- c0 = lp.getVector();
1108
- c1 = lp.getVector();
1109
-
1110
- segment = {
1111
- material: material,
1112
- colorCode: colorCode,
1113
- vertices: [ v0, v1 ],
1114
- controlPoints: [ c0, c1 ],
1115
- };
1116
-
1117
- conditionalSegments.push( segment );
1118
-
1119
- break;
1120
-
1121
- // Line type 3: Triangle
1122
- case '3':
1123
-
1124
- colorCode = lp.getToken();
1125
- material = getLocalMaterial( colorCode );
1126
- ccw = bfcCCW;
1127
- doubleSided = ! bfcCertified || ! bfcCull;
1128
-
1129
- if ( ccw === true ) {
1130
-
1131
- v0 = lp.getVector();
1132
- v1 = lp.getVector();
1133
- v2 = lp.getVector();
1134
-
1135
- } else {
1136
-
1137
- v2 = lp.getVector();
1138
- v1 = lp.getVector();
1139
- v0 = lp.getVector();
1140
-
1141
- }
1142
-
1143
- faces.push( {
1144
- material: material,
1145
- colorCode: colorCode,
1146
- faceNormal: null,
1147
- vertices: [ v0, v1, v2 ],
1148
- normals: [ null, null, null ],
1149
- } );
1150
- totalFaces ++;
1151
-
1152
- if ( doubleSided === true ) {
1153
-
1154
- faces.push( {
1155
- material: material,
1156
- colorCode: colorCode,
1157
- faceNormal: null,
1158
- vertices: [ v2, v1, v0 ],
1159
- normals: [ null, null, null ],
1160
- } );
1161
- totalFaces ++;
1162
-
1163
- }
1164
-
1165
- break;
1166
-
1167
- // Line type 4: Quadrilateral
1168
- case '4':
1169
-
1170
- colorCode = lp.getToken();
1171
- material = getLocalMaterial( colorCode );
1172
- ccw = bfcCCW;
1173
- doubleSided = ! bfcCertified || ! bfcCull;
1174
-
1175
- if ( ccw === true ) {
1176
-
1177
- v0 = lp.getVector();
1178
- v1 = lp.getVector();
1179
- v2 = lp.getVector();
1180
- v3 = lp.getVector();
1181
-
1182
- } else {
1183
-
1184
- v3 = lp.getVector();
1185
- v2 = lp.getVector();
1186
- v1 = lp.getVector();
1187
- v0 = lp.getVector();
1188
-
1189
- }
1190
-
1191
- // specifically place the triangle diagonal in the v0 and v1 slots so we can
1192
- // account for the doubling of vertices later when smoothing normals.
1193
- faces.push( {
1194
- material: material,
1195
- colorCode: colorCode,
1196
- faceNormal: null,
1197
- vertices: [ v0, v1, v2, v3 ],
1198
- normals: [ null, null, null, null ],
1199
- } );
1200
- totalFaces += 2;
1201
-
1202
- if ( doubleSided === true ) {
1203
-
1204
- faces.push( {
1205
- material: material,
1206
- colorCode: colorCode,
1207
- faceNormal: null,
1208
- vertices: [ v3, v2, v1, v0 ],
1209
- normals: [ null, null, null, null ],
1210
- } );
1211
- totalFaces += 2;
1212
-
1213
- }
1214
-
1215
- break;
1216
-
1217
- default:
1218
- throw new Error( 'LDrawLoader: Unknown line type "' + lineType + '"' + lp.getLineNumberString() + '.' );
1219
-
1220
- }
1221
-
1222
- }
1223
-
1224
- if ( parsingEmbeddedFiles ) {
1225
-
1226
- this.setData( currentEmbeddedFileName, currentEmbeddedText );
1227
-
1228
- }
1229
-
1230
- return {
1231
- faces,
1232
- conditionalSegments,
1233
- lineSegments,
1234
- type,
1235
- category,
1236
- keywords,
1237
- author,
1238
- subobjects,
1239
- totalFaces,
1240
- startingBuildingStep,
1241
- materials,
1242
- fileName,
1243
- group: null
1244
- };
1245
-
1246
- }
1247
-
1248
- // returns an (optionally cloned) instance of the data
1249
- getData( fileName, clone = true ) {
1250
-
1251
- const key = fileName.toLowerCase();
1252
- const result = this._cache[ key ];
1253
- if ( result === null || result instanceof Promise ) {
1254
-
1255
- return null;
1256
-
1257
- }
1258
-
1259
- if ( clone ) {
1260
-
1261
- return this.cloneResult( result );
1262
-
1263
- } else {
1264
-
1265
- return result;
1266
-
1267
- }
1268
-
1269
- }
1270
-
1271
- // kicks off a fetch and parse of the requested data if it hasn't already been loaded. Returns when
1272
- // the data is ready to use and can be retrieved synchronously with "getData".
1273
- async ensureDataLoaded( fileName ) {
1274
-
1275
- const key = fileName.toLowerCase();
1276
- if ( ! ( key in this._cache ) ) {
1277
-
1278
- // replace the promise with a copy of the parsed data for immediate processing
1279
- this._cache[ key ] = this.fetchData( fileName ).then( text => {
1280
-
1281
- const info = this.parse( text, fileName );
1282
- this._cache[ key ] = info;
1283
- return info;
1284
-
1285
- } );
1286
-
1287
- }
1288
-
1289
- await this._cache[ key ];
1290
-
1291
- }
1292
-
1293
- // sets the data in the cache from parsed data
1294
- setData( fileName, text ) {
1295
-
1296
- const key = fileName.toLowerCase();
1297
- this._cache[ key ] = this.parse( text, fileName );
1298
-
1299
- }
1300
-
1301
- }
1302
-
1303
- // returns the material for an associated color code. If the color code is 16 for a face or 24 for
1304
- // an edge then the passthroughColorCode is used.
1305
- function getMaterialFromCode( colorCode, parentColorCode, materialHierarchy, forEdge ) {
1306
-
1307
- const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
1308
- if ( isPassthrough ) {
1309
-
1310
- colorCode = parentColorCode;
1311
-
1312
- }
1313
-
1314
- return materialHierarchy[ colorCode ] || null;
1315
-
1316
- }
1317
-
1318
- // Class used to parse and build LDraw parts as three.js objects and cache them if they're a "Part" type.
1319
- class LDrawPartsGeometryCache {
1320
-
1321
- constructor( loader ) {
1322
-
1323
- this.loader = loader;
1324
- this.parseCache = new LDrawParsedCache( loader );
1325
- this._cache = {};
1326
-
1327
- }
1328
-
1329
- // Convert the given file information into a mesh by processing subobjects.
1330
- async processIntoMesh( info ) {
1331
-
1332
- const loader = this.loader;
1333
- const parseCache = this.parseCache;
1334
- const faceMaterials = new Set();
1335
-
1336
- // Processes the part subobject information to load child parts and merge geometry onto part
1337
- // piece object.
1338
- const processInfoSubobjects = async ( info, subobject = null ) => {
1339
-
1340
- const subobjects = info.subobjects;
1341
- const promises = [];
1342
-
1343
- // Trigger load of all subobjects. If a subobject isn't a primitive then load it as a separate
1344
- // group which lets instruction steps apply correctly.
1345
- for ( let i = 0, l = subobjects.length; i < l; i ++ ) {
1346
-
1347
- const subobject = subobjects[ i ];
1348
- const promise = parseCache.ensureDataLoaded( subobject.fileName ).then( () => {
1349
-
1350
- const subobjectInfo = parseCache.getData( subobject.fileName, false );
1351
- if ( ! isPrimitiveType( subobjectInfo.type ) ) {
1352
-
1353
- return this.loadModel( subobject.fileName ).catch( error => {
1354
-
1355
- console.warn( error );
1356
- return null;
1357
-
1358
- } );
1359
-
1360
- }
1361
-
1362
- return processInfoSubobjects( parseCache.getData( subobject.fileName ), subobject );
1363
-
1364
- } );
1365
-
1366
- promises.push( promise );
1367
-
1368
- }
1369
-
1370
- const group = new Group();
1371
- group.userData.category = info.category;
1372
- group.userData.keywords = info.keywords;
1373
- group.userData.author = info.author;
1374
- group.userData.type = info.type;
1375
- group.userData.fileName = info.fileName;
1376
- info.group = group;
1377
-
1378
- const subobjectInfos = await Promise.all( promises );
1379
- for ( let i = 0, l = subobjectInfos.length; i < l; i ++ ) {
1380
-
1381
- const subobject = info.subobjects[ i ];
1382
- const subobjectInfo = subobjectInfos[ i ];
1383
-
1384
- if ( subobjectInfo === null ) {
1385
-
1386
- // the subobject failed to load
1387
- continue;
1388
-
1389
- }
1390
-
1391
- // if the subobject was loaded as a separate group then apply the parent scopes materials
1392
- if ( subobjectInfo.isGroup ) {
1393
-
1394
- const subobjectGroup = subobjectInfo;
1395
- subobject.matrix.decompose( subobjectGroup.position, subobjectGroup.quaternion, subobjectGroup.scale );
1396
- subobjectGroup.userData.startingBuildingStep = subobject.startingBuildingStep;
1397
- subobjectGroup.name = subobject.fileName;
1398
-
1399
- loader.applyMaterialsToMesh( subobjectGroup, subobject.colorCode, info.materials );
1400
- subobjectGroup.userData.colorCode = subobject.colorCode;
1401
-
1402
- group.add( subobjectGroup );
1403
- continue;
1404
-
1405
- }
1406
-
1407
- // add the subobject group if it has children in case it has both children and primitives
1408
- if ( subobjectInfo.group.children.length ) {
1409
-
1410
- group.add( subobjectInfo.group );
1411
-
1412
- }
1413
-
1414
- // transform the primitives into the local space of the parent piece and append them to
1415
- // to the parent primitives list.
1416
- const parentLineSegments = info.lineSegments;
1417
- const parentConditionalSegments = info.conditionalSegments;
1418
- const parentFaces = info.faces;
1419
-
1420
- const lineSegments = subobjectInfo.lineSegments;
1421
- const conditionalSegments = subobjectInfo.conditionalSegments;
1422
-
1423
- const faces = subobjectInfo.faces;
1424
- const matrix = subobject.matrix;
1425
- const inverted = subobject.inverted;
1426
- const matrixScaleInverted = matrix.determinant() < 0;
1427
- const colorCode = subobject.colorCode;
1428
-
1429
- const lineColorCode = colorCode === MAIN_COLOUR_CODE ? MAIN_EDGE_COLOUR_CODE : colorCode;
1430
- for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
1431
-
1432
- const ls = lineSegments[ i ];
1433
- const vertices = ls.vertices;
1434
- vertices[ 0 ].applyMatrix4( matrix );
1435
- vertices[ 1 ].applyMatrix4( matrix );
1436
- ls.colorCode = ls.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : ls.colorCode;
1437
- ls.material = ls.material || getMaterialFromCode( ls.colorCode, ls.colorCode, info.materials, true );
1438
-
1439
- parentLineSegments.push( ls );
1440
-
1441
- }
1442
-
1443
- for ( let i = 0, l = conditionalSegments.length; i < l; i ++ ) {
1444
-
1445
- const os = conditionalSegments[ i ];
1446
- const vertices = os.vertices;
1447
- const controlPoints = os.controlPoints;
1448
- vertices[ 0 ].applyMatrix4( matrix );
1449
- vertices[ 1 ].applyMatrix4( matrix );
1450
- controlPoints[ 0 ].applyMatrix4( matrix );
1451
- controlPoints[ 1 ].applyMatrix4( matrix );
1452
- os.colorCode = os.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : os.colorCode;
1453
- os.material = os.material || getMaterialFromCode( os.colorCode, os.colorCode, info.materials, true );
1454
-
1455
- parentConditionalSegments.push( os );
1456
-
1457
- }
1458
-
1459
- for ( let i = 0, l = faces.length; i < l; i ++ ) {
1460
-
1461
- const tri = faces[ i ];
1462
- const vertices = tri.vertices;
1463
- for ( let i = 0, l = vertices.length; i < l; i ++ ) {
1464
-
1465
- vertices[ i ].applyMatrix4( matrix );
1466
-
1467
- }
1468
-
1469
- tri.colorCode = tri.colorCode === MAIN_COLOUR_CODE ? colorCode : tri.colorCode;
1470
- tri.material = tri.material || getMaterialFromCode( tri.colorCode, colorCode, info.materials, false );
1471
- faceMaterials.add( tri.colorCode );
1472
-
1473
- // If the scale of the object is negated then the triangle winding order
1474
- // needs to be flipped.
1475
- if ( matrixScaleInverted !== inverted ) {
1476
-
1477
- vertices.reverse();
1478
-
1479
- }
1480
-
1481
- parentFaces.push( tri );
1482
-
1483
- }
1484
-
1485
- info.totalFaces += subobjectInfo.totalFaces;
1486
-
1487
- }
1488
-
1489
- // Apply the parent subobjects pass through material code to this object. This is done several times due
1490
- // to material scoping.
1491
- if ( subobject ) {
1492
-
1493
- loader.applyMaterialsToMesh( group, subobject.colorCode, info.materials );
1494
- group.userData.colorCode = subobject.colorCode;
1495
-
1496
- }
1497
-
1498
- return info;
1499
-
1500
- };
1501
-
1502
- // Track material use to see if we need to use the normal smooth slow path for hard edges.
1503
- for ( let i = 0, l = info.faces; i < l; i ++ ) {
1504
-
1505
- faceMaterials.add( info.faces[ i ].colorCode );
1506
-
1507
- }
1508
-
1509
- await processInfoSubobjects( info );
1510
-
1511
- if ( loader.smoothNormals ) {
1512
-
1513
- const checkSubSegments = faceMaterials.size > 1;
1514
- generateFaceNormals( info.faces );
1515
- smoothNormals( info.faces, info.lineSegments, checkSubSegments );
1516
-
1517
- }
1518
-
1519
- // Add the primitive objects and metadata.
1520
- const group = info.group;
1521
- if ( info.faces.length > 0 ) {
1522
-
1523
- group.add( createObject( info.faces, 3, false, info.totalFaces ) );
1524
-
1525
- }
1526
-
1527
- if ( info.lineSegments.length > 0 ) {
1528
-
1529
- group.add( createObject( info.lineSegments, 2 ) );
1530
-
1531
- }
1532
-
1533
- if ( info.conditionalSegments.length > 0 ) {
1534
-
1535
- group.add( createObject( info.conditionalSegments, 2, true ) );
1536
-
1537
- }
1538
-
1539
- return group;
1540
-
1541
- }
1542
-
1543
- hasCachedModel( fileName ) {
1544
-
1545
- return fileName !== null && fileName.toLowerCase() in this._cache;
1546
-
1547
- }
1548
-
1549
- async getCachedModel( fileName ) {
1550
-
1551
- if ( fileName !== null && this.hasCachedModel( fileName ) ) {
1552
-
1553
- const key = fileName.toLowerCase();
1554
- const group = await this._cache[ key ];
1555
- return group.clone();
1556
-
1557
- } else {
1558
-
1559
- return null;
1560
-
1561
- }
1562
-
1563
- }
1564
-
1565
- // Loads and parses the model with the given file name. Returns a cached copy if available.
1566
- async loadModel( fileName ) {
1567
-
1568
- const parseCache = this.parseCache;
1569
- const key = fileName.toLowerCase();
1570
- if ( this.hasCachedModel( fileName ) ) {
1571
-
1572
- // Return cached model if available.
1573
- return this.getCachedModel( fileName );
1574
-
1575
- } else {
1576
-
1577
- // Otherwise parse a new model.
1578
- // Ensure the file data is loaded and pre parsed.
1579
- await parseCache.ensureDataLoaded( fileName );
1580
-
1581
- const info = parseCache.getData( fileName );
1582
- const promise = this.processIntoMesh( info );
1583
-
1584
- // Now that the file has loaded it's possible that another part parse has been waiting in parallel
1585
- // so check the cache again to see if it's been added since the last async operation so we don't
1586
- // do unnecessary work.
1587
- if ( this.hasCachedModel( fileName ) ) {
1588
-
1589
- return this.getCachedModel( fileName );
1590
-
1591
- }
1592
-
1593
- // Cache object if it's a part so it can be reused later.
1594
- if ( isPartType( info.type ) ) {
1595
-
1596
- this._cache[ key ] = promise;
1597
-
1598
- }
1599
-
1600
- // return a copy
1601
- const group = await promise;
1602
- return group.clone();
1603
-
1604
- }
1605
-
1606
- }
1607
-
1608
- // parses the given model text into a renderable object. Returns cached copy if available.
1609
- async parseModel( text ) {
1610
-
1611
- const parseCache = this.parseCache;
1612
- const info = parseCache.parse( text );
1613
- if ( isPartType( info.type ) && this.hasCachedModel( info.fileName ) ) {
1614
-
1615
- return this.getCachedModel( info.fileName );
1616
-
1617
- }
1618
-
1619
- return this.processIntoMesh( info );
1620
-
1621
- }
1622
-
1623
- }
1624
-
1625
- function sortByMaterial( a, b ) {
1626
-
1627
- if ( a.colorCode === b.colorCode ) {
1628
-
1629
- return 0;
1630
-
1631
- }
1632
-
1633
- if ( a.colorCode < b.colorCode ) {
1634
-
1635
- return - 1;
1636
-
1637
- }
1638
-
1639
- return 1;
1640
-
1641
- }
1642
-
1643
- function createObject( elements, elementSize, isConditionalSegments = false, totalElements = null ) {
1644
-
1645
- // Creates a LineSegments (elementSize = 2) or a Mesh (elementSize = 3 )
1646
- // With per face / segment material, implemented with mesh groups and materials array
1647
-
1648
- // Sort the faces or line segments by color code to make later the mesh groups
1649
- elements.sort( sortByMaterial );
1650
-
1651
- if ( totalElements === null ) {
1652
-
1653
- totalElements = elements.length;
1654
-
1655
- }
1656
-
1657
- const positions = new Float32Array( elementSize * totalElements * 3 );
1658
- const normals = elementSize === 3 ? new Float32Array( elementSize * totalElements * 3 ) : null;
1659
- const materials = [];
1660
-
1661
- const quadArray = new Array( 6 );
1662
- const bufferGeometry = new BufferGeometry();
1663
- let prevMaterial = null;
1664
- let index0 = 0;
1665
- let numGroupVerts = 0;
1666
- let offset = 0;
1667
-
1668
- for ( let iElem = 0, nElem = elements.length; iElem < nElem; iElem ++ ) {
1669
-
1670
- const elem = elements[ iElem ];
1671
- let vertices = elem.vertices;
1672
- if ( vertices.length === 4 ) {
1673
-
1674
- quadArray[ 0 ] = vertices[ 0 ];
1675
- quadArray[ 1 ] = vertices[ 1 ];
1676
- quadArray[ 2 ] = vertices[ 2 ];
1677
- quadArray[ 3 ] = vertices[ 0 ];
1678
- quadArray[ 4 ] = vertices[ 2 ];
1679
- quadArray[ 5 ] = vertices[ 3 ];
1680
- vertices = quadArray;
1681
-
1682
- }
1683
-
1684
- for ( let j = 0, l = vertices.length; j < l; j ++ ) {
1685
-
1686
- const v = vertices[ j ];
1687
- const index = offset + j * 3;
1688
- positions[ index + 0 ] = v.x;
1689
- positions[ index + 1 ] = v.y;
1690
- positions[ index + 2 ] = v.z;
1691
-
1692
- }
1693
-
1694
- // create the normals array if this is a set of faces
1695
- if ( elementSize === 3 ) {
1696
-
1697
- if ( ! elem.faceNormal ) {
1698
-
1699
- const v0 = vertices[ 0 ];
1700
- const v1 = vertices[ 1 ];
1701
- const v2 = vertices[ 2 ];
1702
- _tempVec0.subVectors( v1, v0 );
1703
- _tempVec1.subVectors( v2, v1 );
1704
- elem.faceNormal = new Vector3()
1705
- .crossVectors( _tempVec0, _tempVec1 )
1706
- .normalize();
1707
-
1708
- }
1709
-
1710
- let elemNormals = elem.normals;
1711
- if ( elemNormals.length === 4 ) {
1712
-
1713
- quadArray[ 0 ] = elemNormals[ 0 ];
1714
- quadArray[ 1 ] = elemNormals[ 1 ];
1715
- quadArray[ 2 ] = elemNormals[ 2 ];
1716
- quadArray[ 3 ] = elemNormals[ 0 ];
1717
- quadArray[ 4 ] = elemNormals[ 2 ];
1718
- quadArray[ 5 ] = elemNormals[ 3 ];
1719
- elemNormals = quadArray;
1720
-
1721
- }
1722
-
1723
- for ( let j = 0, l = elemNormals.length; j < l; j ++ ) {
1724
-
1725
- // use face normal if a vertex normal is not provided
1726
- let n = elem.faceNormal;
1727
- if ( elemNormals[ j ] ) {
1728
-
1729
- n = elemNormals[ j ].norm;
1730
-
1731
- }
1732
-
1733
- const index = offset + j * 3;
1734
- normals[ index + 0 ] = n.x;
1735
- normals[ index + 1 ] = n.y;
1736
- normals[ index + 2 ] = n.z;
1737
-
1738
- }
1739
-
1740
- }
1741
-
1742
- if ( prevMaterial !== elem.colorCode ) {
1743
-
1744
- if ( prevMaterial !== null ) {
1745
-
1746
- bufferGeometry.addGroup( index0, numGroupVerts, materials.length - 1 );
1747
-
1748
- }
1749
-
1750
- const material = elem.material;
1751
-
1752
- if ( material !== null ) {
1753
-
1754
- if ( elementSize === 3 ) {
1755
-
1756
- materials.push( material );
1757
-
1758
- } else if ( elementSize === 2 ) {
1759
-
1760
- if ( isConditionalSegments ) {
1761
-
1762
- materials.push( material.userData.edgeMaterial.userData.conditionalEdgeMaterial );
1763
-
1764
- } else {
1765
-
1766
- materials.push( material.userData.edgeMaterial );
1767
-
1768
- }
1769
-
1770
- }
1771
-
1772
- } else {
1773
-
1774
- // If a material has not been made available yet then keep the color code string in the material array
1775
- // to save the spot for the material once a parent scopes materials are being applied to the object.
1776
- materials.push( elem.colorCode );
1777
-
1778
- }
1779
-
1780
- prevMaterial = elem.colorCode;
1781
- index0 = offset / 3;
1782
- numGroupVerts = vertices.length;
1783
-
1784
- } else {
1785
-
1786
- numGroupVerts += vertices.length;
1787
-
1788
- }
1789
-
1790
- offset += 3 * vertices.length;
1791
-
1792
- }
1793
-
1794
- if ( numGroupVerts > 0 ) {
1795
-
1796
- bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
1797
-
1798
- }
1799
-
1800
- bufferGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
1801
-
1802
- if ( normals !== null ) {
1803
-
1804
- bufferGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
1805
-
1806
- }
1807
-
1808
- let object3d = null;
1809
-
1810
- if ( elementSize === 2 ) {
1811
-
1812
- if ( isConditionalSegments ) {
1813
-
1814
- object3d = new ConditionalLineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1815
-
1816
- } else {
1817
-
1818
- object3d = new LineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1819
-
1820
- }
1821
-
1822
- } else if ( elementSize === 3 ) {
1823
-
1824
- object3d = new Mesh( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1825
-
1826
- }
1827
-
1828
- if ( isConditionalSegments ) {
1829
-
1830
- object3d.isConditionalLine = true;
1831
-
1832
- const controlArray0 = new Float32Array( elements.length * 3 * 2 );
1833
- const controlArray1 = new Float32Array( elements.length * 3 * 2 );
1834
- const directionArray = new Float32Array( elements.length * 3 * 2 );
1835
- for ( let i = 0, l = elements.length; i < l; i ++ ) {
1836
-
1837
- const os = elements[ i ];
1838
- const vertices = os.vertices;
1839
- const controlPoints = os.controlPoints;
1840
- const c0 = controlPoints[ 0 ];
1841
- const c1 = controlPoints[ 1 ];
1842
- const v0 = vertices[ 0 ];
1843
- const v1 = vertices[ 1 ];
1844
- const index = i * 3 * 2;
1845
- controlArray0[ index + 0 ] = c0.x;
1846
- controlArray0[ index + 1 ] = c0.y;
1847
- controlArray0[ index + 2 ] = c0.z;
1848
- controlArray0[ index + 3 ] = c0.x;
1849
- controlArray0[ index + 4 ] = c0.y;
1850
- controlArray0[ index + 5 ] = c0.z;
1851
-
1852
- controlArray1[ index + 0 ] = c1.x;
1853
- controlArray1[ index + 1 ] = c1.y;
1854
- controlArray1[ index + 2 ] = c1.z;
1855
- controlArray1[ index + 3 ] = c1.x;
1856
- controlArray1[ index + 4 ] = c1.y;
1857
- controlArray1[ index + 5 ] = c1.z;
1858
-
1859
- directionArray[ index + 0 ] = v1.x - v0.x;
1860
- directionArray[ index + 1 ] = v1.y - v0.y;
1861
- directionArray[ index + 2 ] = v1.z - v0.z;
1862
- directionArray[ index + 3 ] = v1.x - v0.x;
1863
- directionArray[ index + 4 ] = v1.y - v0.y;
1864
- directionArray[ index + 5 ] = v1.z - v0.z;
1865
-
1866
- }
1867
-
1868
- bufferGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
1869
- bufferGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
1870
- bufferGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );
1871
-
1872
- }
1873
-
1874
- return object3d;
1875
-
1876
- }
1877
-
1878
- //
1879
-
1880
- class LDrawLoader extends Loader {
1881
-
1882
- constructor( manager ) {
1883
-
1884
- super( manager );
1885
-
1886
- // Array of THREE.Material
1887
- this.materials = [];
1888
- this.materialLibrary = {};
1889
-
1890
- // This also allows to handle the embedded text files ("0 FILE" lines)
1891
- this.partsCache = new LDrawPartsGeometryCache( this );
1892
-
1893
- // This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error.
1894
- this.fileMap = {};
1895
-
1896
- // Initializes the materials library with default materials
1897
- this.setMaterials( [] );
1898
-
1899
- // If this flag is set to true the vertex normals will be smoothed.
1900
- this.smoothNormals = true;
1901
-
1902
- // The path to load parts from the LDraw parts library from.
1903
- this.partsLibraryPath = '';
1904
-
1905
- // Material assigned to not available colors for meshes and edges
1906
- this.missingColorMaterial = new MeshStandardMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF, roughness: 0.3, metalness: 0 } );
1907
- this.missingEdgeColorMaterial = new LineBasicMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF } );
1908
- this.missingConditionalEdgeColorMaterial = new LDrawConditionalLineMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, fog: true, color: 0xFF00FF } );
1909
- this.missingColorMaterial.userData.edgeMaterial = this.missingEdgeColorMaterial;
1910
- this.missingEdgeColorMaterial.userData.conditionalEdgeMaterial = this.missingConditionalEdgeColorMaterial;
1911
-
1912
- }
1913
-
1914
- setPartsLibraryPath( path ) {
1915
-
1916
- this.partsLibraryPath = path;
1917
- return this;
1918
-
1919
- }
1920
-
1921
- async preloadMaterials( url ) {
1922
-
1923
- const fileLoader = new FileLoader( this.manager );
1924
- fileLoader.setPath( this.path );
1925
- fileLoader.setRequestHeader( this.requestHeader );
1926
- fileLoader.setWithCredentials( this.withCredentials );
1927
-
1928
- const text = await fileLoader.loadAsync( url );
1929
- const colorLineRegex = /^0 !COLOUR/;
1930
- const lines = text.split( /[\n\r]/g );
1931
- const materials = [];
1932
- for ( let i = 0, l = lines.length; i < l; i ++ ) {
1933
-
1934
- const line = lines[ i ];
1935
- if ( colorLineRegex.test( line ) ) {
1936
-
1937
- const directive = line.replace( colorLineRegex, '' );
1938
- const material = this.parseColorMetaDirective( new LineParser( directive ) );
1939
- materials.push( material );
1940
-
1941
- }
1942
-
1943
- }
1944
-
1945
- this.setMaterials( materials );
1946
-
1947
- }
1948
-
1949
- load( url, onLoad, onProgress, onError ) {
1950
-
1951
- const fileLoader = new FileLoader( this.manager );
1952
- fileLoader.setPath( this.path );
1953
- fileLoader.setRequestHeader( this.requestHeader );
1954
- fileLoader.setWithCredentials( this.withCredentials );
1955
- fileLoader.load( url, text => {
1956
-
1957
- this.partsCache
1958
- .parseModel( text, this.materialLibrary )
1959
- .then( group => {
1960
-
1961
- this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1962
- this.computeBuildingSteps( group );
1963
- group.userData.fileName = url;
1964
- onLoad( group );
1965
-
1966
- } )
1967
- .catch( onError );
1968
-
1969
- }, onProgress, onError );
1970
-
1971
- }
1972
-
1973
- parse( text, onLoad ) {
1974
-
1975
- this.partsCache
1976
- .parseModel( text, this.materialLibrary )
1977
- .then( group => {
1978
-
1979
- this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1980
- this.computeBuildingSteps( group );
1981
- group.userData.fileName = '';
1982
- onLoad( group );
1983
-
1984
- } );
1985
-
1986
- }
1987
-
1988
- setMaterials( materials ) {
1989
-
1990
- this.materialLibrary = {};
1991
- this.materials = [];
1992
- for ( let i = 0, l = materials.length; i < l; i ++ ) {
1993
-
1994
- this.addMaterial( materials[ i ] );
1995
-
1996
- }
1997
-
1998
- // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
1999
- this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Main_Colour CODE 16 VALUE #FF8080 EDGE #333333' ) ) );
2000
- this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333' ) ) );
2001
-
2002
- return this;
2003
-
2004
- }
2005
-
2006
- setFileMap( fileMap ) {
2007
-
2008
- this.fileMap = fileMap;
2009
-
2010
- return this;
2011
-
2012
- }
2013
-
2014
- addMaterial( material ) {
2015
-
2016
- // Adds a material to the material library which is on top of the parse scopes stack. And also to the materials array
2017
-
2018
- const matLib = this.materialLibrary;
2019
- if ( ! matLib[ material.userData.code ] ) {
2020
-
2021
- this.materials.push( material );
2022
- matLib[ material.userData.code ] = material;
2023
-
2024
- }
2025
-
2026
- return this;
2027
-
2028
- }
2029
-
2030
- getMaterial( colorCode ) {
2031
-
2032
- if ( colorCode.startsWith( '0x2' ) ) {
2033
-
2034
- // Special 'direct' material value (RGB color)
2035
- const color = colorCode.substring( 3 );
2036
-
2037
- return this.parseColorMetaDirective( new LineParser( 'Direct_Color_' + color + ' CODE -1 VALUE #' + color + ' EDGE #' + color + '' ) );
2038
-
2039
- }
2040
-
2041
- return this.materialLibrary[ colorCode ] || null;
2042
-
2043
- }
2044
-
2045
- // Applies the appropriate materials to a prebuilt hierarchy of geometry. Assumes that color codes are present
2046
- // in the material array if they need to be filled in.
2047
- applyMaterialsToMesh( group, parentColorCode, materialHierarchy, finalMaterialPass = false ) {
2048
-
2049
- // find any missing materials as indicated by a color code string and replace it with a material from the current material lib
2050
- const loader = this;
2051
- const parentIsPassthrough = parentColorCode === MAIN_COLOUR_CODE;
2052
- group.traverse( c => {
2053
-
2054
- if ( c.isMesh || c.isLineSegments ) {
2055
-
2056
- if ( Array.isArray( c.material ) ) {
2057
-
2058
- for ( let i = 0, l = c.material.length; i < l; i ++ ) {
2059
-
2060
- if ( ! c.material[ i ].isMaterial ) {
2061
-
2062
- c.material[ i ] = getMaterial( c, c.material[ i ] );
2063
-
2064
- }
2065
-
2066
- }
2067
-
2068
- } else if ( ! c.material.isMaterial ) {
2069
-
2070
- c.material = getMaterial( c, c.material );
2071
-
2072
- }
2073
-
2074
- }
2075
-
2076
- } );
2077
-
2078
-
2079
- // Returns the appropriate material for the object (line or face) given color code. If the code is "pass through"
2080
- // (24 for lines, 16 for edges) then the pass through color code is used. If that is also pass through then it's
2081
- // simply returned for the subsequent material application.
2082
- function getMaterial( c, colorCode ) {
2083
-
2084
- // if our parent is a passthrough color code and we don't have the current material color available then
2085
- // return early.
2086
- if ( parentIsPassthrough && ! ( colorCode in materialHierarchy ) && ! finalMaterialPass ) {
2087
-
2088
- return colorCode;
2089
-
2090
- }
2091
-
2092
- const forEdge = c.isLineSegments || c.isConditionalLine;
2093
- const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
2094
- if ( isPassthrough ) {
2095
-
2096
- colorCode = parentColorCode;
2097
-
2098
- }
2099
-
2100
- let material = null;
2101
- if ( colorCode in materialHierarchy ) {
2102
-
2103
- material = materialHierarchy[ colorCode ];
2104
-
2105
- } else if ( finalMaterialPass ) {
2106
-
2107
- // see if we can get the final material from from the "getMaterial" function which will attempt to
2108
- // parse the "direct" colors
2109
- material = loader.getMaterial( colorCode );
2110
- if ( material === null ) {
2111
-
2112
- // otherwise throw a warning if this is final opportunity to set the material
2113
- console.warn( `LDrawLoader: Material properties for code ${ colorCode } not available.` );
2114
-
2115
- // And return the 'missing color' material
2116
- material = loader.missingColorMaterial;
2117
-
2118
- }
2119
-
2120
-
2121
- } else {
2122
-
2123
- return colorCode;
2124
-
2125
- }
2126
-
2127
- if ( c.isLineSegments ) {
2128
-
2129
- material = material.userData.edgeMaterial;
2130
-
2131
- if ( c.isConditionalLine ) {
2132
-
2133
- material = material.userData.conditionalEdgeMaterial;
2134
-
2135
- }
2136
-
2137
- }
2138
-
2139
- return material;
2140
-
2141
- }
2142
-
2143
- }
2144
-
2145
- getMainMaterial() {
2146
-
2147
- return this.getMaterial( MAIN_COLOUR_CODE );
2148
-
2149
- }
2150
-
2151
- getMainEdgeMaterial() {
2152
-
2153
- const mat = this.getMaterial( MAIN_EDGE_COLOUR_CODE );
2154
- return mat ? mat.userData.edgeMaterial : null;
2155
-
2156
- }
2157
-
2158
- parseColorMetaDirective( lineParser ) {
2159
-
2160
- // Parses a color definition and returns a THREE.Material
2161
-
2162
- let code = null;
2163
-
2164
- // Triangle and line colors
2165
- let fillColor = '#FF00FF';
2166
- let edgeColor = '#FF00FF';
2167
-
2168
- // Transparency
2169
- let alpha = 1;
2170
- let isTransparent = false;
2171
- // Self-illumination:
2172
- let luminance = 0;
2173
-
2174
- let finishType = FINISH_TYPE_DEFAULT;
2175
-
2176
- let edgeMaterial = null;
2177
-
2178
- const name = lineParser.getToken();
2179
- if ( ! name ) {
2180
-
2181
- throw new Error( 'LDrawLoader: Material name was expected after "!COLOUR tag' + lineParser.getLineNumberString() + '.' );
2182
-
2183
- }
2184
-
2185
- // Parse tag tokens and their parameters
2186
- let token = null;
2187
- while ( true ) {
2188
-
2189
- token = lineParser.getToken();
2190
-
2191
- if ( ! token ) {
2192
-
2193
- break;
2194
-
2195
- }
2196
-
2197
- if ( ! parseLuminance( token ) ) {
2198
-
2199
- switch ( token.toUpperCase() ) {
2200
-
2201
- case 'CODE':
2202
-
2203
- code = lineParser.getToken();
2204
- break;
2205
-
2206
- case 'VALUE':
2207
-
2208
- fillColor = lineParser.getToken();
2209
- if ( fillColor.startsWith( '0x' ) ) {
2210
-
2211
- fillColor = '#' + fillColor.substring( 2 );
2212
-
2213
- } else if ( ! fillColor.startsWith( '#' ) ) {
2214
-
2215
- throw new Error( 'LDrawLoader: Invalid color while parsing material' + lineParser.getLineNumberString() + '.' );
2216
-
2217
- }
2218
-
2219
- break;
2220
-
2221
- case 'EDGE':
2222
-
2223
- edgeColor = lineParser.getToken();
2224
- if ( edgeColor.startsWith( '0x' ) ) {
2225
-
2226
- edgeColor = '#' + edgeColor.substring( 2 );
2227
-
2228
- } else if ( ! edgeColor.startsWith( '#' ) ) {
2229
-
2230
- // Try to see if edge color is a color code
2231
- edgeMaterial = this.getMaterial( edgeColor );
2232
- if ( ! edgeMaterial ) {
2233
-
2234
- throw new Error( 'LDrawLoader: Invalid edge color while parsing material' + lineParser.getLineNumberString() + '.' );
2235
-
2236
- }
2237
-
2238
- // Get the edge material for this triangle material
2239
- edgeMaterial = edgeMaterial.userData.edgeMaterial;
2240
-
2241
- }
2242
-
2243
- break;
2244
-
2245
- case 'ALPHA':
2246
-
2247
- alpha = parseInt( lineParser.getToken() );
2248
-
2249
- if ( isNaN( alpha ) ) {
2250
-
2251
- throw new Error( 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + '.' );
2252
-
2253
- }
2254
-
2255
- alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
2256
-
2257
- if ( alpha < 1 ) {
2258
-
2259
- isTransparent = true;
2260
-
2261
- }
2262
-
2263
- break;
2264
-
2265
- case 'LUMINANCE':
2266
-
2267
- if ( ! parseLuminance( lineParser.getToken() ) ) {
2268
-
2269
- throw new Error( 'LDrawLoader: Invalid luminance value in material definition' + LineParser.getLineNumberString() + '.' );
2270
-
2271
- }
2272
-
2273
- break;
2274
-
2275
- case 'CHROME':
2276
- finishType = FINISH_TYPE_CHROME;
2277
- break;
2278
-
2279
- case 'PEARLESCENT':
2280
- finishType = FINISH_TYPE_PEARLESCENT;
2281
- break;
2282
-
2283
- case 'RUBBER':
2284
- finishType = FINISH_TYPE_RUBBER;
2285
- break;
2286
-
2287
- case 'MATTE_METALLIC':
2288
- finishType = FINISH_TYPE_MATTE_METALLIC;
2289
- break;
2290
-
2291
- case 'METAL':
2292
- finishType = FINISH_TYPE_METAL;
2293
- break;
2294
-
2295
- case 'MATERIAL':
2296
- // Not implemented
2297
- lineParser.setToEnd();
2298
- break;
2299
-
2300
- default:
2301
- throw new Error( 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + '.' );
2302
-
2303
- }
2304
-
2305
- }
2306
-
2307
- }
2308
-
2309
- let material = null;
2310
-
2311
- switch ( finishType ) {
2312
-
2313
- case FINISH_TYPE_DEFAULT:
2314
-
2315
- material = new MeshStandardMaterial( { roughness: 0.3, metalness: 0 } );
2316
- break;
2317
-
2318
- case FINISH_TYPE_PEARLESCENT:
2319
-
2320
- // Try to imitate pearlescency by making the surface glossy
2321
- material = new MeshStandardMaterial( { roughness: 0.3, metalness: 0.25 } );
2322
- break;
2323
-
2324
- case FINISH_TYPE_CHROME:
2325
-
2326
- // Mirror finish surface
2327
- material = new MeshStandardMaterial( { roughness: 0, metalness: 1 } );
2328
- break;
2329
-
2330
- case FINISH_TYPE_RUBBER:
2331
-
2332
- // Rubber finish
2333
- material = new MeshStandardMaterial( { roughness: 0.9, metalness: 0 } );
2334
- break;
2335
-
2336
- case FINISH_TYPE_MATTE_METALLIC:
2337
-
2338
- // Brushed metal finish
2339
- material = new MeshStandardMaterial( { roughness: 0.8, metalness: 0.4 } );
2340
- break;
2341
-
2342
- case FINISH_TYPE_METAL:
2343
-
2344
- // Average metal finish
2345
- material = new MeshStandardMaterial( { roughness: 0.2, metalness: 0.85 } );
2346
- break;
2347
-
2348
- default:
2349
- // Should not happen
2350
- break;
2351
-
2352
- }
2353
-
2354
- material.color.setStyle( fillColor, COLOR_SPACE_LDRAW );
2355
- material.transparent = isTransparent;
2356
- material.premultipliedAlpha = true;
2357
- material.opacity = alpha;
2358
- material.depthWrite = ! isTransparent;
2359
-
2360
- material.polygonOffset = true;
2361
- material.polygonOffsetFactor = 1;
2362
-
2363
- if ( luminance !== 0 ) {
2364
-
2365
- material.emissive.setStyle( fillColor, COLOR_SPACE_LDRAW ).multiplyScalar( luminance );
2366
-
2367
- }
2368
-
2369
- if ( ! edgeMaterial ) {
2370
-
2371
- // This is the material used for edges
2372
- edgeMaterial = new LineBasicMaterial( {
2373
- color: new Color().setStyle( edgeColor, COLOR_SPACE_LDRAW ),
2374
- transparent: isTransparent,
2375
- opacity: alpha,
2376
- depthWrite: ! isTransparent
2377
- } );
2378
- edgeMaterial.color;
2379
- edgeMaterial.userData.code = code;
2380
- edgeMaterial.name = name + ' - Edge';
2381
-
2382
- // This is the material used for conditional edges
2383
- edgeMaterial.userData.conditionalEdgeMaterial = new LDrawConditionalLineMaterial( {
2384
-
2385
- fog: true,
2386
- transparent: isTransparent,
2387
- depthWrite: ! isTransparent,
2388
- color: new Color().setStyle( edgeColor, COLOR_SPACE_LDRAW ),
2389
- opacity: alpha,
2390
-
2391
- } );
2392
- edgeMaterial.userData.conditionalEdgeMaterial.userData.code = code;
2393
- edgeMaterial.userData.conditionalEdgeMaterial.name = name + ' - Conditional Edge';
2394
-
2395
- }
2396
-
2397
- material.userData.code = code;
2398
- material.name = name;
2399
-
2400
- material.userData.edgeMaterial = edgeMaterial;
2401
-
2402
- this.addMaterial( material );
2403
-
2404
- return material;
2405
-
2406
- function parseLuminance( token ) {
2407
-
2408
- // Returns success
2409
-
2410
- let lum;
2411
-
2412
- if ( token.startsWith( 'LUMINANCE' ) ) {
2413
-
2414
- lum = parseInt( token.substring( 9 ) );
2415
-
2416
- } else {
2417
-
2418
- lum = parseInt( token );
2419
-
2420
- }
2421
-
2422
- if ( isNaN( lum ) ) {
2423
-
2424
- return false;
2425
-
2426
- }
2427
-
2428
- luminance = Math.max( 0, Math.min( 1, lum / 255 ) );
2429
-
2430
- return true;
2431
-
2432
- }
2433
-
2434
- }
2435
-
2436
- computeBuildingSteps( model ) {
2437
-
2438
- // Sets userdata.buildingStep number in Group objects and userData.numBuildingSteps number in the root Group object.
2439
-
2440
- let stepNumber = 0;
2441
-
2442
- model.traverse( c => {
2443
-
2444
- if ( c.isGroup ) {
2445
-
2446
- if ( c.userData.startingBuildingStep ) {
2447
-
2448
- stepNumber ++;
2449
-
2450
- }
2451
-
2452
- c.userData.buildingStep = stepNumber;
2453
-
2454
- }
2455
-
2456
- } );
2457
-
2458
- model.userData.numBuildingSteps = stepNumber + 1;
2459
-
2460
- }
2461
-
2462
- }
2463
-
2464
- export { LDrawLoader };
1
+ import {
2
+ BufferAttribute,
3
+ BufferGeometry,
4
+ Color,
5
+ FileLoader,
6
+ Group,
7
+ LineBasicMaterial,
8
+ LineSegments,
9
+ Loader,
10
+ Matrix4,
11
+ Mesh,
12
+ MeshStandardMaterial,
13
+ ShaderMaterial,
14
+ SRGBColorSpace,
15
+ UniformsLib,
16
+ UniformsUtils,
17
+ Vector3,
18
+ Ray
19
+ } from 'three';
20
+
21
+ // Special surface finish tag types.
22
+ // Note: "MATERIAL" tag (e.g. GLITTER, SPECKLE) is not implemented
23
+ const FINISH_TYPE_DEFAULT = 0;
24
+ const FINISH_TYPE_CHROME = 1;
25
+ const FINISH_TYPE_PEARLESCENT = 2;
26
+ const FINISH_TYPE_RUBBER = 3;
27
+ const FINISH_TYPE_MATTE_METALLIC = 4;
28
+ const FINISH_TYPE_METAL = 5;
29
+
30
+ // State machine to search a subobject path.
31
+ // The LDraw standard establishes these various possible subfolders.
32
+ const FILE_LOCATION_TRY_PARTS = 0;
33
+ const FILE_LOCATION_TRY_P = 1;
34
+ const FILE_LOCATION_TRY_MODELS = 2;
35
+ const FILE_LOCATION_AS_IS = 3;
36
+ const FILE_LOCATION_TRY_RELATIVE = 4;
37
+ const FILE_LOCATION_TRY_ABSOLUTE = 5;
38
+ const FILE_LOCATION_NOT_FOUND = 6;
39
+
40
+ const MAIN_COLOUR_CODE = '16';
41
+ const MAIN_EDGE_COLOUR_CODE = '24';
42
+
43
+ const COLOR_SPACE_LDRAW = SRGBColorSpace;
44
+
45
+ const _tempVec0 = new Vector3();
46
+ const _tempVec1 = new Vector3();
47
+
48
+ class LDrawConditionalLineMaterial extends ShaderMaterial {
49
+
50
+ constructor( parameters ) {
51
+
52
+ super( {
53
+
54
+ uniforms: UniformsUtils.merge( [
55
+ UniformsLib.fog,
56
+ {
57
+ diffuse: {
58
+ value: new Color()
59
+ },
60
+ opacity: {
61
+ value: 1.0
62
+ }
63
+ }
64
+ ] ),
65
+
66
+ vertexShader: /* glsl */`
67
+ attribute vec3 control0;
68
+ attribute vec3 control1;
69
+ attribute vec3 direction;
70
+ varying float discardFlag;
71
+
72
+ #include <common>
73
+ #include <color_pars_vertex>
74
+ #include <fog_pars_vertex>
75
+ #include <logdepthbuf_pars_vertex>
76
+ #include <clipping_planes_pars_vertex>
77
+ void main() {
78
+ #include <color_vertex>
79
+
80
+ vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
81
+ gl_Position = projectionMatrix * mvPosition;
82
+
83
+ // Transform the line segment ends and control points into camera clip space
84
+ vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 );
85
+ vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 );
86
+ vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
87
+ vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 );
88
+
89
+ c0.xy /= c0.w;
90
+ c1.xy /= c1.w;
91
+ p0.xy /= p0.w;
92
+ p1.xy /= p1.w;
93
+
94
+ // Get the direction of the segment and an orthogonal vector
95
+ vec2 dir = p1.xy - p0.xy;
96
+ vec2 norm = vec2( -dir.y, dir.x );
97
+
98
+ // Get control point directions from the line
99
+ vec2 c0dir = c0.xy - p1.xy;
100
+ vec2 c1dir = c1.xy - p1.xy;
101
+
102
+ // If the vectors to the controls points are pointed in different directions away
103
+ // from the line segment then the line should not be drawn.
104
+ float d0 = dot( normalize( norm ), normalize( c0dir ) );
105
+ float d1 = dot( normalize( norm ), normalize( c1dir ) );
106
+ discardFlag = float( sign( d0 ) != sign( d1 ) );
107
+
108
+ #include <logdepthbuf_vertex>
109
+ #include <clipping_planes_vertex>
110
+ #include <fog_vertex>
111
+ }
112
+ `,
113
+
114
+ fragmentShader: /* glsl */`
115
+ uniform vec3 diffuse;
116
+ uniform float opacity;
117
+ varying float discardFlag;
118
+
119
+ #include <common>
120
+ #include <color_pars_fragment>
121
+ #include <fog_pars_fragment>
122
+ #include <logdepthbuf_pars_fragment>
123
+ #include <clipping_planes_pars_fragment>
124
+ void main() {
125
+
126
+ if ( discardFlag > 0.5 ) discard;
127
+
128
+ #include <clipping_planes_fragment>
129
+ vec3 outgoingLight = vec3( 0.0 );
130
+ vec4 diffuseColor = vec4( diffuse, opacity );
131
+ #include <logdepthbuf_fragment>
132
+ #include <color_fragment>
133
+ outgoingLight = diffuseColor.rgb; // simple shader
134
+ gl_FragColor = vec4( outgoingLight, diffuseColor.a );
135
+ #include <tonemapping_fragment>
136
+ #include <colorspace_fragment>
137
+ #include <fog_fragment>
138
+ #include <premultiplied_alpha_fragment>
139
+ }
140
+ `,
141
+
142
+ } );
143
+
144
+ Object.defineProperties( this, {
145
+
146
+ opacity: {
147
+ get: function () {
148
+
149
+ return this.uniforms.opacity.value;
150
+
151
+ },
152
+
153
+ set: function ( value ) {
154
+
155
+ this.uniforms.opacity.value = value;
156
+
157
+ }
158
+ },
159
+
160
+ color: {
161
+ get: function () {
162
+
163
+ return this.uniforms.diffuse.value;
164
+
165
+ }
166
+ }
167
+
168
+ } );
169
+
170
+ this.setValues( parameters );
171
+ this.isLDrawConditionalLineMaterial = true;
172
+
173
+ }
174
+
175
+ }
176
+
177
+ class ConditionalLineSegments extends LineSegments {
178
+
179
+ constructor( geometry, material ) {
180
+
181
+ super( geometry, material );
182
+ this.isConditionalLine = true;
183
+
184
+ }
185
+
186
+ }
187
+
188
+ function generateFaceNormals( faces ) {
189
+
190
+ for ( let i = 0, l = faces.length; i < l; i ++ ) {
191
+
192
+ const face = faces[ i ];
193
+ const vertices = face.vertices;
194
+ const v0 = vertices[ 0 ];
195
+ const v1 = vertices[ 1 ];
196
+ const v2 = vertices[ 2 ];
197
+
198
+ _tempVec0.subVectors( v1, v0 );
199
+ _tempVec1.subVectors( v2, v1 );
200
+ face.faceNormal = new Vector3()
201
+ .crossVectors( _tempVec0, _tempVec1 )
202
+ .normalize();
203
+
204
+ }
205
+
206
+ }
207
+
208
+ const _ray = new Ray();
209
+ function smoothNormals( faces, lineSegments, checkSubSegments = false ) {
210
+
211
+ // NOTE: 1e2 is pretty coarse but was chosen to quantize the resulting value because
212
+ // it allows edges to be smoothed as expected (see minifig arms).
213
+ // --
214
+ // And the vector values are initialize multiplied by 1 + 1e-10 to account for floating
215
+ // point errors on vertices along quantization boundaries. Ie after matrix multiplication
216
+ // vertices that should be merged might be set to "1.7" and "1.6999..." meaning they won't
217
+ // get merged. This added epsilon attempts to push these error values to the same quantized
218
+ // value for the sake of hashing. See "AT-ST mini" dishes. See mrdoob/three#23169.
219
+
220
+ const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
221
+ function hashVertex( v ) {
222
+
223
+ const x = ~ ~ ( v.x * hashMultiplier );
224
+ const y = ~ ~ ( v.y * hashMultiplier );
225
+ const z = ~ ~ ( v.z * hashMultiplier );
226
+
227
+ return `${ x },${ y },${ z }`;
228
+
229
+ }
230
+
231
+ function hashEdge( v0, v1 ) {
232
+
233
+ return `${ hashVertex( v0 ) }_${ hashVertex( v1 ) }`;
234
+
235
+ }
236
+
237
+ // converts the two vertices to a ray with a normalized direction and origin of 0, 0, 0 projected
238
+ // onto the original line.
239
+ function toNormalizedRay( v0, v1, targetRay ) {
240
+
241
+ targetRay.direction.subVectors( v1, v0 ).normalize();
242
+
243
+ const scalar = v0.dot( targetRay.direction );
244
+ targetRay.origin.copy( v0 ).addScaledVector( targetRay.direction, - scalar );
245
+
246
+ return targetRay;
247
+
248
+ }
249
+
250
+ function hashRay( ray ) {
251
+
252
+ return hashEdge( ray.origin, ray.direction );
253
+
254
+ }
255
+
256
+ const hardEdges = new Set();
257
+ const hardEdgeRays = new Map();
258
+ const halfEdgeList = {};
259
+ const normals = [];
260
+
261
+ // Save the list of hard edges by hash
262
+ for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
263
+
264
+ const ls = lineSegments[ i ];
265
+ const vertices = ls.vertices;
266
+ const v0 = vertices[ 0 ];
267
+ const v1 = vertices[ 1 ];
268
+ hardEdges.add( hashEdge( v0, v1 ) );
269
+ hardEdges.add( hashEdge( v1, v0 ) );
270
+
271
+ // only generate the hard edge ray map if we're checking subsegments because it's more expensive to check
272
+ // and requires more memory.
273
+ if ( checkSubSegments ) {
274
+
275
+ // add both ray directions to the map
276
+ const ray = toNormalizedRay( v0, v1, new Ray() );
277
+ const rh1 = hashRay( ray );
278
+ if ( ! hardEdgeRays.has( rh1 ) ) {
279
+
280
+ toNormalizedRay( v1, v0, ray );
281
+ const rh2 = hashRay( ray );
282
+
283
+ const info = {
284
+ ray,
285
+ distances: [],
286
+ };
287
+
288
+ hardEdgeRays.set( rh1, info );
289
+ hardEdgeRays.set( rh2, info );
290
+
291
+ }
292
+
293
+ // store both segments ends in min, max order in the distances array to check if a face edge is a
294
+ // subsegment later.
295
+ const info = hardEdgeRays.get( rh1 );
296
+ let d0 = info.ray.direction.dot( v0 );
297
+ let d1 = info.ray.direction.dot( v1 );
298
+ if ( d0 > d1 ) {
299
+
300
+ [ d0, d1 ] = [ d1, d0 ];
301
+
302
+ }
303
+
304
+ info.distances.push( d0, d1 );
305
+
306
+ }
307
+
308
+ }
309
+
310
+ // track the half edges associated with each triangle
311
+ for ( let i = 0, l = faces.length; i < l; i ++ ) {
312
+
313
+ const tri = faces[ i ];
314
+ const vertices = tri.vertices;
315
+ const vertCount = vertices.length;
316
+ for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
317
+
318
+ const index = i2;
319
+ const next = ( i2 + 1 ) % vertCount;
320
+ const v0 = vertices[ index ];
321
+ const v1 = vertices[ next ];
322
+ const hash = hashEdge( v0, v1 );
323
+
324
+ // don't add the triangle if the edge is supposed to be hard
325
+ if ( hardEdges.has( hash ) ) {
326
+
327
+ continue;
328
+
329
+ }
330
+
331
+ // if checking subsegments then check to see if this edge lies on a hard edge ray and whether its within any ray bounds
332
+ if ( checkSubSegments ) {
333
+
334
+ toNormalizedRay( v0, v1, _ray );
335
+
336
+ const rayHash = hashRay( _ray );
337
+ if ( hardEdgeRays.has( rayHash ) ) {
338
+
339
+ const info = hardEdgeRays.get( rayHash );
340
+ const { ray, distances } = info;
341
+ let d0 = ray.direction.dot( v0 );
342
+ let d1 = ray.direction.dot( v1 );
343
+
344
+ if ( d0 > d1 ) {
345
+
346
+ [ d0, d1 ] = [ d1, d0 ];
347
+
348
+ }
349
+
350
+ // return early if the face edge is found to be a subsegment of a line edge meaning the edge will have "hard" normals
351
+ let found = false;
352
+ for ( let i = 0, l = distances.length; i < l; i += 2 ) {
353
+
354
+ if ( d0 >= distances[ i ] && d1 <= distances[ i + 1 ] ) {
355
+
356
+ found = true;
357
+ break;
358
+
359
+ }
360
+
361
+ }
362
+
363
+ if ( found ) {
364
+
365
+ continue;
366
+
367
+ }
368
+
369
+ }
370
+
371
+ }
372
+
373
+ const info = {
374
+ index: index,
375
+ tri: tri
376
+ };
377
+ halfEdgeList[ hash ] = info;
378
+
379
+ }
380
+
381
+ }
382
+
383
+ // Iterate until we've tried to connect all faces to share normals
384
+ while ( true ) {
385
+
386
+ // Stop if there are no more faces left
387
+ let halfEdge = null;
388
+ for ( const key in halfEdgeList ) {
389
+
390
+ halfEdge = halfEdgeList[ key ];
391
+ break;
392
+
393
+ }
394
+
395
+ if ( halfEdge === null ) {
396
+
397
+ break;
398
+
399
+ }
400
+
401
+ // Exhaustively find all connected faces
402
+ const queue = [ halfEdge ];
403
+ while ( queue.length > 0 ) {
404
+
405
+ // initialize all vertex normals in this triangle
406
+ const tri = queue.pop().tri;
407
+ const vertices = tri.vertices;
408
+ const vertNormals = tri.normals;
409
+ const faceNormal = tri.faceNormal;
410
+
411
+ // Check if any edge is connected to another triangle edge
412
+ const vertCount = vertices.length;
413
+ for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
414
+
415
+ const index = i2;
416
+ const next = ( i2 + 1 ) % vertCount;
417
+ const v0 = vertices[ index ];
418
+ const v1 = vertices[ next ];
419
+
420
+ // delete this triangle from the list so it won't be found again
421
+ const hash = hashEdge( v0, v1 );
422
+ delete halfEdgeList[ hash ];
423
+
424
+ const reverseHash = hashEdge( v1, v0 );
425
+ const otherInfo = halfEdgeList[ reverseHash ];
426
+ if ( otherInfo ) {
427
+
428
+ const otherTri = otherInfo.tri;
429
+ const otherIndex = otherInfo.index;
430
+ const otherNormals = otherTri.normals;
431
+ const otherVertCount = otherNormals.length;
432
+ const otherFaceNormal = otherTri.faceNormal;
433
+
434
+ // NOTE: If the angle between faces is > 67.5 degrees then assume it's
435
+ // hard edge. There are some cases where the line segments do not line up exactly
436
+ // with or span multiple triangle edges (see Lunar Vehicle wheels).
437
+ if ( Math.abs( otherTri.faceNormal.dot( tri.faceNormal ) ) < 0.25 ) {
438
+
439
+ continue;
440
+
441
+ }
442
+
443
+ // if this triangle has already been traversed then it won't be in
444
+ // the halfEdgeList. If it has not then add it to the queue and delete
445
+ // it so it won't be found again.
446
+ if ( reverseHash in halfEdgeList ) {
447
+
448
+ queue.push( otherInfo );
449
+ delete halfEdgeList[ reverseHash ];
450
+
451
+ }
452
+
453
+ // share the first normal
454
+ const otherNext = ( otherIndex + 1 ) % otherVertCount;
455
+ if (
456
+ vertNormals[ index ] && otherNormals[ otherNext ] &&
457
+ vertNormals[ index ] !== otherNormals[ otherNext ]
458
+ ) {
459
+
460
+ otherNormals[ otherNext ].norm.add( vertNormals[ index ].norm );
461
+ vertNormals[ index ].norm = otherNormals[ otherNext ].norm;
462
+
463
+ }
464
+
465
+ let sharedNormal1 = vertNormals[ index ] || otherNormals[ otherNext ];
466
+ if ( sharedNormal1 === null ) {
467
+
468
+ // it's possible to encounter an edge of a triangle that has already been traversed meaning
469
+ // both edges already have different normals defined and shared. To work around this we create
470
+ // a wrapper object so when those edges are merged the normals can be updated everywhere.
471
+ sharedNormal1 = { norm: new Vector3() };
472
+ normals.push( sharedNormal1.norm );
473
+
474
+ }
475
+
476
+ if ( vertNormals[ index ] === null ) {
477
+
478
+ vertNormals[ index ] = sharedNormal1;
479
+ sharedNormal1.norm.add( faceNormal );
480
+
481
+ }
482
+
483
+ if ( otherNormals[ otherNext ] === null ) {
484
+
485
+ otherNormals[ otherNext ] = sharedNormal1;
486
+ sharedNormal1.norm.add( otherFaceNormal );
487
+
488
+ }
489
+
490
+ // share the second normal
491
+ if (
492
+ vertNormals[ next ] && otherNormals[ otherIndex ] &&
493
+ vertNormals[ next ] !== otherNormals[ otherIndex ]
494
+ ) {
495
+
496
+ otherNormals[ otherIndex ].norm.add( vertNormals[ next ].norm );
497
+ vertNormals[ next ].norm = otherNormals[ otherIndex ].norm;
498
+
499
+ }
500
+
501
+ let sharedNormal2 = vertNormals[ next ] || otherNormals[ otherIndex ];
502
+ if ( sharedNormal2 === null ) {
503
+
504
+ sharedNormal2 = { norm: new Vector3() };
505
+ normals.push( sharedNormal2.norm );
506
+
507
+ }
508
+
509
+ if ( vertNormals[ next ] === null ) {
510
+
511
+ vertNormals[ next ] = sharedNormal2;
512
+ sharedNormal2.norm.add( faceNormal );
513
+
514
+ }
515
+
516
+ if ( otherNormals[ otherIndex ] === null ) {
517
+
518
+ otherNormals[ otherIndex ] = sharedNormal2;
519
+ sharedNormal2.norm.add( otherFaceNormal );
520
+
521
+ }
522
+
523
+ }
524
+
525
+ }
526
+
527
+ }
528
+
529
+ }
530
+
531
+ // The normals of each face have been added up so now we average them by normalizing the vector.
532
+ for ( let i = 0, l = normals.length; i < l; i ++ ) {
533
+
534
+ normals[ i ].normalize();
535
+
536
+ }
537
+
538
+ }
539
+
540
+ function isPartType( type ) {
541
+
542
+ return type === 'Part' || type === 'Unofficial_Part';
543
+
544
+ }
545
+
546
+ function isPrimitiveType( type ) {
547
+
548
+ return /primitive/i.test( type ) || type === 'Subpart';
549
+
550
+ }
551
+
552
+ class LineParser {
553
+
554
+ constructor( line, lineNumber ) {
555
+
556
+ this.line = line;
557
+ this.lineLength = line.length;
558
+ this.currentCharIndex = 0;
559
+ this.currentChar = ' ';
560
+ this.lineNumber = lineNumber;
561
+
562
+ }
563
+
564
+ seekNonSpace() {
565
+
566
+ while ( this.currentCharIndex < this.lineLength ) {
567
+
568
+ this.currentChar = this.line.charAt( this.currentCharIndex );
569
+
570
+ if ( this.currentChar !== ' ' && this.currentChar !== '\t' ) {
571
+
572
+ return;
573
+
574
+ }
575
+
576
+ this.currentCharIndex ++;
577
+
578
+ }
579
+
580
+ }
581
+
582
+ getToken() {
583
+
584
+ const pos0 = this.currentCharIndex ++;
585
+
586
+ // Seek space
587
+ while ( this.currentCharIndex < this.lineLength ) {
588
+
589
+ this.currentChar = this.line.charAt( this.currentCharIndex );
590
+
591
+ if ( this.currentChar === ' ' || this.currentChar === '\t' ) {
592
+
593
+ break;
594
+
595
+ }
596
+
597
+ this.currentCharIndex ++;
598
+
599
+ }
600
+
601
+ const pos1 = this.currentCharIndex;
602
+
603
+ this.seekNonSpace();
604
+
605
+ return this.line.substring( pos0, pos1 );
606
+
607
+ }
608
+
609
+ getVector() {
610
+
611
+ return new Vector3( parseFloat( this.getToken() ), parseFloat( this.getToken() ), parseFloat( this.getToken() ) );
612
+
613
+ }
614
+
615
+ getRemainingString() {
616
+
617
+ return this.line.substring( this.currentCharIndex, this.lineLength );
618
+
619
+ }
620
+
621
+ isAtTheEnd() {
622
+
623
+ return this.currentCharIndex >= this.lineLength;
624
+
625
+ }
626
+
627
+ setToEnd() {
628
+
629
+ this.currentCharIndex = this.lineLength;
630
+
631
+ }
632
+
633
+ getLineNumberString() {
634
+
635
+ return this.lineNumber >= 0 ? ' at line ' + this.lineNumber : '';
636
+
637
+ }
638
+
639
+ }
640
+
641
+ // Fetches and parses an intermediate representation of LDraw parts files.
642
+ class LDrawParsedCache {
643
+
644
+ constructor( loader ) {
645
+
646
+ this.loader = loader;
647
+ this._cache = {};
648
+
649
+ }
650
+
651
+ cloneResult( original ) {
652
+
653
+ const result = {};
654
+
655
+ // vertices are transformed and normals computed before being converted to geometry
656
+ // so these pieces must be cloned.
657
+ result.faces = original.faces.map( face => {
658
+
659
+ return {
660
+ colorCode: face.colorCode,
661
+ material: face.material,
662
+ vertices: face.vertices.map( v => v.clone() ),
663
+ normals: face.normals.map( () => null ),
664
+ faceNormal: null
665
+ };
666
+
667
+ } );
668
+
669
+ result.conditionalSegments = original.conditionalSegments.map( face => {
670
+
671
+ return {
672
+ colorCode: face.colorCode,
673
+ material: face.material,
674
+ vertices: face.vertices.map( v => v.clone() ),
675
+ controlPoints: face.controlPoints.map( v => v.clone() )
676
+ };
677
+
678
+ } );
679
+
680
+ result.lineSegments = original.lineSegments.map( face => {
681
+
682
+ return {
683
+ colorCode: face.colorCode,
684
+ material: face.material,
685
+ vertices: face.vertices.map( v => v.clone() )
686
+ };
687
+
688
+ } );
689
+
690
+ // none if this is subsequently modified
691
+ result.type = original.type;
692
+ result.category = original.category;
693
+ result.keywords = original.keywords;
694
+ result.author = original.author;
695
+ result.subobjects = original.subobjects;
696
+ result.fileName = original.fileName;
697
+ result.totalFaces = original.totalFaces;
698
+ result.startingBuildingStep = original.startingBuildingStep;
699
+ result.materials = original.materials;
700
+ result.group = null;
701
+ return result;
702
+
703
+ }
704
+
705
+ async fetchData( fileName ) {
706
+
707
+ let triedLowerCase = false;
708
+ let locationState = FILE_LOCATION_TRY_PARTS;
709
+ while ( locationState !== FILE_LOCATION_NOT_FOUND ) {
710
+
711
+ let subobjectURL = fileName;
712
+ switch ( locationState ) {
713
+
714
+ case FILE_LOCATION_AS_IS:
715
+ locationState = locationState + 1;
716
+ break;
717
+
718
+ case FILE_LOCATION_TRY_PARTS:
719
+ subobjectURL = 'parts/' + subobjectURL;
720
+ locationState = locationState + 1;
721
+ break;
722
+
723
+ case FILE_LOCATION_TRY_P:
724
+ subobjectURL = 'p/' + subobjectURL;
725
+ locationState = locationState + 1;
726
+ break;
727
+
728
+ case FILE_LOCATION_TRY_MODELS:
729
+ subobjectURL = 'models/' + subobjectURL;
730
+ locationState = locationState + 1;
731
+ break;
732
+
733
+ case FILE_LOCATION_TRY_RELATIVE:
734
+ subobjectURL = fileName.substring( 0, fileName.lastIndexOf( '/' ) + 1 ) + subobjectURL;
735
+ locationState = locationState + 1;
736
+ break;
737
+
738
+ case FILE_LOCATION_TRY_ABSOLUTE:
739
+
740
+ if ( triedLowerCase ) {
741
+
742
+ // Try absolute path
743
+ locationState = FILE_LOCATION_NOT_FOUND;
744
+
745
+ } else {
746
+
747
+ // Next attempt is lower case
748
+ fileName = fileName.toLowerCase();
749
+ subobjectURL = fileName;
750
+ triedLowerCase = true;
751
+ locationState = FILE_LOCATION_TRY_PARTS;
752
+
753
+ }
754
+
755
+ break;
756
+
757
+ }
758
+
759
+ const loader = this.loader;
760
+ const fileLoader = new FileLoader( loader.manager );
761
+ fileLoader.setPath( loader.partsLibraryPath );
762
+ fileLoader.setRequestHeader( loader.requestHeader );
763
+ fileLoader.setWithCredentials( loader.withCredentials );
764
+
765
+ try {
766
+
767
+ const text = await fileLoader.loadAsync( subobjectURL );
768
+ return text;
769
+
770
+ } catch ( _ ) {
771
+
772
+ continue;
773
+
774
+ }
775
+
776
+ }
777
+
778
+ throw new Error( 'LDrawLoader: Subobject "' + fileName + '" could not be loaded.' );
779
+
780
+ }
781
+
782
+ parse( text, fileName = null ) {
783
+
784
+ const loader = this.loader;
785
+
786
+ // final results
787
+ const faces = [];
788
+ const lineSegments = [];
789
+ const conditionalSegments = [];
790
+ const subobjects = [];
791
+ const materials = {};
792
+
793
+ const getLocalMaterial = colorCode => {
794
+
795
+ return materials[ colorCode ] || null;
796
+
797
+ };
798
+
799
+ let type = 'Model';
800
+ let category = null;
801
+ let keywords = null;
802
+ let author = null;
803
+ let totalFaces = 0;
804
+
805
+ // split into lines
806
+ if ( text.indexOf( '\r\n' ) !== - 1 ) {
807
+
808
+ // This is faster than String.split with regex that splits on both
809
+ text = text.replace( /\r\n/g, '\n' );
810
+
811
+ }
812
+
813
+ const lines = text.split( '\n' );
814
+ const numLines = lines.length;
815
+
816
+ let parsingEmbeddedFiles = false;
817
+ let currentEmbeddedFileName = null;
818
+ let currentEmbeddedText = null;
819
+
820
+ let bfcCertified = false;
821
+ let bfcCCW = true;
822
+ let bfcInverted = false;
823
+ let bfcCull = true;
824
+
825
+ let startingBuildingStep = false;
826
+
827
+ // Parse all line commands
828
+ for ( let lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
829
+
830
+ const line = lines[ lineIndex ];
831
+
832
+ if ( line.length === 0 ) continue;
833
+
834
+ if ( parsingEmbeddedFiles ) {
835
+
836
+ if ( line.startsWith( '0 FILE ' ) ) {
837
+
838
+ // Save previous embedded file in the cache
839
+ this.setData( currentEmbeddedFileName, currentEmbeddedText );
840
+
841
+ // New embedded text file
842
+ currentEmbeddedFileName = line.substring( 7 );
843
+ currentEmbeddedText = '';
844
+
845
+ } else {
846
+
847
+ currentEmbeddedText += line + '\n';
848
+
849
+ }
850
+
851
+ continue;
852
+
853
+ }
854
+
855
+ const lp = new LineParser( line, lineIndex + 1 );
856
+ lp.seekNonSpace();
857
+
858
+ if ( lp.isAtTheEnd() ) {
859
+
860
+ // Empty line
861
+ continue;
862
+
863
+ }
864
+
865
+ // Parse the line type
866
+ const lineType = lp.getToken();
867
+
868
+ let material;
869
+ let colorCode;
870
+ let segment;
871
+ let ccw;
872
+ let doubleSided;
873
+ let v0, v1, v2, v3, c0, c1;
874
+
875
+ switch ( lineType ) {
876
+
877
+ // Line type 0: Comment or META
878
+ case '0':
879
+
880
+ // Parse meta directive
881
+ const meta = lp.getToken();
882
+
883
+ if ( meta ) {
884
+
885
+ switch ( meta ) {
886
+
887
+ case '!LDRAW_ORG':
888
+
889
+ type = lp.getToken();
890
+ break;
891
+
892
+ case '!COLOUR':
893
+
894
+ material = loader.parseColorMetaDirective( lp );
895
+ if ( material ) {
896
+
897
+ materials[ material.userData.code ] = material;
898
+
899
+ } else {
900
+
901
+ console.warn( 'LDrawLoader: Error parsing material' + lp.getLineNumberString() );
902
+
903
+ }
904
+
905
+ break;
906
+
907
+ case '!CATEGORY':
908
+
909
+ category = lp.getToken();
910
+ break;
911
+
912
+ case '!KEYWORDS':
913
+
914
+ const newKeywords = lp.getRemainingString().split( ',' );
915
+ if ( newKeywords.length > 0 ) {
916
+
917
+ if ( ! keywords ) {
918
+
919
+ keywords = [];
920
+
921
+ }
922
+
923
+ newKeywords.forEach( function ( keyword ) {
924
+
925
+ keywords.push( keyword.trim() );
926
+
927
+ } );
928
+
929
+ }
930
+
931
+ break;
932
+
933
+ case 'FILE':
934
+
935
+ if ( lineIndex > 0 ) {
936
+
937
+ // Start embedded text files parsing
938
+ parsingEmbeddedFiles = true;
939
+ currentEmbeddedFileName = lp.getRemainingString();
940
+ currentEmbeddedText = '';
941
+
942
+ bfcCertified = false;
943
+ bfcCCW = true;
944
+
945
+ }
946
+
947
+ break;
948
+
949
+ case 'BFC':
950
+
951
+ // Changes to the backface culling state
952
+ while ( ! lp.isAtTheEnd() ) {
953
+
954
+ const token = lp.getToken();
955
+
956
+ switch ( token ) {
957
+
958
+ case 'CERTIFY':
959
+ case 'NOCERTIFY':
960
+
961
+ bfcCertified = token === 'CERTIFY';
962
+ bfcCCW = true;
963
+
964
+ break;
965
+
966
+ case 'CW':
967
+ case 'CCW':
968
+
969
+ bfcCCW = token === 'CCW';
970
+
971
+ break;
972
+
973
+ case 'INVERTNEXT':
974
+
975
+ bfcInverted = true;
976
+
977
+ break;
978
+
979
+ case 'CLIP':
980
+ case 'NOCLIP':
981
+
982
+ bfcCull = token === 'CLIP';
983
+
984
+ break;
985
+
986
+ default:
987
+
988
+ console.warn( 'THREE.LDrawLoader: BFC directive "' + token + '" is unknown.' );
989
+
990
+ break;
991
+
992
+ }
993
+
994
+ }
995
+
996
+ break;
997
+
998
+ case 'STEP':
999
+
1000
+ startingBuildingStep = true;
1001
+
1002
+ break;
1003
+
1004
+ case 'Author:':
1005
+
1006
+ author = lp.getToken();
1007
+
1008
+ break;
1009
+
1010
+ default:
1011
+ // Other meta directives are not implemented
1012
+ break;
1013
+
1014
+ }
1015
+
1016
+ }
1017
+
1018
+ break;
1019
+
1020
+ // Line type 1: Sub-object file
1021
+ case '1':
1022
+
1023
+ colorCode = lp.getToken();
1024
+ material = getLocalMaterial( colorCode );
1025
+
1026
+ const posX = parseFloat( lp.getToken() );
1027
+ const posY = parseFloat( lp.getToken() );
1028
+ const posZ = parseFloat( lp.getToken() );
1029
+ const m0 = parseFloat( lp.getToken() );
1030
+ const m1 = parseFloat( lp.getToken() );
1031
+ const m2 = parseFloat( lp.getToken() );
1032
+ const m3 = parseFloat( lp.getToken() );
1033
+ const m4 = parseFloat( lp.getToken() );
1034
+ const m5 = parseFloat( lp.getToken() );
1035
+ const m6 = parseFloat( lp.getToken() );
1036
+ const m7 = parseFloat( lp.getToken() );
1037
+ const m8 = parseFloat( lp.getToken() );
1038
+
1039
+ const matrix = new Matrix4().set(
1040
+ m0, m1, m2, posX,
1041
+ m3, m4, m5, posY,
1042
+ m6, m7, m8, posZ,
1043
+ 0, 0, 0, 1
1044
+ );
1045
+
1046
+ let fileName = lp.getRemainingString().trim().replace( /\\/g, '/' );
1047
+
1048
+ if ( loader.fileMap[ fileName ] ) {
1049
+
1050
+ // Found the subobject path in the preloaded file path map
1051
+ fileName = loader.fileMap[ fileName ];
1052
+
1053
+ } else {
1054
+
1055
+ // Standardized subfolders
1056
+ if ( fileName.startsWith( 's/' ) ) {
1057
+
1058
+ fileName = 'parts/' + fileName;
1059
+
1060
+ } else if ( fileName.startsWith( '48/' ) ) {
1061
+
1062
+ fileName = 'p/' + fileName;
1063
+
1064
+ }
1065
+
1066
+ }
1067
+
1068
+ subobjects.push( {
1069
+ material: material,
1070
+ colorCode: colorCode,
1071
+ matrix: matrix,
1072
+ fileName: fileName,
1073
+ inverted: bfcInverted,
1074
+ startingBuildingStep: startingBuildingStep
1075
+ } );
1076
+
1077
+ startingBuildingStep = false;
1078
+ bfcInverted = false;
1079
+
1080
+ break;
1081
+
1082
+ // Line type 2: Line segment
1083
+ case '2':
1084
+
1085
+ colorCode = lp.getToken();
1086
+ material = getLocalMaterial( colorCode );
1087
+ v0 = lp.getVector();
1088
+ v1 = lp.getVector();
1089
+
1090
+ segment = {
1091
+ material: material,
1092
+ colorCode: colorCode,
1093
+ vertices: [ v0, v1 ],
1094
+ };
1095
+
1096
+ lineSegments.push( segment );
1097
+
1098
+ break;
1099
+
1100
+ // Line type 5: Conditional Line segment
1101
+ case '5':
1102
+
1103
+ colorCode = lp.getToken();
1104
+ material = getLocalMaterial( colorCode );
1105
+ v0 = lp.getVector();
1106
+ v1 = lp.getVector();
1107
+ c0 = lp.getVector();
1108
+ c1 = lp.getVector();
1109
+
1110
+ segment = {
1111
+ material: material,
1112
+ colorCode: colorCode,
1113
+ vertices: [ v0, v1 ],
1114
+ controlPoints: [ c0, c1 ],
1115
+ };
1116
+
1117
+ conditionalSegments.push( segment );
1118
+
1119
+ break;
1120
+
1121
+ // Line type 3: Triangle
1122
+ case '3':
1123
+
1124
+ colorCode = lp.getToken();
1125
+ material = getLocalMaterial( colorCode );
1126
+ ccw = bfcCCW;
1127
+ doubleSided = ! bfcCertified || ! bfcCull;
1128
+
1129
+ if ( ccw === true ) {
1130
+
1131
+ v0 = lp.getVector();
1132
+ v1 = lp.getVector();
1133
+ v2 = lp.getVector();
1134
+
1135
+ } else {
1136
+
1137
+ v2 = lp.getVector();
1138
+ v1 = lp.getVector();
1139
+ v0 = lp.getVector();
1140
+
1141
+ }
1142
+
1143
+ faces.push( {
1144
+ material: material,
1145
+ colorCode: colorCode,
1146
+ faceNormal: null,
1147
+ vertices: [ v0, v1, v2 ],
1148
+ normals: [ null, null, null ],
1149
+ } );
1150
+ totalFaces ++;
1151
+
1152
+ if ( doubleSided === true ) {
1153
+
1154
+ faces.push( {
1155
+ material: material,
1156
+ colorCode: colorCode,
1157
+ faceNormal: null,
1158
+ vertices: [ v2, v1, v0 ],
1159
+ normals: [ null, null, null ],
1160
+ } );
1161
+ totalFaces ++;
1162
+
1163
+ }
1164
+
1165
+ break;
1166
+
1167
+ // Line type 4: Quadrilateral
1168
+ case '4':
1169
+
1170
+ colorCode = lp.getToken();
1171
+ material = getLocalMaterial( colorCode );
1172
+ ccw = bfcCCW;
1173
+ doubleSided = ! bfcCertified || ! bfcCull;
1174
+
1175
+ if ( ccw === true ) {
1176
+
1177
+ v0 = lp.getVector();
1178
+ v1 = lp.getVector();
1179
+ v2 = lp.getVector();
1180
+ v3 = lp.getVector();
1181
+
1182
+ } else {
1183
+
1184
+ v3 = lp.getVector();
1185
+ v2 = lp.getVector();
1186
+ v1 = lp.getVector();
1187
+ v0 = lp.getVector();
1188
+
1189
+ }
1190
+
1191
+ // specifically place the triangle diagonal in the v0 and v1 slots so we can
1192
+ // account for the doubling of vertices later when smoothing normals.
1193
+ faces.push( {
1194
+ material: material,
1195
+ colorCode: colorCode,
1196
+ faceNormal: null,
1197
+ vertices: [ v0, v1, v2, v3 ],
1198
+ normals: [ null, null, null, null ],
1199
+ } );
1200
+ totalFaces += 2;
1201
+
1202
+ if ( doubleSided === true ) {
1203
+
1204
+ faces.push( {
1205
+ material: material,
1206
+ colorCode: colorCode,
1207
+ faceNormal: null,
1208
+ vertices: [ v3, v2, v1, v0 ],
1209
+ normals: [ null, null, null, null ],
1210
+ } );
1211
+ totalFaces += 2;
1212
+
1213
+ }
1214
+
1215
+ break;
1216
+
1217
+ default:
1218
+ throw new Error( 'LDrawLoader: Unknown line type "' + lineType + '"' + lp.getLineNumberString() + '.' );
1219
+
1220
+ }
1221
+
1222
+ }
1223
+
1224
+ if ( parsingEmbeddedFiles ) {
1225
+
1226
+ this.setData( currentEmbeddedFileName, currentEmbeddedText );
1227
+
1228
+ }
1229
+
1230
+ return {
1231
+ faces,
1232
+ conditionalSegments,
1233
+ lineSegments,
1234
+ type,
1235
+ category,
1236
+ keywords,
1237
+ author,
1238
+ subobjects,
1239
+ totalFaces,
1240
+ startingBuildingStep,
1241
+ materials,
1242
+ fileName,
1243
+ group: null
1244
+ };
1245
+
1246
+ }
1247
+
1248
+ // returns an (optionally cloned) instance of the data
1249
+ getData( fileName, clone = true ) {
1250
+
1251
+ const key = fileName.toLowerCase();
1252
+ const result = this._cache[ key ];
1253
+ if ( result === null || result instanceof Promise ) {
1254
+
1255
+ return null;
1256
+
1257
+ }
1258
+
1259
+ if ( clone ) {
1260
+
1261
+ return this.cloneResult( result );
1262
+
1263
+ } else {
1264
+
1265
+ return result;
1266
+
1267
+ }
1268
+
1269
+ }
1270
+
1271
+ // kicks off a fetch and parse of the requested data if it hasn't already been loaded. Returns when
1272
+ // the data is ready to use and can be retrieved synchronously with "getData".
1273
+ async ensureDataLoaded( fileName ) {
1274
+
1275
+ const key = fileName.toLowerCase();
1276
+ if ( ! ( key in this._cache ) ) {
1277
+
1278
+ // replace the promise with a copy of the parsed data for immediate processing
1279
+ this._cache[ key ] = this.fetchData( fileName ).then( text => {
1280
+
1281
+ const info = this.parse( text, fileName );
1282
+ this._cache[ key ] = info;
1283
+ return info;
1284
+
1285
+ } );
1286
+
1287
+ }
1288
+
1289
+ await this._cache[ key ];
1290
+
1291
+ }
1292
+
1293
+ // sets the data in the cache from parsed data
1294
+ setData( fileName, text ) {
1295
+
1296
+ const key = fileName.toLowerCase();
1297
+ this._cache[ key ] = this.parse( text, fileName );
1298
+
1299
+ }
1300
+
1301
+ }
1302
+
1303
+ // returns the material for an associated color code. If the color code is 16 for a face or 24 for
1304
+ // an edge then the passthroughColorCode is used.
1305
+ function getMaterialFromCode( colorCode, parentColorCode, materialHierarchy, forEdge ) {
1306
+
1307
+ const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
1308
+ if ( isPassthrough ) {
1309
+
1310
+ colorCode = parentColorCode;
1311
+
1312
+ }
1313
+
1314
+ return materialHierarchy[ colorCode ] || null;
1315
+
1316
+ }
1317
+
1318
+ // Class used to parse and build LDraw parts as three.js objects and cache them if they're a "Part" type.
1319
+ class LDrawPartsGeometryCache {
1320
+
1321
+ constructor( loader ) {
1322
+
1323
+ this.loader = loader;
1324
+ this.parseCache = new LDrawParsedCache( loader );
1325
+ this._cache = {};
1326
+
1327
+ }
1328
+
1329
+ // Convert the given file information into a mesh by processing subobjects.
1330
+ async processIntoMesh( info ) {
1331
+
1332
+ const loader = this.loader;
1333
+ const parseCache = this.parseCache;
1334
+ const faceMaterials = new Set();
1335
+
1336
+ // Processes the part subobject information to load child parts and merge geometry onto part
1337
+ // piece object.
1338
+ const processInfoSubobjects = async ( info, subobject = null ) => {
1339
+
1340
+ const subobjects = info.subobjects;
1341
+ const promises = [];
1342
+
1343
+ // Trigger load of all subobjects. If a subobject isn't a primitive then load it as a separate
1344
+ // group which lets instruction steps apply correctly.
1345
+ for ( let i = 0, l = subobjects.length; i < l; i ++ ) {
1346
+
1347
+ const subobject = subobjects[ i ];
1348
+ const promise = parseCache.ensureDataLoaded( subobject.fileName ).then( () => {
1349
+
1350
+ const subobjectInfo = parseCache.getData( subobject.fileName, false );
1351
+ if ( ! isPrimitiveType( subobjectInfo.type ) ) {
1352
+
1353
+ return this.loadModel( subobject.fileName ).catch( error => {
1354
+
1355
+ console.warn( error );
1356
+ return null;
1357
+
1358
+ } );
1359
+
1360
+ }
1361
+
1362
+ return processInfoSubobjects( parseCache.getData( subobject.fileName ), subobject );
1363
+
1364
+ } );
1365
+
1366
+ promises.push( promise );
1367
+
1368
+ }
1369
+
1370
+ const group = new Group();
1371
+ group.userData.category = info.category;
1372
+ group.userData.keywords = info.keywords;
1373
+ group.userData.author = info.author;
1374
+ group.userData.type = info.type;
1375
+ group.userData.fileName = info.fileName;
1376
+ info.group = group;
1377
+
1378
+ const subobjectInfos = await Promise.all( promises );
1379
+ for ( let i = 0, l = subobjectInfos.length; i < l; i ++ ) {
1380
+
1381
+ const subobject = info.subobjects[ i ];
1382
+ const subobjectInfo = subobjectInfos[ i ];
1383
+
1384
+ if ( subobjectInfo === null ) {
1385
+
1386
+ // the subobject failed to load
1387
+ continue;
1388
+
1389
+ }
1390
+
1391
+ // if the subobject was loaded as a separate group then apply the parent scopes materials
1392
+ if ( subobjectInfo.isGroup ) {
1393
+
1394
+ const subobjectGroup = subobjectInfo;
1395
+ subobject.matrix.decompose( subobjectGroup.position, subobjectGroup.quaternion, subobjectGroup.scale );
1396
+ subobjectGroup.userData.startingBuildingStep = subobject.startingBuildingStep;
1397
+ subobjectGroup.name = subobject.fileName;
1398
+
1399
+ loader.applyMaterialsToMesh( subobjectGroup, subobject.colorCode, info.materials );
1400
+ subobjectGroup.userData.colorCode = subobject.colorCode;
1401
+
1402
+ group.add( subobjectGroup );
1403
+ continue;
1404
+
1405
+ }
1406
+
1407
+ // add the subobject group if it has children in case it has both children and primitives
1408
+ if ( subobjectInfo.group.children.length ) {
1409
+
1410
+ group.add( subobjectInfo.group );
1411
+
1412
+ }
1413
+
1414
+ // transform the primitives into the local space of the parent piece and append them to
1415
+ // to the parent primitives list.
1416
+ const parentLineSegments = info.lineSegments;
1417
+ const parentConditionalSegments = info.conditionalSegments;
1418
+ const parentFaces = info.faces;
1419
+
1420
+ const lineSegments = subobjectInfo.lineSegments;
1421
+ const conditionalSegments = subobjectInfo.conditionalSegments;
1422
+
1423
+ const faces = subobjectInfo.faces;
1424
+ const matrix = subobject.matrix;
1425
+ const inverted = subobject.inverted;
1426
+ const matrixScaleInverted = matrix.determinant() < 0;
1427
+ const colorCode = subobject.colorCode;
1428
+
1429
+ const lineColorCode = colorCode === MAIN_COLOUR_CODE ? MAIN_EDGE_COLOUR_CODE : colorCode;
1430
+ for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
1431
+
1432
+ const ls = lineSegments[ i ];
1433
+ const vertices = ls.vertices;
1434
+ vertices[ 0 ].applyMatrix4( matrix );
1435
+ vertices[ 1 ].applyMatrix4( matrix );
1436
+ ls.colorCode = ls.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : ls.colorCode;
1437
+ ls.material = ls.material || getMaterialFromCode( ls.colorCode, ls.colorCode, info.materials, true );
1438
+
1439
+ parentLineSegments.push( ls );
1440
+
1441
+ }
1442
+
1443
+ for ( let i = 0, l = conditionalSegments.length; i < l; i ++ ) {
1444
+
1445
+ const os = conditionalSegments[ i ];
1446
+ const vertices = os.vertices;
1447
+ const controlPoints = os.controlPoints;
1448
+ vertices[ 0 ].applyMatrix4( matrix );
1449
+ vertices[ 1 ].applyMatrix4( matrix );
1450
+ controlPoints[ 0 ].applyMatrix4( matrix );
1451
+ controlPoints[ 1 ].applyMatrix4( matrix );
1452
+ os.colorCode = os.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : os.colorCode;
1453
+ os.material = os.material || getMaterialFromCode( os.colorCode, os.colorCode, info.materials, true );
1454
+
1455
+ parentConditionalSegments.push( os );
1456
+
1457
+ }
1458
+
1459
+ for ( let i = 0, l = faces.length; i < l; i ++ ) {
1460
+
1461
+ const tri = faces[ i ];
1462
+ const vertices = tri.vertices;
1463
+ for ( let i = 0, l = vertices.length; i < l; i ++ ) {
1464
+
1465
+ vertices[ i ].applyMatrix4( matrix );
1466
+
1467
+ }
1468
+
1469
+ tri.colorCode = tri.colorCode === MAIN_COLOUR_CODE ? colorCode : tri.colorCode;
1470
+ tri.material = tri.material || getMaterialFromCode( tri.colorCode, colorCode, info.materials, false );
1471
+ faceMaterials.add( tri.colorCode );
1472
+
1473
+ // If the scale of the object is negated then the triangle winding order
1474
+ // needs to be flipped.
1475
+ if ( matrixScaleInverted !== inverted ) {
1476
+
1477
+ vertices.reverse();
1478
+
1479
+ }
1480
+
1481
+ parentFaces.push( tri );
1482
+
1483
+ }
1484
+
1485
+ info.totalFaces += subobjectInfo.totalFaces;
1486
+
1487
+ }
1488
+
1489
+ // Apply the parent subobjects pass through material code to this object. This is done several times due
1490
+ // to material scoping.
1491
+ if ( subobject ) {
1492
+
1493
+ loader.applyMaterialsToMesh( group, subobject.colorCode, info.materials );
1494
+ group.userData.colorCode = subobject.colorCode;
1495
+
1496
+ }
1497
+
1498
+ return info;
1499
+
1500
+ };
1501
+
1502
+ // Track material use to see if we need to use the normal smooth slow path for hard edges.
1503
+ for ( let i = 0, l = info.faces; i < l; i ++ ) {
1504
+
1505
+ faceMaterials.add( info.faces[ i ].colorCode );
1506
+
1507
+ }
1508
+
1509
+ await processInfoSubobjects( info );
1510
+
1511
+ if ( loader.smoothNormals ) {
1512
+
1513
+ const checkSubSegments = faceMaterials.size > 1;
1514
+ generateFaceNormals( info.faces );
1515
+ smoothNormals( info.faces, info.lineSegments, checkSubSegments );
1516
+
1517
+ }
1518
+
1519
+ // Add the primitive objects and metadata.
1520
+ const group = info.group;
1521
+ if ( info.faces.length > 0 ) {
1522
+
1523
+ group.add( createObject( this.loader, info.faces, 3, false, info.totalFaces ) );
1524
+
1525
+ }
1526
+
1527
+ if ( info.lineSegments.length > 0 ) {
1528
+
1529
+ group.add( createObject( this.loader, info.lineSegments, 2 ) );
1530
+
1531
+ }
1532
+
1533
+ if ( info.conditionalSegments.length > 0 ) {
1534
+
1535
+ group.add( createObject( this.loader, info.conditionalSegments, 2, true ) );
1536
+
1537
+ }
1538
+
1539
+ return group;
1540
+
1541
+ }
1542
+
1543
+ hasCachedModel( fileName ) {
1544
+
1545
+ return fileName !== null && fileName.toLowerCase() in this._cache;
1546
+
1547
+ }
1548
+
1549
+ async getCachedModel( fileName ) {
1550
+
1551
+ if ( fileName !== null && this.hasCachedModel( fileName ) ) {
1552
+
1553
+ const key = fileName.toLowerCase();
1554
+ const group = await this._cache[ key ];
1555
+ return group.clone();
1556
+
1557
+ } else {
1558
+
1559
+ return null;
1560
+
1561
+ }
1562
+
1563
+ }
1564
+
1565
+ // Loads and parses the model with the given file name. Returns a cached copy if available.
1566
+ async loadModel( fileName ) {
1567
+
1568
+ const parseCache = this.parseCache;
1569
+ const key = fileName.toLowerCase();
1570
+ if ( this.hasCachedModel( fileName ) ) {
1571
+
1572
+ // Return cached model if available.
1573
+ return this.getCachedModel( fileName );
1574
+
1575
+ } else {
1576
+
1577
+ // Otherwise parse a new model.
1578
+ // Ensure the file data is loaded and pre parsed.
1579
+ await parseCache.ensureDataLoaded( fileName );
1580
+
1581
+ const info = parseCache.getData( fileName );
1582
+ const promise = this.processIntoMesh( info );
1583
+
1584
+ // Now that the file has loaded it's possible that another part parse has been waiting in parallel
1585
+ // so check the cache again to see if it's been added since the last async operation so we don't
1586
+ // do unnecessary work.
1587
+ if ( this.hasCachedModel( fileName ) ) {
1588
+
1589
+ return this.getCachedModel( fileName );
1590
+
1591
+ }
1592
+
1593
+ // Cache object if it's a part so it can be reused later.
1594
+ if ( isPartType( info.type ) ) {
1595
+
1596
+ this._cache[ key ] = promise;
1597
+
1598
+ }
1599
+
1600
+ // return a copy
1601
+ const group = await promise;
1602
+ return group.clone();
1603
+
1604
+ }
1605
+
1606
+ }
1607
+
1608
+ // parses the given model text into a renderable object. Returns cached copy if available.
1609
+ async parseModel( text ) {
1610
+
1611
+ const parseCache = this.parseCache;
1612
+ const info = parseCache.parse( text );
1613
+ if ( isPartType( info.type ) && this.hasCachedModel( info.fileName ) ) {
1614
+
1615
+ return this.getCachedModel( info.fileName );
1616
+
1617
+ }
1618
+
1619
+ return this.processIntoMesh( info );
1620
+
1621
+ }
1622
+
1623
+ }
1624
+
1625
+ function sortByMaterial( a, b ) {
1626
+
1627
+ if ( a.colorCode === b.colorCode ) {
1628
+
1629
+ return 0;
1630
+
1631
+ }
1632
+
1633
+ if ( a.colorCode < b.colorCode ) {
1634
+
1635
+ return - 1;
1636
+
1637
+ }
1638
+
1639
+ return 1;
1640
+
1641
+ }
1642
+
1643
+ function createObject( loader, elements, elementSize, isConditionalSegments = false, totalElements = null ) {
1644
+
1645
+ // Creates a LineSegments (elementSize = 2) or a Mesh (elementSize = 3 )
1646
+ // With per face / segment material, implemented with mesh groups and materials array
1647
+
1648
+ // Sort the faces or line segments by color code to make later the mesh groups
1649
+ elements.sort( sortByMaterial );
1650
+
1651
+ if ( totalElements === null ) {
1652
+
1653
+ totalElements = elements.length;
1654
+
1655
+ }
1656
+
1657
+ const positions = new Float32Array( elementSize * totalElements * 3 );
1658
+ const normals = elementSize === 3 ? new Float32Array( elementSize * totalElements * 3 ) : null;
1659
+ const materials = [];
1660
+
1661
+ const quadArray = new Array( 6 );
1662
+ const bufferGeometry = new BufferGeometry();
1663
+ let prevMaterial = null;
1664
+ let index0 = 0;
1665
+ let numGroupVerts = 0;
1666
+ let offset = 0;
1667
+
1668
+ for ( let iElem = 0, nElem = elements.length; iElem < nElem; iElem ++ ) {
1669
+
1670
+ const elem = elements[ iElem ];
1671
+ let vertices = elem.vertices;
1672
+ if ( vertices.length === 4 ) {
1673
+
1674
+ quadArray[ 0 ] = vertices[ 0 ];
1675
+ quadArray[ 1 ] = vertices[ 1 ];
1676
+ quadArray[ 2 ] = vertices[ 2 ];
1677
+ quadArray[ 3 ] = vertices[ 0 ];
1678
+ quadArray[ 4 ] = vertices[ 2 ];
1679
+ quadArray[ 5 ] = vertices[ 3 ];
1680
+ vertices = quadArray;
1681
+
1682
+ }
1683
+
1684
+ for ( let j = 0, l = vertices.length; j < l; j ++ ) {
1685
+
1686
+ const v = vertices[ j ];
1687
+ const index = offset + j * 3;
1688
+ positions[ index + 0 ] = v.x;
1689
+ positions[ index + 1 ] = v.y;
1690
+ positions[ index + 2 ] = v.z;
1691
+
1692
+ }
1693
+
1694
+ // create the normals array if this is a set of faces
1695
+ if ( elementSize === 3 ) {
1696
+
1697
+ if ( ! elem.faceNormal ) {
1698
+
1699
+ const v0 = vertices[ 0 ];
1700
+ const v1 = vertices[ 1 ];
1701
+ const v2 = vertices[ 2 ];
1702
+ _tempVec0.subVectors( v1, v0 );
1703
+ _tempVec1.subVectors( v2, v1 );
1704
+ elem.faceNormal = new Vector3()
1705
+ .crossVectors( _tempVec0, _tempVec1 )
1706
+ .normalize();
1707
+
1708
+ }
1709
+
1710
+ let elemNormals = elem.normals;
1711
+ if ( elemNormals.length === 4 ) {
1712
+
1713
+ quadArray[ 0 ] = elemNormals[ 0 ];
1714
+ quadArray[ 1 ] = elemNormals[ 1 ];
1715
+ quadArray[ 2 ] = elemNormals[ 2 ];
1716
+ quadArray[ 3 ] = elemNormals[ 0 ];
1717
+ quadArray[ 4 ] = elemNormals[ 2 ];
1718
+ quadArray[ 5 ] = elemNormals[ 3 ];
1719
+ elemNormals = quadArray;
1720
+
1721
+ }
1722
+
1723
+ for ( let j = 0, l = elemNormals.length; j < l; j ++ ) {
1724
+
1725
+ // use face normal if a vertex normal is not provided
1726
+ let n = elem.faceNormal;
1727
+ if ( elemNormals[ j ] ) {
1728
+
1729
+ n = elemNormals[ j ].norm;
1730
+
1731
+ }
1732
+
1733
+ const index = offset + j * 3;
1734
+ normals[ index + 0 ] = n.x;
1735
+ normals[ index + 1 ] = n.y;
1736
+ normals[ index + 2 ] = n.z;
1737
+
1738
+ }
1739
+
1740
+ }
1741
+
1742
+ if ( prevMaterial !== elem.colorCode ) {
1743
+
1744
+ if ( prevMaterial !== null ) {
1745
+
1746
+ bufferGeometry.addGroup( index0, numGroupVerts, materials.length - 1 );
1747
+
1748
+ }
1749
+
1750
+ const material = elem.material;
1751
+
1752
+ if ( material !== null ) {
1753
+
1754
+ if ( elementSize === 3 ) {
1755
+
1756
+ materials.push( material );
1757
+
1758
+ } else if ( elementSize === 2 ) {
1759
+
1760
+ if ( isConditionalSegments ) {
1761
+
1762
+ const edgeMaterial = loader.edgeMaterialCache.get( material );
1763
+
1764
+ materials.push( loader.conditionalEdgeMaterialCache.get( edgeMaterial ) );
1765
+
1766
+ } else {
1767
+
1768
+ materials.push( loader.edgeMaterialCache.get( material ) );
1769
+
1770
+ }
1771
+
1772
+ }
1773
+
1774
+ } else {
1775
+
1776
+ // If a material has not been made available yet then keep the color code string in the material array
1777
+ // to save the spot for the material once a parent scopes materials are being applied to the object.
1778
+ materials.push( elem.colorCode );
1779
+
1780
+ }
1781
+
1782
+ prevMaterial = elem.colorCode;
1783
+ index0 = offset / 3;
1784
+ numGroupVerts = vertices.length;
1785
+
1786
+ } else {
1787
+
1788
+ numGroupVerts += vertices.length;
1789
+
1790
+ }
1791
+
1792
+ offset += 3 * vertices.length;
1793
+
1794
+ }
1795
+
1796
+ if ( numGroupVerts > 0 ) {
1797
+
1798
+ bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
1799
+
1800
+ }
1801
+
1802
+ bufferGeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
1803
+
1804
+ if ( normals !== null ) {
1805
+
1806
+ bufferGeometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
1807
+
1808
+ }
1809
+
1810
+ let object3d = null;
1811
+
1812
+ if ( elementSize === 2 ) {
1813
+
1814
+ if ( isConditionalSegments ) {
1815
+
1816
+ object3d = new ConditionalLineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1817
+
1818
+ } else {
1819
+
1820
+ object3d = new LineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1821
+
1822
+ }
1823
+
1824
+ } else if ( elementSize === 3 ) {
1825
+
1826
+ object3d = new Mesh( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1827
+
1828
+ }
1829
+
1830
+ if ( isConditionalSegments ) {
1831
+
1832
+ object3d.isConditionalLine = true;
1833
+
1834
+ const controlArray0 = new Float32Array( elements.length * 3 * 2 );
1835
+ const controlArray1 = new Float32Array( elements.length * 3 * 2 );
1836
+ const directionArray = new Float32Array( elements.length * 3 * 2 );
1837
+ for ( let i = 0, l = elements.length; i < l; i ++ ) {
1838
+
1839
+ const os = elements[ i ];
1840
+ const vertices = os.vertices;
1841
+ const controlPoints = os.controlPoints;
1842
+ const c0 = controlPoints[ 0 ];
1843
+ const c1 = controlPoints[ 1 ];
1844
+ const v0 = vertices[ 0 ];
1845
+ const v1 = vertices[ 1 ];
1846
+ const index = i * 3 * 2;
1847
+ controlArray0[ index + 0 ] = c0.x;
1848
+ controlArray0[ index + 1 ] = c0.y;
1849
+ controlArray0[ index + 2 ] = c0.z;
1850
+ controlArray0[ index + 3 ] = c0.x;
1851
+ controlArray0[ index + 4 ] = c0.y;
1852
+ controlArray0[ index + 5 ] = c0.z;
1853
+
1854
+ controlArray1[ index + 0 ] = c1.x;
1855
+ controlArray1[ index + 1 ] = c1.y;
1856
+ controlArray1[ index + 2 ] = c1.z;
1857
+ controlArray1[ index + 3 ] = c1.x;
1858
+ controlArray1[ index + 4 ] = c1.y;
1859
+ controlArray1[ index + 5 ] = c1.z;
1860
+
1861
+ directionArray[ index + 0 ] = v1.x - v0.x;
1862
+ directionArray[ index + 1 ] = v1.y - v0.y;
1863
+ directionArray[ index + 2 ] = v1.z - v0.z;
1864
+ directionArray[ index + 3 ] = v1.x - v0.x;
1865
+ directionArray[ index + 4 ] = v1.y - v0.y;
1866
+ directionArray[ index + 5 ] = v1.z - v0.z;
1867
+
1868
+ }
1869
+
1870
+ bufferGeometry.setAttribute( 'control0', new BufferAttribute( controlArray0, 3, false ) );
1871
+ bufferGeometry.setAttribute( 'control1', new BufferAttribute( controlArray1, 3, false ) );
1872
+ bufferGeometry.setAttribute( 'direction', new BufferAttribute( directionArray, 3, false ) );
1873
+
1874
+ }
1875
+
1876
+ return object3d;
1877
+
1878
+ }
1879
+
1880
+ //
1881
+
1882
+ class LDrawLoader extends Loader {
1883
+
1884
+ constructor( manager ) {
1885
+
1886
+ super( manager );
1887
+
1888
+ // Array of THREE.Material
1889
+ this.materials = [];
1890
+ this.materialLibrary = {};
1891
+ this.edgeMaterialCache = new WeakMap();
1892
+ this.conditionalEdgeMaterialCache = new WeakMap();
1893
+
1894
+ // This also allows to handle the embedded text files ("0 FILE" lines)
1895
+ this.partsCache = new LDrawPartsGeometryCache( this );
1896
+
1897
+ // This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error.
1898
+ this.fileMap = {};
1899
+
1900
+ // Initializes the materials library with default materials
1901
+ this.setMaterials( [] );
1902
+
1903
+ // If this flag is set to true the vertex normals will be smoothed.
1904
+ this.smoothNormals = true;
1905
+
1906
+ // The path to load parts from the LDraw parts library from.
1907
+ this.partsLibraryPath = '';
1908
+
1909
+ // Material assigned to not available colors for meshes and edges
1910
+ this.missingColorMaterial = new MeshStandardMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF, roughness: 0.3, metalness: 0 } );
1911
+ this.missingEdgeColorMaterial = new LineBasicMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF } );
1912
+ this.missingConditionalEdgeColorMaterial = new LDrawConditionalLineMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, fog: true, color: 0xFF00FF } );
1913
+ this.edgeMaterialCache.set( this.missingColorMaterial, this.missingEdgeColorMaterial );
1914
+ this.conditionalEdgeMaterialCache.set( this.missingEdgeColorMaterial, this.missingConditionalEdgeColorMaterial );
1915
+
1916
+ }
1917
+
1918
+ setPartsLibraryPath( path ) {
1919
+
1920
+ this.partsLibraryPath = path;
1921
+ return this;
1922
+
1923
+ }
1924
+
1925
+ async preloadMaterials( url ) {
1926
+
1927
+ const fileLoader = new FileLoader( this.manager );
1928
+ fileLoader.setPath( this.path );
1929
+ fileLoader.setRequestHeader( this.requestHeader );
1930
+ fileLoader.setWithCredentials( this.withCredentials );
1931
+
1932
+ const text = await fileLoader.loadAsync( url );
1933
+ const colorLineRegex = /^0 !COLOUR/;
1934
+ const lines = text.split( /[\n\r]/g );
1935
+ const materials = [];
1936
+ for ( let i = 0, l = lines.length; i < l; i ++ ) {
1937
+
1938
+ const line = lines[ i ];
1939
+ if ( colorLineRegex.test( line ) ) {
1940
+
1941
+ const directive = line.replace( colorLineRegex, '' );
1942
+ const material = this.parseColorMetaDirective( new LineParser( directive ) );
1943
+ materials.push( material );
1944
+
1945
+ }
1946
+
1947
+ }
1948
+
1949
+ this.setMaterials( materials );
1950
+
1951
+ }
1952
+
1953
+ load( url, onLoad, onProgress, onError ) {
1954
+
1955
+ const fileLoader = new FileLoader( this.manager );
1956
+ fileLoader.setPath( this.path );
1957
+ fileLoader.setRequestHeader( this.requestHeader );
1958
+ fileLoader.setWithCredentials( this.withCredentials );
1959
+ fileLoader.load( url, text => {
1960
+
1961
+ this.partsCache
1962
+ .parseModel( text, this.materialLibrary )
1963
+ .then( group => {
1964
+
1965
+ this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1966
+ this.computeBuildingSteps( group );
1967
+ group.userData.fileName = url;
1968
+ onLoad( group );
1969
+
1970
+ } )
1971
+ .catch( onError );
1972
+
1973
+ }, onProgress, onError );
1974
+
1975
+ }
1976
+
1977
+ parse( text, onLoad ) {
1978
+
1979
+ this.partsCache
1980
+ .parseModel( text, this.materialLibrary )
1981
+ .then( group => {
1982
+
1983
+ this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1984
+ this.computeBuildingSteps( group );
1985
+ group.userData.fileName = '';
1986
+ onLoad( group );
1987
+
1988
+ } );
1989
+
1990
+ }
1991
+
1992
+ setMaterials( materials ) {
1993
+
1994
+ this.materialLibrary = {};
1995
+ this.materials = [];
1996
+ for ( let i = 0, l = materials.length; i < l; i ++ ) {
1997
+
1998
+ this.addMaterial( materials[ i ] );
1999
+
2000
+ }
2001
+
2002
+ // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
2003
+ this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Main_Colour CODE 16 VALUE #FF8080 EDGE #333333' ) ) );
2004
+ this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333' ) ) );
2005
+
2006
+ return this;
2007
+
2008
+ }
2009
+
2010
+ setFileMap( fileMap ) {
2011
+
2012
+ this.fileMap = fileMap;
2013
+
2014
+ return this;
2015
+
2016
+ }
2017
+
2018
+ addMaterial( material ) {
2019
+
2020
+ // Adds a material to the material library which is on top of the parse scopes stack. And also to the materials array
2021
+
2022
+ const matLib = this.materialLibrary;
2023
+ if ( ! matLib[ material.userData.code ] ) {
2024
+
2025
+ this.materials.push( material );
2026
+ matLib[ material.userData.code ] = material;
2027
+
2028
+ }
2029
+
2030
+ return this;
2031
+
2032
+ }
2033
+
2034
+ getMaterial( colorCode ) {
2035
+
2036
+ if ( colorCode.startsWith( '0x2' ) ) {
2037
+
2038
+ // Special 'direct' material value (RGB color)
2039
+ const color = colorCode.substring( 3 );
2040
+
2041
+ return this.parseColorMetaDirective( new LineParser( 'Direct_Color_' + color + ' CODE -1 VALUE #' + color + ' EDGE #' + color + '' ) );
2042
+
2043
+ }
2044
+
2045
+ return this.materialLibrary[ colorCode ] || null;
2046
+
2047
+ }
2048
+
2049
+ // Applies the appropriate materials to a prebuilt hierarchy of geometry. Assumes that color codes are present
2050
+ // in the material array if they need to be filled in.
2051
+ applyMaterialsToMesh( group, parentColorCode, materialHierarchy, finalMaterialPass = false ) {
2052
+
2053
+ // find any missing materials as indicated by a color code string and replace it with a material from the current material lib
2054
+ const loader = this;
2055
+ const parentIsPassthrough = parentColorCode === MAIN_COLOUR_CODE;
2056
+ group.traverse( c => {
2057
+
2058
+ if ( c.isMesh || c.isLineSegments ) {
2059
+
2060
+ if ( Array.isArray( c.material ) ) {
2061
+
2062
+ for ( let i = 0, l = c.material.length; i < l; i ++ ) {
2063
+
2064
+ if ( ! c.material[ i ].isMaterial ) {
2065
+
2066
+ c.material[ i ] = getMaterial( c, c.material[ i ] );
2067
+
2068
+ }
2069
+
2070
+ }
2071
+
2072
+ } else if ( ! c.material.isMaterial ) {
2073
+
2074
+ c.material = getMaterial( c, c.material );
2075
+
2076
+ }
2077
+
2078
+ }
2079
+
2080
+ } );
2081
+
2082
+
2083
+ // Returns the appropriate material for the object (line or face) given color code. If the code is "pass through"
2084
+ // (24 for lines, 16 for edges) then the pass through color code is used. If that is also pass through then it's
2085
+ // simply returned for the subsequent material application.
2086
+ function getMaterial( c, colorCode ) {
2087
+
2088
+ // if our parent is a passthrough color code and we don't have the current material color available then
2089
+ // return early.
2090
+ if ( parentIsPassthrough && ! ( colorCode in materialHierarchy ) && ! finalMaterialPass ) {
2091
+
2092
+ return colorCode;
2093
+
2094
+ }
2095
+
2096
+ const forEdge = c.isLineSegments || c.isConditionalLine;
2097
+ const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
2098
+ if ( isPassthrough ) {
2099
+
2100
+ colorCode = parentColorCode;
2101
+
2102
+ }
2103
+
2104
+ let material = null;
2105
+ if ( colorCode in materialHierarchy ) {
2106
+
2107
+ material = materialHierarchy[ colorCode ];
2108
+
2109
+ } else if ( finalMaterialPass ) {
2110
+
2111
+ // see if we can get the final material from from the "getMaterial" function which will attempt to
2112
+ // parse the "direct" colors
2113
+ material = loader.getMaterial( colorCode );
2114
+ if ( material === null ) {
2115
+
2116
+ // otherwise throw a warning if this is final opportunity to set the material
2117
+ console.warn( `LDrawLoader: Material properties for code ${ colorCode } not available.` );
2118
+
2119
+ // And return the 'missing color' material
2120
+ material = loader.missingColorMaterial;
2121
+
2122
+ }
2123
+
2124
+
2125
+ } else {
2126
+
2127
+ return colorCode;
2128
+
2129
+ }
2130
+
2131
+ if ( c.isLineSegments ) {
2132
+
2133
+ material = loader.edgeMaterialCache.get( material );
2134
+
2135
+ if ( c.isConditionalLine ) {
2136
+
2137
+ material = loader.conditionalEdgeMaterialCache.get( material );
2138
+
2139
+ }
2140
+
2141
+ }
2142
+
2143
+ return material;
2144
+
2145
+ }
2146
+
2147
+ }
2148
+
2149
+ getMainMaterial() {
2150
+
2151
+ return this.getMaterial( MAIN_COLOUR_CODE );
2152
+
2153
+ }
2154
+
2155
+ getMainEdgeMaterial() {
2156
+
2157
+ const mat = this.getMaterial( MAIN_EDGE_COLOUR_CODE );
2158
+ return mat ? this.edgeMaterialCache.get( mat ) : null;
2159
+
2160
+ }
2161
+
2162
+ parseColorMetaDirective( lineParser ) {
2163
+
2164
+ // Parses a color definition and returns a THREE.Material
2165
+
2166
+ let code = null;
2167
+
2168
+ // Triangle and line colors
2169
+ let fillColor = '#FF00FF';
2170
+ let edgeColor = '#FF00FF';
2171
+
2172
+ // Transparency
2173
+ let alpha = 1;
2174
+ let isTransparent = false;
2175
+ // Self-illumination:
2176
+ let luminance = 0;
2177
+
2178
+ let finishType = FINISH_TYPE_DEFAULT;
2179
+
2180
+ let edgeMaterial = null;
2181
+
2182
+ const name = lineParser.getToken();
2183
+ if ( ! name ) {
2184
+
2185
+ throw new Error( 'LDrawLoader: Material name was expected after "!COLOUR tag' + lineParser.getLineNumberString() + '.' );
2186
+
2187
+ }
2188
+
2189
+ // Parse tag tokens and their parameters
2190
+ let token = null;
2191
+ while ( true ) {
2192
+
2193
+ token = lineParser.getToken();
2194
+
2195
+ if ( ! token ) {
2196
+
2197
+ break;
2198
+
2199
+ }
2200
+
2201
+ if ( ! parseLuminance( token ) ) {
2202
+
2203
+ switch ( token.toUpperCase() ) {
2204
+
2205
+ case 'CODE':
2206
+
2207
+ code = lineParser.getToken();
2208
+ break;
2209
+
2210
+ case 'VALUE':
2211
+
2212
+ fillColor = lineParser.getToken();
2213
+ if ( fillColor.startsWith( '0x' ) ) {
2214
+
2215
+ fillColor = '#' + fillColor.substring( 2 );
2216
+
2217
+ } else if ( ! fillColor.startsWith( '#' ) ) {
2218
+
2219
+ throw new Error( 'LDrawLoader: Invalid color while parsing material' + lineParser.getLineNumberString() + '.' );
2220
+
2221
+ }
2222
+
2223
+ break;
2224
+
2225
+ case 'EDGE':
2226
+
2227
+ edgeColor = lineParser.getToken();
2228
+ if ( edgeColor.startsWith( '0x' ) ) {
2229
+
2230
+ edgeColor = '#' + edgeColor.substring( 2 );
2231
+
2232
+ } else if ( ! edgeColor.startsWith( '#' ) ) {
2233
+
2234
+ // Try to see if edge color is a color code
2235
+ edgeMaterial = this.getMaterial( edgeColor );
2236
+ if ( ! edgeMaterial ) {
2237
+
2238
+ throw new Error( 'LDrawLoader: Invalid edge color while parsing material' + lineParser.getLineNumberString() + '.' );
2239
+
2240
+ }
2241
+
2242
+ // Get the edge material for this triangle material
2243
+ edgeMaterial = this.edgeMaterialCache.get( edgeMaterial );
2244
+
2245
+ }
2246
+
2247
+ break;
2248
+
2249
+ case 'ALPHA':
2250
+
2251
+ alpha = parseInt( lineParser.getToken() );
2252
+
2253
+ if ( isNaN( alpha ) ) {
2254
+
2255
+ throw new Error( 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + '.' );
2256
+
2257
+ }
2258
+
2259
+ alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
2260
+
2261
+ if ( alpha < 1 ) {
2262
+
2263
+ isTransparent = true;
2264
+
2265
+ }
2266
+
2267
+ break;
2268
+
2269
+ case 'LUMINANCE':
2270
+
2271
+ if ( ! parseLuminance( lineParser.getToken() ) ) {
2272
+
2273
+ throw new Error( 'LDrawLoader: Invalid luminance value in material definition' + LineParser.getLineNumberString() + '.' );
2274
+
2275
+ }
2276
+
2277
+ break;
2278
+
2279
+ case 'CHROME':
2280
+ finishType = FINISH_TYPE_CHROME;
2281
+ break;
2282
+
2283
+ case 'PEARLESCENT':
2284
+ finishType = FINISH_TYPE_PEARLESCENT;
2285
+ break;
2286
+
2287
+ case 'RUBBER':
2288
+ finishType = FINISH_TYPE_RUBBER;
2289
+ break;
2290
+
2291
+ case 'MATTE_METALLIC':
2292
+ finishType = FINISH_TYPE_MATTE_METALLIC;
2293
+ break;
2294
+
2295
+ case 'METAL':
2296
+ finishType = FINISH_TYPE_METAL;
2297
+ break;
2298
+
2299
+ case 'MATERIAL':
2300
+ // Not implemented
2301
+ lineParser.setToEnd();
2302
+ break;
2303
+
2304
+ default:
2305
+ throw new Error( 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + '.' );
2306
+
2307
+ }
2308
+
2309
+ }
2310
+
2311
+ }
2312
+
2313
+ let material = null;
2314
+
2315
+ switch ( finishType ) {
2316
+
2317
+ case FINISH_TYPE_DEFAULT:
2318
+
2319
+ material = new MeshStandardMaterial( { roughness: 0.3, metalness: 0 } );
2320
+ break;
2321
+
2322
+ case FINISH_TYPE_PEARLESCENT:
2323
+
2324
+ // Try to imitate pearlescency by making the surface glossy
2325
+ material = new MeshStandardMaterial( { roughness: 0.3, metalness: 0.25 } );
2326
+ break;
2327
+
2328
+ case FINISH_TYPE_CHROME:
2329
+
2330
+ // Mirror finish surface
2331
+ material = new MeshStandardMaterial( { roughness: 0, metalness: 1 } );
2332
+ break;
2333
+
2334
+ case FINISH_TYPE_RUBBER:
2335
+
2336
+ // Rubber finish
2337
+ material = new MeshStandardMaterial( { roughness: 0.9, metalness: 0 } );
2338
+ break;
2339
+
2340
+ case FINISH_TYPE_MATTE_METALLIC:
2341
+
2342
+ // Brushed metal finish
2343
+ material = new MeshStandardMaterial( { roughness: 0.8, metalness: 0.4 } );
2344
+ break;
2345
+
2346
+ case FINISH_TYPE_METAL:
2347
+
2348
+ // Average metal finish
2349
+ material = new MeshStandardMaterial( { roughness: 0.2, metalness: 0.85 } );
2350
+ break;
2351
+
2352
+ default:
2353
+ // Should not happen
2354
+ break;
2355
+
2356
+ }
2357
+
2358
+ material.color.setStyle( fillColor, COLOR_SPACE_LDRAW );
2359
+ material.transparent = isTransparent;
2360
+ material.premultipliedAlpha = true;
2361
+ material.opacity = alpha;
2362
+ material.depthWrite = ! isTransparent;
2363
+
2364
+ material.polygonOffset = true;
2365
+ material.polygonOffsetFactor = 1;
2366
+
2367
+ if ( luminance !== 0 ) {
2368
+
2369
+ material.emissive.setStyle( fillColor, COLOR_SPACE_LDRAW ).multiplyScalar( luminance );
2370
+
2371
+ }
2372
+
2373
+ if ( ! edgeMaterial ) {
2374
+
2375
+ // This is the material used for edges
2376
+ edgeMaterial = new LineBasicMaterial( {
2377
+ color: new Color().setStyle( edgeColor, COLOR_SPACE_LDRAW ),
2378
+ transparent: isTransparent,
2379
+ opacity: alpha,
2380
+ depthWrite: ! isTransparent
2381
+ } );
2382
+ edgeMaterial.color;
2383
+ edgeMaterial.userData.code = code;
2384
+ edgeMaterial.name = name + ' - Edge';
2385
+
2386
+ // This is the material used for conditional edges
2387
+ const conditionalEdgeMaterial = new LDrawConditionalLineMaterial( {
2388
+
2389
+ fog: true,
2390
+ transparent: isTransparent,
2391
+ depthWrite: ! isTransparent,
2392
+ color: new Color().setStyle( edgeColor, COLOR_SPACE_LDRAW ),
2393
+ opacity: alpha,
2394
+
2395
+ } );
2396
+ conditionalEdgeMaterial.userData.code = code;
2397
+ conditionalEdgeMaterial.name = name + ' - Conditional Edge';
2398
+
2399
+ this.conditionalEdgeMaterialCache.set( edgeMaterial, conditionalEdgeMaterial );
2400
+
2401
+ }
2402
+
2403
+ material.userData.code = code;
2404
+ material.name = name;
2405
+
2406
+ this.edgeMaterialCache.set( material, edgeMaterial );
2407
+
2408
+ this.addMaterial( material );
2409
+
2410
+ return material;
2411
+
2412
+ function parseLuminance( token ) {
2413
+
2414
+ // Returns success
2415
+
2416
+ let lum;
2417
+
2418
+ if ( token.startsWith( 'LUMINANCE' ) ) {
2419
+
2420
+ lum = parseInt( token.substring( 9 ) );
2421
+
2422
+ } else {
2423
+
2424
+ lum = parseInt( token );
2425
+
2426
+ }
2427
+
2428
+ if ( isNaN( lum ) ) {
2429
+
2430
+ return false;
2431
+
2432
+ }
2433
+
2434
+ luminance = Math.max( 0, Math.min( 1, lum / 255 ) );
2435
+
2436
+ return true;
2437
+
2438
+ }
2439
+
2440
+ }
2441
+
2442
+ computeBuildingSteps( model ) {
2443
+
2444
+ // Sets userdata.buildingStep number in Group objects and userData.numBuildingSteps number in the root Group object.
2445
+
2446
+ let stepNumber = 0;
2447
+
2448
+ model.traverse( c => {
2449
+
2450
+ if ( c.isGroup ) {
2451
+
2452
+ if ( c.userData.startingBuildingStep ) {
2453
+
2454
+ stepNumber ++;
2455
+
2456
+ }
2457
+
2458
+ c.userData.buildingStep = stepNumber;
2459
+
2460
+ }
2461
+
2462
+ } );
2463
+
2464
+ model.userData.numBuildingSteps = stepNumber + 1;
2465
+
2466
+ }
2467
+
2468
+ }
2469
+
2470
+ export { LDrawLoader };