@needle-tools/three 0.145.4 → 0.146.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 (393) hide show
  1. package/README.md +1 -1
  2. package/build/three.cjs +32586 -35951
  3. package/build/three.js +32600 -35965
  4. package/build/three.min.js +6 -7
  5. package/build/three.module.js +1547 -1154
  6. package/examples/js/animation/AnimationClipCreator.js +0 -8
  7. package/examples/js/animation/CCDIKSolver.js +49 -66
  8. package/examples/js/animation/MMDAnimationHelper.js +66 -137
  9. package/examples/js/animation/MMDPhysics.js +70 -134
  10. package/examples/js/cameras/CinematicCamera.js +33 -22
  11. package/examples/js/controls/ArcballControls.js +138 -405
  12. package/examples/js/controls/DragControls.js +8 -33
  13. package/examples/js/controls/FirstPersonControls.js +32 -54
  14. package/examples/js/controls/FlyControls.js +29 -55
  15. package/examples/js/controls/OrbitControls.js +85 -95
  16. package/examples/js/controls/PointerLockControls.js +5 -14
  17. package/examples/js/controls/TrackballControls.js +33 -86
  18. package/examples/js/controls/TransformControls.js +84 -169
  19. package/examples/js/csm/CSM.js +4 -39
  20. package/examples/js/csm/CSMFrustum.js +3 -9
  21. package/examples/js/csm/CSMHelper.js +24 -4
  22. package/examples/js/csm/CSMShader.js +2 -6
  23. package/examples/js/curves/CurveExtras.js +27 -27
  24. package/examples/js/curves/NURBSCurve.js +4 -16
  25. package/examples/js/curves/NURBSSurface.js +3 -9
  26. package/examples/js/curves/NURBSUtils.js +8 -45
  27. package/examples/js/effects/AnaglyphEffect.js +4 -18
  28. package/examples/js/effects/AsciiEffect.js +32 -31
  29. package/examples/js/effects/OutlineEffect.js +26 -30
  30. package/examples/js/effects/ParallaxBarrierEffect.js +0 -13
  31. package/examples/js/effects/PeppersGhostEffect.js +12 -39
  32. package/examples/js/effects/StereoEffect.js +0 -4
  33. package/examples/js/environments/RoomEnvironment.js +12 -10
  34. package/examples/js/exporters/ColladaExporter.js +48 -65
  35. package/examples/js/exporters/DRACOExporter.js +22 -22
  36. package/examples/js/exporters/EXRExporter.js +15 -18
  37. package/examples/js/exporters/GLTFExporter.js +143 -261
  38. package/examples/js/exporters/MMDExporter.js +5 -12
  39. package/examples/js/exporters/OBJExporter.js +42 -33
  40. package/examples/js/exporters/PLYExporter.js +38 -33
  41. package/examples/js/exporters/STLExporter.js +5 -7
  42. package/examples/js/exporters/USDZExporter.js +110 -25
  43. package/examples/js/geometries/BoxLineGeometry.js +0 -1
  44. package/examples/js/geometries/ConvexGeometry.js +11 -6
  45. package/examples/js/geometries/DecalGeometry.js +53 -20
  46. package/examples/js/geometries/LightningStrike.js +54 -67
  47. package/examples/js/geometries/ParametricGeometries.js +8 -7
  48. package/examples/js/geometries/ParametricGeometry.js +25 -12
  49. package/examples/js/geometries/RoundedBoxGeometry.js +21 -19
  50. package/examples/js/geometries/TeapotGeometry.js +54 -50
  51. package/examples/js/geometries/TextGeometry.js +6 -4
  52. package/examples/js/helpers/LightProbeHelper.js +1 -2
  53. package/examples/js/helpers/OctreeHelper.js +22 -20
  54. package/examples/js/helpers/PositionalAudioHelper.js +8 -6
  55. package/examples/js/helpers/RectAreaLightHelper.js +6 -7
  56. package/examples/js/helpers/VertexNormalsHelper.js +15 -13
  57. package/examples/js/helpers/VertexTangentsHelper.js +15 -9
  58. package/examples/js/helpers/ViewHelper.js +31 -16
  59. package/examples/js/interactive/HTMLMesh.js +22 -33
  60. package/examples/js/interactive/InteractiveGroup.js +6 -12
  61. package/examples/js/interactive/SelectionBox.js +3 -70
  62. package/examples/js/interactive/SelectionHelper.js +0 -8
  63. package/examples/js/lights/LightProbeGenerator.js +32 -39
  64. package/examples/js/lights/RectAreaLightUniformsLib.js +5 -1
  65. package/examples/js/lines/LineGeometry.js +3 -5
  66. package/examples/js/lines/LineMaterial.js +4 -11
  67. package/examples/js/lines/LineSegments2.js +38 -89
  68. package/examples/js/lines/LineSegmentsGeometry.js +7 -28
  69. package/examples/js/lines/Wireframe.js +2 -7
  70. package/examples/js/lines/WireframeGeometry2.js +3 -1
  71. package/examples/js/loaders/3DMLoader.js +58 -155
  72. package/examples/js/loaders/3MFLoader.js +72 -106
  73. package/examples/js/loaders/AMFLoader.js +0 -25
  74. package/examples/js/loaders/BVHLoader.js +44 -43
  75. package/examples/js/loaders/BasisTextureLoader.js +16 -46
  76. package/examples/js/loaders/ColladaLoader.js +201 -359
  77. package/examples/js/loaders/DDSLoader.js +24 -25
  78. package/examples/js/loaders/DRACOLoader.js +29 -66
  79. package/examples/js/loaders/EXRLoader.js +67 -164
  80. package/examples/js/loaders/FBXLoader.js +286 -441
  81. package/examples/js/loaders/FontLoader.js +6 -15
  82. package/examples/js/loaders/GCodeLoader.js +15 -16
  83. package/examples/js/loaders/GLTFLoader.js +354 -405
  84. package/examples/js/loaders/HDRCubeTextureLoader.js +0 -6
  85. package/examples/js/loaders/KMZLoader.js +3 -7
  86. package/examples/js/loaders/KTXLoader.js +12 -30
  87. package/examples/js/loaders/LDrawLoader.js +178 -289
  88. package/examples/js/loaders/LUT3dlLoader.js +7 -11
  89. package/examples/js/loaders/LUTCubeLoader.js +0 -8
  90. package/examples/js/loaders/LWOLoader.js +59 -124
  91. package/examples/js/loaders/LogLuvLoader.js +27 -77
  92. package/examples/js/loaders/LottieLoader.js +4 -4
  93. package/examples/js/loaders/MD2Loader.js +26 -27
  94. package/examples/js/loaders/MDDLoader.js +6 -10
  95. package/examples/js/loaders/MMDLoader.js +180 -189
  96. package/examples/js/loaders/MTLLoader.js +18 -47
  97. package/examples/js/loaders/MaterialXLoader.js +392 -0
  98. package/examples/js/loaders/NRRDLoader.js +44 -84
  99. package/examples/js/loaders/OBJLoader.js +50 -65
  100. package/examples/js/loaders/PCDLoader.js +34 -29
  101. package/examples/js/loaders/PDBLoader.js +17 -13
  102. package/examples/js/loaders/PLYLoader.js +9 -39
  103. package/examples/js/loaders/PRWMLoader.js +11 -22
  104. package/examples/js/loaders/PVRLoader.js +7 -16
  105. package/examples/js/loaders/RGBELoader.js +36 -61
  106. package/examples/js/loaders/RGBMLoader.js +26 -87
  107. package/examples/js/loaders/STLLoader.js +20 -27
  108. package/examples/js/loaders/SVGLoader.js +361 -233
  109. package/examples/js/loaders/TDSLoader.js +81 -118
  110. package/examples/js/loaders/TGALoader.js +39 -41
  111. package/examples/js/loaders/TIFFLoader.js +0 -1
  112. package/examples/js/loaders/TTFLoader.js +0 -8
  113. package/examples/js/loaders/TiltLoader.js +14 -15
  114. package/examples/js/loaders/VOXLoader.js +8 -16
  115. package/examples/js/loaders/VRMLLoader.js +243 -340
  116. package/examples/js/loaders/VTKLoader.js +101 -118
  117. package/examples/js/loaders/XYZLoader.js +2 -4
  118. package/examples/js/loaders/lwo/IFFParser.js +55 -136
  119. package/examples/js/loaders/lwo/LWO2Parser.js +32 -83
  120. package/examples/js/loaders/lwo/LWO3Parser.js +31 -73
  121. package/examples/js/materials/MeshGouraudMaterial.js +15 -13
  122. package/examples/js/math/Capsule.js +0 -17
  123. package/examples/js/math/ColorConverter.js +3 -3
  124. package/examples/js/math/ConvexHull.js +183 -139
  125. package/examples/js/math/ImprovedNoise.js +1 -1
  126. package/examples/js/math/Lut.js +8 -15
  127. package/examples/js/math/MeshSurfaceSampler.js +6 -28
  128. package/examples/js/math/OBB.js +90 -49
  129. package/examples/js/math/Octree.js +2 -57
  130. package/examples/js/math/SimplexNoise.js +74 -88
  131. package/examples/js/misc/ConvexObjectBreaker.js +37 -48
  132. package/examples/js/misc/GPUComputationRenderer.js +14 -18
  133. package/examples/js/misc/Gyroscope.js +5 -9
  134. package/examples/js/misc/MD2Character.js +14 -23
  135. package/examples/js/misc/MD2CharacterComplex.js +73 -54
  136. package/examples/js/misc/MorphAnimMesh.js +0 -6
  137. package/examples/js/misc/MorphBlendMesh.js +3 -30
  138. package/examples/js/misc/ProgressiveLightMap.js +47 -43
  139. package/examples/js/misc/RollerCoaster.js +17 -24
  140. package/examples/js/misc/TubePainter.js +18 -12
  141. package/examples/js/misc/Volume.js +16 -45
  142. package/examples/js/misc/VolumeSlice.js +14 -24
  143. package/examples/js/modifiers/CurveModifier.js +19 -21
  144. package/examples/js/modifiers/EdgeSplitModifier.js +0 -30
  145. package/examples/js/modifiers/SimplifyModifier.js +56 -59
  146. package/examples/js/modifiers/TessellateModifier.js +2 -9
  147. package/examples/js/objects/GroundProjectedEnv.js +2 -14
  148. package/examples/js/objects/Lensflare.js +47 -38
  149. package/examples/js/objects/LightningStorm.js +10 -13
  150. package/examples/js/objects/MarchingCubes.js +80 -59
  151. package/examples/js/objects/Reflector.js +22 -20
  152. package/examples/js/objects/ReflectorForSSRPass.js +19 -23
  153. package/examples/js/objects/Refractor.js +52 -30
  154. package/examples/js/objects/ShadowMesh.js +1 -2
  155. package/examples/js/objects/Sky.js +2 -7
  156. package/examples/js/objects/Water.js +23 -18
  157. package/examples/js/objects/Water2.js +20 -19
  158. package/examples/js/physics/AmmoPhysics.js +23 -20
  159. package/examples/js/physics/OimoPhysics.js +19 -17
  160. package/examples/js/postprocessing/AdaptiveToneMappingPass.js +13 -20
  161. package/examples/js/postprocessing/AfterimagePass.js +19 -12
  162. package/examples/js/postprocessing/BloomPass.js +38 -17
  163. package/examples/js/postprocessing/BokehPass.js +29 -12
  164. package/examples/js/postprocessing/ClearPass.js +1 -6
  165. package/examples/js/postprocessing/CubeTexturePass.js +12 -9
  166. package/examples/js/postprocessing/DotScreenPass.js +7 -5
  167. package/examples/js/postprocessing/EffectComposer.js +25 -32
  168. package/examples/js/postprocessing/FilmPass.js +7 -5
  169. package/examples/js/postprocessing/GlitchPass.js +10 -11
  170. package/examples/js/postprocessing/HalftonePass.js +9 -9
  171. package/examples/js/postprocessing/LUTPass.js +2 -15
  172. package/examples/js/postprocessing/MaskPass.js +20 -17
  173. package/examples/js/postprocessing/OutlinePass.js +45 -36
  174. package/examples/js/postprocessing/Pass.js +11 -14
  175. package/examples/js/postprocessing/RenderPass.js +3 -7
  176. package/examples/js/postprocessing/SAOPass.js +40 -32
  177. package/examples/js/postprocessing/SMAAPass.js +34 -17
  178. package/examples/js/postprocessing/SSAARenderPass.js +14 -14
  179. package/examples/js/postprocessing/SSAOPass.js +56 -42
  180. package/examples/js/postprocessing/SSRPass.js +78 -61
  181. package/examples/js/postprocessing/SavePass.js +14 -6
  182. package/examples/js/postprocessing/ShaderPass.js +9 -8
  183. package/examples/js/postprocessing/TAARenderPass.js +11 -9
  184. package/examples/js/postprocessing/TexturePass.js +7 -4
  185. package/examples/js/postprocessing/UnrealBloomPass.js +43 -25
  186. package/examples/js/renderers/CSS2DRenderer.js +2 -21
  187. package/examples/js/renderers/CSS3DRenderer.js +3 -24
  188. package/examples/js/renderers/Projector.js +29 -85
  189. package/examples/js/renderers/SVGRenderer.js +4 -50
  190. package/examples/js/shaders/ACESFilmicToneMappingShader.js +3 -6
  191. package/examples/js/shaders/AfterimageShader.js +3 -6
  192. package/examples/js/shaders/BasicShader.js +3 -6
  193. package/examples/js/shaders/BleachBypassShader.js +3 -6
  194. package/examples/js/shaders/BlendShader.js +3 -6
  195. package/examples/js/shaders/BokehShader.js +3 -6
  196. package/examples/js/shaders/BokehShader2.js +4 -13
  197. package/examples/js/shaders/BrightnessContrastShader.js +3 -6
  198. package/examples/js/shaders/ColorCorrectionShader.js +2 -6
  199. package/examples/js/shaders/ColorifyShader.js +2 -6
  200. package/examples/js/shaders/ConvolutionShader.js +5 -10
  201. package/examples/js/shaders/CopyShader.js +3 -6
  202. package/examples/js/shaders/DOFMipMapShader.js +3 -6
  203. package/examples/js/shaders/DepthLimitedBlurShader.js +2 -9
  204. package/examples/js/shaders/DigitalGlitch.js +3 -6
  205. package/examples/js/shaders/DotScreenShader.js +2 -6
  206. package/examples/js/shaders/FXAAShader.js +1 -3
  207. package/examples/js/shaders/FilmShader.js +3 -6
  208. package/examples/js/shaders/FocusShader.js +3 -6
  209. package/examples/js/shaders/FreiChenShader.js +2 -6
  210. package/examples/js/shaders/GammaCorrectionShader.js +3 -6
  211. package/examples/js/shaders/GodRaysShader.js +11 -24
  212. package/examples/js/shaders/HalftoneShader.js +3 -6
  213. package/examples/js/shaders/HorizontalBlurShader.js +3 -6
  214. package/examples/js/shaders/HorizontalTiltShiftShader.js +3 -6
  215. package/examples/js/shaders/HueSaturationShader.js +3 -6
  216. package/examples/js/shaders/KaleidoShader.js +3 -6
  217. package/examples/js/shaders/LuminosityHighPassShader.js +2 -6
  218. package/examples/js/shaders/LuminosityShader.js +3 -6
  219. package/examples/js/shaders/MMDToonShader.js +2 -6
  220. package/examples/js/shaders/MirrorShader.js +3 -6
  221. package/examples/js/shaders/NormalMapShader.js +2 -6
  222. package/examples/js/shaders/RGBShiftShader.js +3 -6
  223. package/examples/js/shaders/SAOShader.js +2 -6
  224. package/examples/js/shaders/SMAAShader.js +6 -18
  225. package/examples/js/shaders/SSAOShader.js +2 -6
  226. package/examples/js/shaders/SSRShader.js +6 -18
  227. package/examples/js/shaders/SepiaShader.js +3 -6
  228. package/examples/js/shaders/SobelOperatorShader.js +2 -6
  229. package/examples/js/shaders/TechnicolorShader.js +3 -6
  230. package/examples/js/shaders/ToneMapShader.js +3 -6
  231. package/examples/js/shaders/ToonShader.js +8 -24
  232. package/examples/js/shaders/TriangleBlurShader.js +2 -6
  233. package/examples/js/shaders/UnpackDepthRGBAShader.js +3 -6
  234. package/examples/js/shaders/VelocityShader.js +126 -0
  235. package/examples/js/shaders/VerticalBlurShader.js +3 -6
  236. package/examples/js/shaders/VerticalTiltShiftShader.js +3 -6
  237. package/examples/js/shaders/VignetteShader.js +3 -6
  238. package/examples/js/shaders/VolumeShader.js +2 -6
  239. package/examples/js/shaders/WaterRefractionShader.js +2 -6
  240. package/examples/js/textures/FlakesTexture.js +0 -1
  241. package/examples/js/utils/BufferGeometryUtils.js +234 -168
  242. package/examples/js/utils/CameraUtils.js +5 -20
  243. package/examples/js/utils/GPUStatsPanel.js +3 -12
  244. package/examples/js/utils/GeometryCompressionUtils.js +19 -44
  245. package/examples/js/utils/GeometryUtils.js +13 -18
  246. package/examples/js/utils/LDrawUtils.js +8 -11
  247. package/examples/js/utils/PackedPhongMaterial.js +6 -4
  248. package/examples/js/utils/SceneUtils.js +117 -6
  249. package/examples/js/utils/ShadowMapViewer.js +17 -14
  250. package/examples/js/utils/SkeletonUtils.js +13 -27
  251. package/examples/js/utils/UVsDebug.js +20 -12
  252. package/examples/js/utils/WorkerPool.js +1 -11
  253. package/examples/jsm/animation/CCDIKSolver.js +1 -1
  254. package/examples/jsm/capabilities/WebGPU.js +3 -1
  255. package/examples/jsm/controls/OrbitControls.js +44 -4
  256. package/examples/jsm/exporters/GLTFExporter.js +17 -131
  257. package/examples/jsm/exporters/USDZExporter.js +75 -19
  258. package/examples/jsm/interactive/HTMLMesh.js +2 -0
  259. package/examples/jsm/libs/lottie_canvas.module.js +14844 -0
  260. package/examples/jsm/loaders/3DMLoader.js +1 -2
  261. package/examples/jsm/loaders/ColladaLoader.js +28 -0
  262. package/examples/jsm/loaders/FBXLoader.js +16 -2
  263. package/examples/jsm/loaders/GLTFLoader.js +204 -377
  264. package/examples/jsm/loaders/KTX2Loader.js +68 -29
  265. package/examples/jsm/loaders/LDrawLoader.js +14 -13
  266. package/examples/jsm/loaders/LottieLoader.js +4 -2
  267. package/examples/jsm/loaders/MaterialXLoader.js +728 -0
  268. package/examples/jsm/loaders/PCDLoader.js +1 -1
  269. package/examples/jsm/loaders/PLYLoader.js +68 -16
  270. package/examples/jsm/loaders/SVGLoader.js +227 -14
  271. package/examples/jsm/loaders/USDZLoader.js +31 -16
  272. package/examples/jsm/nodes/Nodes.js +14 -2
  273. package/examples/jsm/nodes/accessors/Object3DNode.js +1 -1
  274. package/examples/jsm/nodes/accessors/PositionNode.js +6 -0
  275. package/examples/jsm/nodes/accessors/ReferenceNode.js +1 -1
  276. package/examples/jsm/nodes/accessors/SkinningNode.js +1 -1
  277. package/examples/jsm/nodes/core/Node.js +1 -1
  278. package/examples/jsm/nodes/core/NodeBuilder.js +36 -4
  279. package/examples/jsm/nodes/core/NodeFrame.js +2 -2
  280. package/examples/jsm/nodes/core/NodeVarying.js +7 -4
  281. package/examples/jsm/nodes/core/VaryingNode.js +6 -4
  282. package/examples/jsm/nodes/core/constants.js +13 -13
  283. package/examples/jsm/nodes/display/PosterizeNode.js +25 -0
  284. package/examples/jsm/nodes/display/ViewportNode.js +106 -0
  285. package/examples/jsm/nodes/gpgpu/ComputeNode.js +1 -1
  286. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +1 -1
  287. package/examples/jsm/nodes/loaders/NodeMaterialLoader.js +3 -1
  288. package/examples/jsm/nodes/materials/Materials.js +9 -7
  289. package/examples/jsm/nodes/materials/NodeMaterial.js +9 -1
  290. package/examples/jsm/nodes/materialx/MaterialXNodes.js +6 -2
  291. package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +18 -0
  292. package/examples/jsm/nodes/math/MathNode.js +5 -0
  293. package/examples/jsm/nodes/math/OperatorNode.js +6 -1
  294. package/examples/jsm/nodes/shadernode/ShaderNode.js +26 -13
  295. package/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js +2 -0
  296. package/examples/jsm/nodes/shadernode/ShaderNodeElements.js +18 -0
  297. package/examples/jsm/nodes/utils/EquirectUVNode.js +27 -0
  298. package/examples/jsm/nodes/utils/JoinNode.js +8 -2
  299. package/examples/jsm/nodes/utils/MatcapUVNode.js +2 -4
  300. package/examples/jsm/nodes/utils/MaxMipLevelNode.js +1 -1
  301. package/examples/jsm/nodes/utils/SpriteSheetUVNode.js +8 -10
  302. package/examples/jsm/nodes/utils/TimerNode.js +1 -1
  303. package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +51 -0
  304. package/examples/jsm/postprocessing/AfterimagePass.js +17 -4
  305. package/examples/jsm/postprocessing/BloomPass.js +22 -3
  306. package/examples/jsm/postprocessing/BokehPass.js +18 -4
  307. package/examples/jsm/postprocessing/CubeTexturePass.js +12 -5
  308. package/examples/jsm/postprocessing/DotScreenPass.js +8 -0
  309. package/examples/jsm/postprocessing/EffectComposer.js +9 -0
  310. package/examples/jsm/postprocessing/FilmPass.js +8 -0
  311. package/examples/jsm/postprocessing/GlitchPass.js +13 -1
  312. package/examples/jsm/postprocessing/HalftonePass.js +8 -0
  313. package/examples/jsm/postprocessing/OutlinePass.js +10 -0
  314. package/examples/jsm/postprocessing/Pass.js +2 -0
  315. package/examples/jsm/postprocessing/RenderPixelatedPass.js +234 -0
  316. package/examples/jsm/postprocessing/SAOPass.js +20 -0
  317. package/examples/jsm/postprocessing/SMAAPass.js +16 -0
  318. package/examples/jsm/postprocessing/SSAARenderPass.js +4 -0
  319. package/examples/jsm/postprocessing/SavePass.js +17 -1
  320. package/examples/jsm/postprocessing/ShaderPass.js +8 -0
  321. package/examples/jsm/postprocessing/TAARenderPass.js +9 -0
  322. package/examples/jsm/postprocessing/TexturePass.js +8 -0
  323. package/examples/jsm/postprocessing/UnrealBloomPass.js +16 -0
  324. package/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +39 -16
  325. package/examples/jsm/renderers/webgpu/WebGPUAnimation.js +58 -0
  326. package/examples/jsm/renderers/webgpu/WebGPUAttributes.js +63 -5
  327. package/examples/jsm/renderers/webgpu/WebGPUBackground.js +36 -7
  328. package/examples/jsm/renderers/webgpu/WebGPURenderer.js +47 -12
  329. package/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js +35 -5
  330. package/examples/jsm/shaders/MMDToonShader.js +0 -2
  331. package/examples/jsm/shaders/VelocityShader.js +128 -0
  332. package/examples/jsm/utils/BufferGeometryUtils.js +130 -6
  333. package/examples/jsm/utils/SceneUtils.js +129 -4
  334. package/examples/jsm/utils/TextureUtils.js +85 -0
  335. package/examples/jsm/webxr/OculusHandModel.js +1 -1
  336. package/examples/jsm/webxr/XRHandMeshModel.js +6 -3
  337. package/package.json +11 -12
  338. package/src/Three.js +1 -0
  339. package/src/audio/AudioContext.js +5 -5
  340. package/src/cameras/CubeCamera.js +14 -14
  341. package/src/constants.js +1 -1
  342. package/src/core/InstancedBufferGeometry.js +1 -7
  343. package/src/extras/Earcut.js +67 -67
  344. package/src/helpers/DirectionalLightHelper.js +5 -1
  345. package/src/helpers/HemisphereLightHelper.js +4 -1
  346. package/src/helpers/PointLightHelper.js +2 -1
  347. package/src/helpers/SpotLightHelper.js +4 -2
  348. package/src/lights/PointLight.js +2 -2
  349. package/src/lights/SpotLight.js +2 -2
  350. package/src/loaders/FileLoader.js +4 -1
  351. package/src/loaders/ObjectLoader.js +5 -1
  352. package/src/materials/Material.js +1 -1
  353. package/src/math/Color.js +5 -5
  354. package/src/math/Matrix3.js +53 -18
  355. package/src/math/Ray.js +2 -5
  356. package/src/math/Sphere.js +19 -26
  357. package/src/objects/InstancedMesh.js +7 -0
  358. package/src/objects/LOD.js +25 -6
  359. package/src/renderers/WebGL3DRenderTarget.js +1 -1
  360. package/src/renderers/WebGLArrayRenderTarget.js +1 -1
  361. package/src/renderers/WebGLCubeRenderTarget.js +1 -1
  362. package/src/renderers/WebGLMultipleRenderTargets.js +1 -1
  363. package/src/renderers/WebGLRenderTarget.js +1 -1
  364. package/src/renderers/WebGLRenderer.js +36 -62
  365. package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +0 -4
  366. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +0 -1
  367. package/src/renderers/shaders/ShaderChunk/lights_lambert_pars_fragment.glsl.js +0 -2
  368. package/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl.js +0 -2
  369. package/src/renderers/shaders/ShaderChunk/lights_toon_pars_fragment.glsl.js +0 -2
  370. package/src/renderers/shaders/ShaderChunk/packing.glsl.js +8 -0
  371. package/src/renderers/shaders/ShaderChunk.js +3 -0
  372. package/src/renderers/shaders/ShaderLib/background.glsl.js +7 -2
  373. package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +62 -0
  374. package/src/renderers/shaders/ShaderLib/cube.glsl.js +4 -6
  375. package/src/renderers/shaders/ShaderLib.js +20 -6
  376. package/src/renderers/shaders/UniformsLib.js +1 -1
  377. package/src/renderers/shaders/UniformsUtils.js +15 -0
  378. package/src/renderers/webgl/WebGLAttributes.js +2 -0
  379. package/src/renderers/webgl/WebGLBackground.js +15 -7
  380. package/src/renderers/webgl/WebGLLights.js +0 -4
  381. package/src/renderers/webgl/WebGLMaterials.js +2 -1
  382. package/src/renderers/webgl/WebGLShadowMap.js +3 -1
  383. package/src/renderers/webgl/WebGLState.js +31 -1
  384. package/src/renderers/webgl/WebGLTextures.js +71 -18
  385. package/src/renderers/webgl/WebGLUniforms.js +116 -20
  386. package/src/renderers/webgl/WebGLUtils.js +1 -1
  387. package/src/renderers/webxr/WebXRController.js +46 -13
  388. package/src/renderers/webxr/WebXRManager.js +85 -3
  389. package/src/scenes/Scene.js +8 -0
  390. package/src/textures/CompressedArrayTexture.js +18 -0
  391. package/examples/js/libs/lottie_canvas.js +0 -12751
  392. package/examples/js/shaders/PixelShader.js +0 -51
  393. package/examples/jsm/shaders/PixelShader.js +0 -44
@@ -1,15 +1,16 @@
1
1
  ( function () {
2
2
 
3
+ // Special surface finish tag types.
3
4
  // Note: "MATERIAL" tag (e.g. GLITTER, SPECKLE) is not implemented
4
-
5
5
  const FINISH_TYPE_DEFAULT = 0;
6
6
  const FINISH_TYPE_CHROME = 1;
7
7
  const FINISH_TYPE_PEARLESCENT = 2;
8
8
  const FINISH_TYPE_RUBBER = 3;
9
9
  const FINISH_TYPE_MATTE_METALLIC = 4;
10
- const FINISH_TYPE_METAL = 5; // State machine to search a subobject path.
11
- // The LDraw standard establishes these various possible subfolders.
10
+ const FINISH_TYPE_METAL = 5;
12
11
 
12
+ // State machine to search a subobject path.
13
+ // The LDraw standard establishes these various possible subfolders.
13
14
  const FILE_LOCATION_TRY_PARTS = 0;
14
15
  const FILE_LOCATION_TRY_P = 1;
15
16
  const FILE_LOCATION_TRY_MODELS = 2;
@@ -19,11 +20,8 @@
19
20
  const FILE_LOCATION_NOT_FOUND = 6;
20
21
  const MAIN_COLOUR_CODE = '16';
21
22
  const MAIN_EDGE_COLOUR_CODE = '24';
22
-
23
23
  const _tempVec0 = new THREE.Vector3();
24
-
25
24
  const _tempVec1 = new THREE.Vector3();
26
-
27
25
  class LDrawConditionalLineMaterial extends THREE.ShaderMaterial {
28
26
 
29
27
  constructor( parameters ) {
@@ -37,9 +35,7 @@
37
35
  value: 1.0
38
36
  }
39
37
  } ] ),
40
- vertexShader:
41
- /* glsl */
42
- `
38
+ vertexShader: /* glsl */`
43
39
  attribute vec3 control0;
44
40
  attribute vec3 control1;
45
41
  attribute vec3 direction;
@@ -86,9 +82,7 @@
86
82
  #include <fog_vertex>
87
83
  }
88
84
  `,
89
- fragmentShader:
90
- /* glsl */
91
- `
85
+ fragmentShader: /* glsl */`
92
86
  uniform vec3 diffuse;
93
87
  uniform float opacity;
94
88
  varying float discardFlag;
@@ -143,7 +137,6 @@
143
137
  }
144
138
 
145
139
  }
146
-
147
140
  class ConditionalLineSegments extends THREE.LineSegments {
148
141
 
149
142
  constructor( geometry, material ) {
@@ -154,7 +147,6 @@
154
147
  }
155
148
 
156
149
  }
157
-
158
150
  function generateFaceNormals( faces ) {
159
151
 
160
152
  for ( let i = 0, l = faces.length; i < l; i ++ ) {
@@ -164,11 +156,8 @@
164
156
  const v0 = vertices[ 0 ];
165
157
  const v1 = vertices[ 1 ];
166
158
  const v2 = vertices[ 2 ];
167
-
168
159
  _tempVec0.subVectors( v1, v0 );
169
-
170
160
  _tempVec1.subVectors( v2, v1 );
171
-
172
161
  face.faceNormal = new THREE.Vector3().crossVectors( _tempVec0, _tempVec1 ).normalize();
173
162
 
174
163
  }
@@ -176,7 +165,6 @@
176
165
  }
177
166
 
178
167
  const _ray = new THREE.Ray();
179
-
180
168
  function smoothNormals( faces, lineSegments, checkSubSegments = false ) {
181
169
 
182
170
  // NOTE: 1e2 is pretty coarse but was chosen to quantize the resulting value because
@@ -187,8 +175,8 @@
187
175
  // vertices that should be merged might be set to "1.7" and "1.6999..." meaning they won't
188
176
  // get merged. This added epsilon attempts to push these error values to the same quantized
189
177
  // value for the sake of hashing. See "AT-ST mini" dishes. See mrdoob/three#23169.
190
- const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
191
178
 
179
+ const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
192
180
  function hashVertex( v ) {
193
181
 
194
182
  const x = ~ ~ ( v.x * hashMultiplier );
@@ -202,10 +190,10 @@
202
190
 
203
191
  return `${hashVertex( v0 )}_${hashVertex( v1 )}`;
204
192
 
205
- } // converts the two vertices to a ray with a normalized direction and origin of 0, 0, 0 projected
206
- // onto the original line.
207
-
193
+ }
208
194
 
195
+ // converts the two vertices to a ray with a normalized direction and origin of 0, 0, 0 projected
196
+ // onto the original line.
209
197
  function toNormalizedRay( v0, v1, targetRay ) {
210
198
 
211
199
  targetRay.direction.subVectors( v1, v0 ).normalize();
@@ -224,8 +212,9 @@
224
212
  const hardEdges = new Set();
225
213
  const hardEdgeRays = new Map();
226
214
  const halfEdgeList = {};
227
- const normals = []; // Save the list of hard edges by hash
215
+ const normals = [];
228
216
 
217
+ // Save the list of hard edges by hash
229
218
  for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
230
219
 
231
220
  const ls = lineSegments[ i ];
@@ -233,15 +222,15 @@
233
222
  const v0 = vertices[ 0 ];
234
223
  const v1 = vertices[ 1 ];
235
224
  hardEdges.add( hashEdge( v0, v1 ) );
236
- hardEdges.add( hashEdge( v1, v0 ) ); // only generate the hard edge ray map if we're checking subsegments because it's more expensive to check
237
- // and requires more memory.
225
+ hardEdges.add( hashEdge( v1, v0 ) );
238
226
 
227
+ // only generate the hard edge ray map if we're checking subsegments because it's more expensive to check
228
+ // and requires more memory.
239
229
  if ( checkSubSegments ) {
240
230
 
241
231
  // add both ray directions to the map
242
232
  const ray = toNormalizedRay( v0, v1, new THREE.Ray() );
243
233
  const rh1 = hashRay( ray );
244
-
245
234
  if ( ! hardEdgeRays.has( rh1 ) ) {
246
235
 
247
236
  toNormalizedRay( v1, v0, ray );
@@ -253,14 +242,13 @@
253
242
  hardEdgeRays.set( rh1, info );
254
243
  hardEdgeRays.set( rh2, info );
255
244
 
256
- } // store both segments ends in min, max order in the distances array to check if a face edge is a
257
- // subsegment later.
258
-
245
+ }
259
246
 
247
+ // store both segments ends in min, max order in the distances array to check if a face edge is a
248
+ // subsegment later.
260
249
  const info = hardEdgeRays.get( rh1 );
261
250
  let d0 = info.ray.direction.dot( v0 );
262
251
  let d1 = info.ray.direction.dot( v1 );
263
-
264
252
  if ( d0 > d1 ) {
265
253
 
266
254
  [ d0, d1 ] = [ d1, d0 ];
@@ -271,35 +259,34 @@
271
259
 
272
260
  }
273
261
 
274
- } // track the half edges associated with each triangle
275
-
262
+ }
276
263
 
264
+ // track the half edges associated with each triangle
277
265
  for ( let i = 0, l = faces.length; i < l; i ++ ) {
278
266
 
279
267
  const tri = faces[ i ];
280
268
  const vertices = tri.vertices;
281
269
  const vertCount = vertices.length;
282
-
283
270
  for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
284
271
 
285
272
  const index = i2;
286
273
  const next = ( i2 + 1 ) % vertCount;
287
274
  const v0 = vertices[ index ];
288
275
  const v1 = vertices[ next ];
289
- const hash = hashEdge( v0, v1 ); // don't add the triangle if the edge is supposed to be hard
276
+ const hash = hashEdge( v0, v1 );
290
277
 
278
+ // don't add the triangle if the edge is supposed to be hard
291
279
  if ( hardEdges.has( hash ) ) {
292
280
 
293
281
  continue;
294
282
 
295
- } // if checking subsegments then check to see if this edge lies on a hard edge ray and whether its within any ray bounds
296
-
283
+ }
297
284
 
285
+ // if checking subsegments then check to see if this edge lies on a hard edge ray and whether its within any ray bounds
298
286
  if ( checkSubSegments ) {
299
287
 
300
288
  toNormalizedRay( v0, v1, _ray );
301
289
  const rayHash = hashRay( _ray );
302
-
303
290
  if ( hardEdgeRays.has( rayHash ) ) {
304
291
 
305
292
  const info = hardEdgeRays.get( rayHash );
@@ -309,16 +296,14 @@
309
296
  } = info;
310
297
  let d0 = ray.direction.dot( v0 );
311
298
  let d1 = ray.direction.dot( v1 );
312
-
313
299
  if ( d0 > d1 ) {
314
300
 
315
301
  [ d0, d1 ] = [ d1, d0 ];
316
302
 
317
- } // return early if the face edge is found to be a subsegment of a line edge meaning the edge will have "hard" normals
318
-
303
+ }
319
304
 
305
+ // return early if the face edge is found to be a subsegment of a line edge meaning the edge will have "hard" normals
320
306
  let found = false;
321
-
322
307
  for ( let i = 0, l = distances.length; i < l; i += 2 ) {
323
308
 
324
309
  if ( d0 >= distances[ i ] && d1 <= distances[ i + 1 ] ) {
@@ -348,14 +333,13 @@
348
333
 
349
334
  }
350
335
 
351
- } // Iterate until we've tried to connect all faces to share normals
352
-
336
+ }
353
337
 
338
+ // Iterate until we've tried to connect all faces to share normals
354
339
  while ( true ) {
355
340
 
356
341
  // Stop if there are no more faces left
357
342
  let halfEdge = null;
358
-
359
343
  for ( const key in halfEdgeList ) {
360
344
 
361
345
  halfEdge = halfEdgeList[ key ];
@@ -367,62 +351,61 @@
367
351
 
368
352
  break;
369
353
 
370
- } // Exhaustively find all connected faces
371
-
354
+ }
372
355
 
356
+ // Exhaustively find all connected faces
373
357
  const queue = [ halfEdge ];
374
-
375
358
  while ( queue.length > 0 ) {
376
359
 
377
360
  // initialize all vertex normals in this triangle
378
361
  const tri = queue.pop().tri;
379
362
  const vertices = tri.vertices;
380
363
  const vertNormals = tri.normals;
381
- const faceNormal = tri.faceNormal; // Check if any edge is connected to another triangle edge
364
+ const faceNormal = tri.faceNormal;
382
365
 
366
+ // Check if any edge is connected to another triangle edge
383
367
  const vertCount = vertices.length;
384
-
385
368
  for ( let i2 = 0; i2 < vertCount; i2 ++ ) {
386
369
 
387
370
  const index = i2;
388
371
  const next = ( i2 + 1 ) % vertCount;
389
372
  const v0 = vertices[ index ];
390
- const v1 = vertices[ next ]; // delete this triangle from the list so it won't be found again
373
+ const v1 = vertices[ next ];
391
374
 
375
+ // delete this triangle from the list so it won't be found again
392
376
  const hash = hashEdge( v0, v1 );
393
377
  delete halfEdgeList[ hash ];
394
378
  const reverseHash = hashEdge( v1, v0 );
395
379
  const otherInfo = halfEdgeList[ reverseHash ];
396
-
397
380
  if ( otherInfo ) {
398
381
 
399
382
  const otherTri = otherInfo.tri;
400
383
  const otherIndex = otherInfo.index;
401
384
  const otherNormals = otherTri.normals;
402
385
  const otherVertCount = otherNormals.length;
403
- const otherFaceNormal = otherTri.faceNormal; // NOTE: If the angle between faces is > 67.5 degrees then assume it's
386
+ const otherFaceNormal = otherTri.faceNormal;
387
+
388
+ // NOTE: If the angle between faces is > 67.5 degrees then assume it's
404
389
  // hard edge. There are some cases where the line segments do not line up exactly
405
390
  // with or span multiple triangle edges (see Lunar Vehicle wheels).
406
-
407
391
  if ( Math.abs( otherTri.faceNormal.dot( tri.faceNormal ) ) < 0.25 ) {
408
392
 
409
393
  continue;
410
394
 
411
- } // if this triangle has already been traversed then it won't be in
395
+ }
396
+
397
+ // if this triangle has already been traversed then it won't be in
412
398
  // the halfEdgeList. If it has not then add it to the queue and delete
413
399
  // it so it won't be found again.
414
-
415
-
416
400
  if ( reverseHash in halfEdgeList ) {
417
401
 
418
402
  queue.push( otherInfo );
419
403
  delete halfEdgeList[ reverseHash ];
420
404
 
421
- } // share the first normal
422
-
405
+ }
423
406
 
407
+ // share the first normal
424
408
  const otherNext = ( otherIndex + 1 ) % otherVertCount;
425
-
426
409
  if ( vertNormals[ index ] && otherNormals[ otherNext ] && vertNormals[ index ] !== otherNormals[ otherNext ] ) {
427
410
 
428
411
  otherNormals[ otherNext ].norm.add( vertNormals[ index ].norm );
@@ -431,7 +414,6 @@
431
414
  }
432
415
 
433
416
  let sharedNormal1 = vertNormals[ index ] || otherNormals[ otherNext ];
434
-
435
417
  if ( sharedNormal1 === null ) {
436
418
 
437
419
  // it's possible to encounter an edge of a triangle that has already been traversed meaning
@@ -456,9 +438,9 @@
456
438
  otherNormals[ otherNext ] = sharedNormal1;
457
439
  sharedNormal1.norm.add( otherFaceNormal );
458
440
 
459
- } // share the second normal
460
-
441
+ }
461
442
 
443
+ // share the second normal
462
444
  if ( vertNormals[ next ] && otherNormals[ otherIndex ] && vertNormals[ next ] !== otherNormals[ otherIndex ] ) {
463
445
 
464
446
  otherNormals[ otherIndex ].norm.add( vertNormals[ next ].norm );
@@ -467,7 +449,6 @@
467
449
  }
468
450
 
469
451
  let sharedNormal2 = vertNormals[ next ] || otherNormals[ otherIndex ];
470
-
471
452
  if ( sharedNormal2 === null ) {
472
453
 
473
454
  sharedNormal2 = {
@@ -497,9 +478,9 @@
497
478
 
498
479
  }
499
480
 
500
- } // The normals of each face have been added up so now we average them by normalizing the vector.
501
-
481
+ }
502
482
 
483
+ // The normals of each face have been added up so now we average them by normalizing the vector.
503
484
  for ( let i = 0, l = normals.length; i < l; i ++ ) {
504
485
 
505
486
  normals[ i ].normalize();
@@ -531,13 +512,11 @@
531
512
  this.lineNumber = lineNumber;
532
513
 
533
514
  }
534
-
535
515
  seekNonSpace() {
536
516
 
537
517
  while ( this.currentCharIndex < this.lineLength ) {
538
518
 
539
519
  this.currentChar = this.line.charAt( this.currentCharIndex );
540
-
541
520
  if ( this.currentChar !== ' ' && this.currentChar !== '\t' ) {
542
521
 
543
522
  return;
@@ -549,15 +528,14 @@
549
528
  }
550
529
 
551
530
  }
552
-
553
531
  getToken() {
554
532
 
555
- const pos0 = this.currentCharIndex ++; // Seek space
533
+ const pos0 = this.currentCharIndex ++;
556
534
 
535
+ // Seek space
557
536
  while ( this.currentCharIndex < this.lineLength ) {
558
537
 
559
538
  this.currentChar = this.line.charAt( this.currentCharIndex );
560
-
561
539
  if ( this.currentChar === ' ' || this.currentChar === '\t' ) {
562
540
 
563
541
  break;
@@ -573,40 +551,35 @@
573
551
  return this.line.substring( pos0, pos1 );
574
552
 
575
553
  }
576
-
577
554
  getVector() {
578
555
 
579
556
  return new THREE.Vector3( parseFloat( this.getToken() ), parseFloat( this.getToken() ), parseFloat( this.getToken() ) );
580
557
 
581
558
  }
582
-
583
559
  getRemainingString() {
584
560
 
585
561
  return this.line.substring( this.currentCharIndex, this.lineLength );
586
562
 
587
563
  }
588
-
589
564
  isAtTheEnd() {
590
565
 
591
566
  return this.currentCharIndex >= this.lineLength;
592
567
 
593
568
  }
594
-
595
569
  setToEnd() {
596
570
 
597
571
  this.currentCharIndex = this.lineLength;
598
572
 
599
573
  }
600
-
601
574
  getLineNumberString() {
602
575
 
603
576
  return this.lineNumber >= 0 ? ' at line ' + this.lineNumber : '';
604
577
 
605
578
  }
606
579
 
607
- } // Fetches and parses an intermediate representation of LDraw parts files.
608
-
580
+ }
609
581
 
582
+ // Fetches and parses an intermediate representation of LDraw parts files.
610
583
  class LDrawParsedCache {
611
584
 
612
585
  constructor( loader ) {
@@ -615,12 +588,12 @@
615
588
  this._cache = {};
616
589
 
617
590
  }
618
-
619
591
  cloneResult( original ) {
620
592
 
621
- const result = {}; // vertices are transformed and normals computed before being converted to geometry
622
- // so these pieces must be cloned.
593
+ const result = {};
623
594
 
595
+ // vertices are transformed and normals computed before being converted to geometry
596
+ // so these pieces must be cloned.
624
597
  result.faces = original.faces.map( face => {
625
598
 
626
599
  return {
@@ -650,8 +623,9 @@
650
623
  vertices: face.vertices.map( v => v.clone() )
651
624
  };
652
625
 
653
- } ); // none if this is subsequently modified
626
+ } );
654
627
 
628
+ // none if this is subsequently modified
655
629
  result.type = original.type;
656
630
  result.category = original.category;
657
631
  result.keywords = original.keywords;
@@ -659,48 +633,40 @@
659
633
  result.subobjects = original.subobjects;
660
634
  result.fileName = original.fileName;
661
635
  result.totalFaces = original.totalFaces;
662
- result.startingConstructionStep = original.startingConstructionStep;
636
+ result.startingBuildingStep = original.startingBuildingStep;
663
637
  result.materials = original.materials;
664
638
  result.group = null;
665
639
  return result;
666
640
 
667
641
  }
668
-
669
642
  async fetchData( fileName ) {
670
643
 
671
644
  let triedLowerCase = false;
672
645
  let locationState = FILE_LOCATION_TRY_PARTS;
673
-
674
646
  while ( locationState !== FILE_LOCATION_NOT_FOUND ) {
675
647
 
676
648
  let subobjectURL = fileName;
677
-
678
649
  switch ( locationState ) {
679
650
 
680
651
  case FILE_LOCATION_AS_IS:
681
652
  locationState = locationState + 1;
682
653
  break;
683
-
684
654
  case FILE_LOCATION_TRY_PARTS:
685
655
  subobjectURL = 'parts/' + subobjectURL;
686
656
  locationState = locationState + 1;
687
657
  break;
688
-
689
658
  case FILE_LOCATION_TRY_P:
690
659
  subobjectURL = 'p/' + subobjectURL;
691
660
  locationState = locationState + 1;
692
661
  break;
693
-
694
662
  case FILE_LOCATION_TRY_MODELS:
695
663
  subobjectURL = 'models/' + subobjectURL;
696
664
  locationState = locationState + 1;
697
665
  break;
698
-
699
666
  case FILE_LOCATION_TRY_RELATIVE:
700
667
  subobjectURL = fileName.substring( 0, fileName.lastIndexOf( '/' ) + 1 ) + subobjectURL;
701
668
  locationState = locationState + 1;
702
669
  break;
703
-
704
670
  case FILE_LOCATION_TRY_ABSOLUTE:
705
671
  if ( triedLowerCase ) {
706
672
 
@@ -726,7 +692,6 @@
726
692
  fileLoader.setPath( loader.partsLibraryPath );
727
693
  fileLoader.setRequestHeader( loader.requestHeader );
728
694
  fileLoader.setWithCredentials( loader.withCredentials );
729
-
730
695
  try {
731
696
 
732
697
  const text = await fileLoader.loadAsync( subobjectURL );
@@ -743,17 +708,16 @@
743
708
  throw new Error( 'LDrawLoader: Subobject "' + fileName + '" could not be loaded.' );
744
709
 
745
710
  }
746
-
747
711
  parse( text, fileName = null ) {
748
712
 
749
- const loader = this.loader; // final results
713
+ const loader = this.loader;
750
714
 
715
+ // final results
751
716
  const faces = [];
752
717
  const lineSegments = [];
753
718
  const conditionalSegments = [];
754
719
  const subobjects = [];
755
720
  const materials = {};
756
-
757
721
  const getLocalMaterial = colorCode => {
758
722
 
759
723
  return materials[ colorCode ] || null;
@@ -764,8 +728,9 @@
764
728
  let category = null;
765
729
  let keywords = null;
766
730
  let author = null;
767
- let totalFaces = 0; // split into lines
731
+ let totalFaces = 0;
768
732
 
733
+ // split into lines
769
734
  if ( text.indexOf( '\r\n' ) !== - 1 ) {
770
735
 
771
736
  // This is faster than String.split with regex that splits on both
@@ -782,20 +747,21 @@
782
747
  let bfcCCW = true;
783
748
  let bfcInverted = false;
784
749
  let bfcCull = true;
785
- let startingConstructionStep = false; // Parse all line commands
750
+ let startingBuildingStep = false;
786
751
 
752
+ // Parse all line commands
787
753
  for ( let lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
788
754
 
789
755
  const line = lines[ lineIndex ];
790
756
  if ( line.length === 0 ) continue;
791
-
792
757
  if ( parsingEmbeddedFiles ) {
793
758
 
794
759
  if ( line.startsWith( '0 FILE ' ) ) {
795
760
 
796
761
  // Save previous embedded file in the cache
797
- this.setData( currentEmbeddedFileName, currentEmbeddedText ); // New embedded text file
762
+ this.setData( currentEmbeddedFileName, currentEmbeddedText );
798
763
 
764
+ // New embedded text file
799
765
  currentEmbeddedFileName = line.substring( 7 );
800
766
  currentEmbeddedText = '';
801
767
 
@@ -811,15 +777,14 @@
811
777
 
812
778
  const lp = new LineParser( line, lineIndex + 1 );
813
779
  lp.seekNonSpace();
814
-
815
780
  if ( lp.isAtTheEnd() ) {
816
781
 
817
782
  // Empty line
818
783
  continue;
819
784
 
820
- } // Parse the line type
821
-
785
+ }
822
786
 
787
+ // Parse the line type
823
788
  const lineType = lp.getToken();
824
789
  let material;
825
790
  let colorCode;
@@ -827,14 +792,12 @@
827
792
  let ccw;
828
793
  let doubleSided;
829
794
  let v0, v1, v2, v3, c0, c1;
830
-
831
795
  switch ( lineType ) {
832
796
 
833
797
  // Line type 0: Comment or META
834
798
  case '0':
835
799
  // Parse meta directive
836
800
  const meta = lp.getToken();
837
-
838
801
  if ( meta ) {
839
802
 
840
803
  switch ( meta ) {
@@ -842,10 +805,8 @@
842
805
  case '!LDRAW_ORG':
843
806
  type = lp.getToken();
844
807
  break;
845
-
846
808
  case '!COLOUR':
847
809
  material = loader.parseColorMetaDirective( lp );
848
-
849
810
  if ( material ) {
850
811
 
851
812
  materials[ material.userData.code ] = material;
@@ -857,14 +818,11 @@
857
818
  }
858
819
 
859
820
  break;
860
-
861
821
  case '!CATEGORY':
862
822
  category = lp.getToken();
863
823
  break;
864
-
865
824
  case '!KEYWORDS':
866
825
  const newKeywords = lp.getRemainingString().split( ',' );
867
-
868
826
  if ( newKeywords.length > 0 ) {
869
827
 
870
828
  if ( ! keywords ) {
@@ -882,7 +840,6 @@
882
840
  }
883
841
 
884
842
  break;
885
-
886
843
  case 'FILE':
887
844
  if ( lineIndex > 0 ) {
888
845
 
@@ -896,13 +853,11 @@
896
853
  }
897
854
 
898
855
  break;
899
-
900
856
  case 'BFC':
901
857
  // Changes to the backface culling state
902
858
  while ( ! lp.isAtTheEnd() ) {
903
859
 
904
860
  const token = lp.getToken();
905
-
906
861
  switch ( token ) {
907
862
 
908
863
  case 'CERTIFY':
@@ -910,21 +865,17 @@
910
865
  bfcCertified = token === 'CERTIFY';
911
866
  bfcCCW = true;
912
867
  break;
913
-
914
868
  case 'CW':
915
869
  case 'CCW':
916
870
  bfcCCW = token === 'CCW';
917
871
  break;
918
-
919
872
  case 'INVERTNEXT':
920
873
  bfcInverted = true;
921
874
  break;
922
-
923
875
  case 'CLIP':
924
876
  case 'NOCLIP':
925
877
  bfcCull = token === 'CLIP';
926
878
  break;
927
-
928
879
  default:
929
880
  console.warn( 'THREE.LDrawLoader: BFC directive "' + token + '" is unknown.' );
930
881
  break;
@@ -934,15 +885,12 @@
934
885
  }
935
886
 
936
887
  break;
937
-
938
888
  case 'STEP':
939
- startingConstructionStep = true;
889
+ startingBuildingStep = true;
940
890
  break;
941
-
942
891
  case 'Author:':
943
892
  author = lp.getToken();
944
893
  break;
945
-
946
894
  default:
947
895
  // Other meta directives are not implemented
948
896
  break;
@@ -952,8 +900,8 @@
952
900
  }
953
901
 
954
902
  break;
955
- // Line type 1: Sub-object file
956
903
 
904
+ // Line type 1: Sub-object file
957
905
  case '1':
958
906
  colorCode = lp.getToken();
959
907
  material = getLocalMaterial( colorCode );
@@ -971,7 +919,6 @@
971
919
  const m8 = parseFloat( lp.getToken() );
972
920
  const matrix = new THREE.Matrix4().set( m0, m1, m2, posX, m3, m4, m5, posY, m6, m7, m8, posZ, 0, 0, 0, 1 );
973
921
  let fileName = lp.getRemainingString().trim().replace( /\\/g, '/' );
974
-
975
922
  if ( loader.fileMap[ fileName ] ) {
976
923
 
977
924
  // Found the subobject path in the preloaded file path map
@@ -998,12 +945,13 @@
998
945
  matrix: matrix,
999
946
  fileName: fileName,
1000
947
  inverted: bfcInverted,
1001
- startingConstructionStep: startingConstructionStep
948
+ startingBuildingStep: startingBuildingStep
1002
949
  } );
950
+ startingBuildingStep = false;
1003
951
  bfcInverted = false;
1004
952
  break;
1005
- // Line type 2: Line segment
1006
953
 
954
+ // Line type 2: Line segment
1007
955
  case '2':
1008
956
  colorCode = lp.getToken();
1009
957
  material = getLocalMaterial( colorCode );
@@ -1016,8 +964,8 @@
1016
964
  };
1017
965
  lineSegments.push( segment );
1018
966
  break;
1019
- // Line type 5: Conditional Line segment
1020
967
 
968
+ // Line type 5: Conditional Line segment
1021
969
  case '5':
1022
970
  colorCode = lp.getToken();
1023
971
  material = getLocalMaterial( colorCode );
@@ -1033,14 +981,13 @@
1033
981
  };
1034
982
  conditionalSegments.push( segment );
1035
983
  break;
1036
- // Line type 3: Triangle
1037
984
 
985
+ // Line type 3: Triangle
1038
986
  case '3':
1039
987
  colorCode = lp.getToken();
1040
988
  material = getLocalMaterial( colorCode );
1041
989
  ccw = bfcCCW;
1042
990
  doubleSided = ! bfcCertified || ! bfcCull;
1043
-
1044
991
  if ( ccw === true ) {
1045
992
 
1046
993
  v0 = lp.getVector();
@@ -1063,7 +1010,6 @@
1063
1010
  normals: [ null, null, null ]
1064
1011
  } );
1065
1012
  totalFaces ++;
1066
-
1067
1013
  if ( doubleSided === true ) {
1068
1014
 
1069
1015
  faces.push( {
@@ -1078,14 +1024,13 @@
1078
1024
  }
1079
1025
 
1080
1026
  break;
1081
- // Line type 4: Quadrilateral
1082
1027
 
1028
+ // Line type 4: Quadrilateral
1083
1029
  case '4':
1084
1030
  colorCode = lp.getToken();
1085
1031
  material = getLocalMaterial( colorCode );
1086
1032
  ccw = bfcCCW;
1087
1033
  doubleSided = ! bfcCertified || ! bfcCull;
1088
-
1089
1034
  if ( ccw === true ) {
1090
1035
 
1091
1036
  v0 = lp.getVector();
@@ -1100,10 +1045,10 @@
1100
1045
  v1 = lp.getVector();
1101
1046
  v0 = lp.getVector();
1102
1047
 
1103
- } // specifically place the triangle diagonal in the v0 and v1 slots so we can
1104
- // account for the doubling of vertices later when smoothing normals.
1105
-
1048
+ }
1106
1049
 
1050
+ // specifically place the triangle diagonal in the v0 and v1 slots so we can
1051
+ // account for the doubling of vertices later when smoothing normals.
1107
1052
  faces.push( {
1108
1053
  material: material,
1109
1054
  colorCode: colorCode,
@@ -1112,7 +1057,6 @@
1112
1057
  normals: [ null, null, null, null ]
1113
1058
  } );
1114
1059
  totalFaces += 2;
1115
-
1116
1060
  if ( doubleSided === true ) {
1117
1061
 
1118
1062
  faces.push( {
@@ -1127,7 +1071,6 @@
1127
1071
  }
1128
1072
 
1129
1073
  break;
1130
-
1131
1074
  default:
1132
1075
  throw new Error( 'LDrawLoader: Unknown line type "' + lineType + '"' + lp.getLineNumberString() + '.' );
1133
1076
 
@@ -1151,20 +1094,19 @@
1151
1094
  author,
1152
1095
  subobjects,
1153
1096
  totalFaces,
1154
- startingConstructionStep,
1097
+ startingBuildingStep,
1155
1098
  materials,
1156
1099
  fileName,
1157
1100
  group: null
1158
1101
  };
1159
1102
 
1160
- } // returns an (optionally cloned) instance of the data
1161
-
1103
+ }
1162
1104
 
1105
+ // returns an (optionally cloned) instance of the data
1163
1106
  getData( fileName, clone = true ) {
1164
1107
 
1165
1108
  const key = fileName.toLowerCase();
1166
1109
  const result = this._cache[ key ];
1167
-
1168
1110
  if ( result === null || result instanceof Promise ) {
1169
1111
 
1170
1112
  return null;
@@ -1181,14 +1123,13 @@
1181
1123
 
1182
1124
  }
1183
1125
 
1184
- } // kicks off a fetch and parse of the requested data if it hasn't already been loaded. Returns when
1185
- // the data is ready to use and can be retrieved synchronously with "getData".
1186
-
1126
+ }
1187
1127
 
1128
+ // kicks off a fetch and parse of the requested data if it hasn't already been loaded. Returns when
1129
+ // the data is ready to use and can be retrieved synchronously with "getData".
1188
1130
  async ensureDataLoaded( fileName ) {
1189
1131
 
1190
1132
  const key = fileName.toLowerCase();
1191
-
1192
1133
  if ( ! ( key in this._cache ) ) {
1193
1134
 
1194
1135
  // replace the promise with a copy of the parsed data for immediate processing
@@ -1204,9 +1145,9 @@
1204
1145
 
1205
1146
  await this._cache[ key ];
1206
1147
 
1207
- } // sets the data in the cache from parsed data
1208
-
1148
+ }
1209
1149
 
1150
+ // sets the data in the cache from parsed data
1210
1151
  setData( fileName, text ) {
1211
1152
 
1212
1153
  const key = fileName.toLowerCase();
@@ -1214,14 +1155,13 @@
1214
1155
 
1215
1156
  }
1216
1157
 
1217
- } // returns the material for an associated color code. If the color code is 16 for a face or 24 for
1218
- // an edge then the passthroughColorCode is used.
1219
-
1158
+ }
1220
1159
 
1160
+ // returns the material for an associated color code. If the color code is 16 for a face or 24 for
1161
+ // an edge then the passthroughColorCode is used.
1221
1162
  function getMaterialFromCode( colorCode, parentColorCode, materialHierarchy, forEdge ) {
1222
1163
 
1223
1164
  const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
1224
-
1225
1165
  if ( isPassthrough ) {
1226
1166
 
1227
1167
  colorCode = parentColorCode;
@@ -1230,9 +1170,9 @@
1230
1170
 
1231
1171
  return materialHierarchy[ colorCode ] || null;
1232
1172
 
1233
- } // Class used to parse and build LDraw parts as three.js objects and cache them if they're a "Part" type.
1234
-
1173
+ }
1235
1174
 
1175
+ // Class used to parse and build LDraw parts as three.js objects and cache them if they're a "Part" type.
1236
1176
  class LDrawPartsGeometryCache {
1237
1177
 
1238
1178
  constructor( loader ) {
@@ -1241,29 +1181,30 @@
1241
1181
  this.parseCache = new LDrawParsedCache( loader );
1242
1182
  this._cache = {};
1243
1183
 
1244
- } // Convert the given file information into a mesh by processing subobjects.
1245
-
1184
+ }
1246
1185
 
1186
+ // Convert the given file information into a mesh by processing subobjects.
1247
1187
  async processIntoMesh( info ) {
1248
1188
 
1249
1189
  const loader = this.loader;
1250
1190
  const parseCache = this.parseCache;
1251
- const faceMaterials = new Set(); // Processes the part subobject information to load child parts and merge geometry onto part
1252
- // piece object.
1191
+ const faceMaterials = new Set();
1253
1192
 
1193
+ // Processes the part subobject information to load child parts and merge geometry onto part
1194
+ // piece object.
1254
1195
  const processInfoSubobjects = async ( info, subobject = null ) => {
1255
1196
 
1256
1197
  const subobjects = info.subobjects;
1257
- const promises = []; // Trigger load of all subobjects. If a subobject isn't a primitive then load it as a separate
1258
- // group which lets instruction steps apply correctly.
1198
+ const promises = [];
1259
1199
 
1200
+ // Trigger load of all subobjects. If a subobject isn't a primitive then load it as a separate
1201
+ // group which lets instruction steps apply correctly.
1260
1202
  for ( let i = 0, l = subobjects.length; i < l; i ++ ) {
1261
1203
 
1262
1204
  const subobject = subobjects[ i ];
1263
1205
  const promise = parseCache.ensureDataLoaded( subobject.fileName ).then( () => {
1264
1206
 
1265
1207
  const subobjectInfo = parseCache.getData( subobject.fileName, false );
1266
-
1267
1208
  if ( ! isPrimitiveType( subobjectInfo.type ) ) {
1268
1209
 
1269
1210
  return this.loadModel( subobject.fileName ).catch( error => {
@@ -1290,42 +1231,40 @@
1290
1231
  group.userData.fileName = info.fileName;
1291
1232
  info.group = group;
1292
1233
  const subobjectInfos = await Promise.all( promises );
1293
-
1294
1234
  for ( let i = 0, l = subobjectInfos.length; i < l; i ++ ) {
1295
1235
 
1296
1236
  const subobject = info.subobjects[ i ];
1297
1237
  const subobjectInfo = subobjectInfos[ i ];
1298
-
1299
1238
  if ( subobjectInfo === null ) {
1300
1239
 
1301
1240
  // the subobject failed to load
1302
1241
  continue;
1303
1242
 
1304
- } // if the subobject was loaded as a separate group then apply the parent scopes materials
1305
-
1243
+ }
1306
1244
 
1245
+ // if the subobject was loaded as a separate group then apply the parent scopes materials
1307
1246
  if ( subobjectInfo.isGroup ) {
1308
1247
 
1309
1248
  const subobjectGroup = subobjectInfo;
1310
1249
  subobject.matrix.decompose( subobjectGroup.position, subobjectGroup.quaternion, subobjectGroup.scale );
1311
- subobjectGroup.userData.startingConstructionStep = subobject.startingConstructionStep;
1250
+ subobjectGroup.userData.startingBuildingStep = subobject.startingBuildingStep;
1312
1251
  subobjectGroup.name = subobject.fileName;
1313
1252
  loader.applyMaterialsToMesh( subobjectGroup, subobject.colorCode, info.materials );
1314
1253
  subobjectGroup.userData.colorCode = subobject.colorCode;
1315
1254
  group.add( subobjectGroup );
1316
1255
  continue;
1317
1256
 
1318
- } // add the subobject group if it has children in case it has both children and primitives
1319
-
1257
+ }
1320
1258
 
1259
+ // add the subobject group if it has children in case it has both children and primitives
1321
1260
  if ( subobjectInfo.group.children.length ) {
1322
1261
 
1323
1262
  group.add( subobjectInfo.group );
1324
1263
 
1325
- } // transform the primitives into the local space of the parent piece and append them to
1326
- // to the parent primitives list.
1327
-
1264
+ }
1328
1265
 
1266
+ // transform the primitives into the local space of the parent piece and append them to
1267
+ // to the parent primitives list.
1329
1268
  const parentLineSegments = info.lineSegments;
1330
1269
  const parentConditionalSegments = info.conditionalSegments;
1331
1270
  const parentFaces = info.faces;
@@ -1337,7 +1276,6 @@
1337
1276
  const matrixScaleInverted = matrix.determinant() < 0;
1338
1277
  const colorCode = subobject.colorCode;
1339
1278
  const lineColorCode = colorCode === MAIN_COLOUR_CODE ? MAIN_EDGE_COLOUR_CODE : colorCode;
1340
-
1341
1279
  for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
1342
1280
 
1343
1281
  const ls = lineSegments[ i ];
@@ -1369,7 +1307,6 @@
1369
1307
 
1370
1308
  const tri = faces[ i ];
1371
1309
  const vertices = tri.vertices;
1372
-
1373
1310
  for ( let i = 0, l = vertices.length; i < l; i ++ ) {
1374
1311
 
1375
1312
  vertices[ i ].applyMatrix4( matrix );
@@ -1378,9 +1315,10 @@
1378
1315
 
1379
1316
  tri.colorCode = tri.colorCode === MAIN_COLOUR_CODE ? colorCode : tri.colorCode;
1380
1317
  tri.material = tri.material || getMaterialFromCode( tri.colorCode, colorCode, info.materials, false );
1381
- faceMaterials.add( tri.colorCode ); // If the scale of the object is negated then the triangle winding order
1382
- // needs to be flipped.
1318
+ faceMaterials.add( tri.colorCode );
1383
1319
 
1320
+ // If the scale of the object is negated then the triangle winding order
1321
+ // needs to be flipped.
1384
1322
  if ( matrixScaleInverted !== inverted ) {
1385
1323
 
1386
1324
  vertices.reverse();
@@ -1393,10 +1331,10 @@
1393
1331
 
1394
1332
  info.totalFaces += subobjectInfo.totalFaces;
1395
1333
 
1396
- } // Apply the parent subobjects pass through material code to this object. This is done several times due
1397
- // to material scoping.
1398
-
1334
+ }
1399
1335
 
1336
+ // Apply the parent subobjects pass through material code to this object. This is done several times due
1337
+ // to material scoping.
1400
1338
  if ( subobject ) {
1401
1339
 
1402
1340
  loader.applyMaterialsToMesh( group, subobject.colorCode, info.materials );
@@ -1406,9 +1344,9 @@
1406
1344
 
1407
1345
  return info;
1408
1346
 
1409
- }; // Track material use to see if we need to use the normal smooth slow path for hard edges.
1410
-
1347
+ };
1411
1348
 
1349
+ // Track material use to see if we need to use the normal smooth slow path for hard edges.
1412
1350
  for ( let i = 0, l = info.faces; i < l; i ++ ) {
1413
1351
 
1414
1352
  faceMaterials.add( info.faces[ i ].colorCode );
@@ -1416,18 +1354,16 @@
1416
1354
  }
1417
1355
 
1418
1356
  await processInfoSubobjects( info );
1419
-
1420
1357
  if ( loader.smoothNormals ) {
1421
1358
 
1422
1359
  const checkSubSegments = faceMaterials.size > 1;
1423
1360
  generateFaceNormals( info.faces );
1424
1361
  smoothNormals( info.faces, info.lineSegments, checkSubSegments );
1425
1362
 
1426
- } // Add the primitive objects and metadata.
1427
-
1363
+ }
1428
1364
 
1365
+ // Add the primitive objects and metadata.
1429
1366
  const group = info.group;
1430
-
1431
1367
  if ( info.faces.length > 0 ) {
1432
1368
 
1433
1369
  group.add( createObject( info.faces, 3, false, info.totalFaces ) );
@@ -1449,13 +1385,11 @@
1449
1385
  return group;
1450
1386
 
1451
1387
  }
1452
-
1453
1388
  hasCachedModel( fileName ) {
1454
1389
 
1455
1390
  return fileName !== null && fileName.toLowerCase() in this._cache;
1456
1391
 
1457
1392
  }
1458
-
1459
1393
  async getCachedModel( fileName ) {
1460
1394
 
1461
1395
  if ( fileName !== null && this.hasCachedModel( fileName ) ) {
@@ -1470,14 +1404,13 @@
1470
1404
 
1471
1405
  }
1472
1406
 
1473
- } // Loads and parses the model with the given file name. Returns a cached copy if available.
1474
-
1407
+ }
1475
1408
 
1409
+ // Loads and parses the model with the given file name. Returns a cached copy if available.
1476
1410
  async loadModel( fileName ) {
1477
1411
 
1478
1412
  const parseCache = this.parseCache;
1479
1413
  const key = fileName.toLowerCase();
1480
-
1481
1414
  if ( this.hasCachedModel( fileName ) ) {
1482
1415
 
1483
1416
  // Return cached model if available.
@@ -1489,37 +1422,37 @@
1489
1422
  // Ensure the file data is loaded and pre parsed.
1490
1423
  await parseCache.ensureDataLoaded( fileName );
1491
1424
  const info = parseCache.getData( fileName );
1492
- const promise = this.processIntoMesh( info ); // Now that the file has loaded it's possible that another part parse has been waiting in parallel
1425
+ const promise = this.processIntoMesh( info );
1426
+
1427
+ // Now that the file has loaded it's possible that another part parse has been waiting in parallel
1493
1428
  // so check the cache again to see if it's been added since the last async operation so we don't
1494
1429
  // do unnecessary work.
1495
-
1496
1430
  if ( this.hasCachedModel( fileName ) ) {
1497
1431
 
1498
1432
  return this.getCachedModel( fileName );
1499
1433
 
1500
- } // Cache object if it's a part so it can be reused later.
1501
-
1434
+ }
1502
1435
 
1436
+ // Cache object if it's a part so it can be reused later.
1503
1437
  if ( isPartType( info.type ) ) {
1504
1438
 
1505
1439
  this._cache[ key ] = promise;
1506
1440
 
1507
- } // return a copy
1508
-
1441
+ }
1509
1442
 
1443
+ // return a copy
1510
1444
  const group = await promise;
1511
1445
  return group.clone();
1512
1446
 
1513
1447
  }
1514
1448
 
1515
- } // parses the given model text into a renderable object. Returns cached copy if available.
1516
-
1449
+ }
1517
1450
 
1451
+ // parses the given model text into a renderable object. Returns cached copy if available.
1518
1452
  async parseModel( text ) {
1519
1453
 
1520
1454
  const parseCache = this.parseCache;
1521
1455
  const info = parseCache.parse( text );
1522
-
1523
1456
  if ( isPartType( info.type ) && this.hasCachedModel( info.fileName ) ) {
1524
1457
 
1525
1458
  return this.getCachedModel( info.fileName );
@@ -1531,7 +1464,6 @@
1531
1464
  }
1532
1465
 
1533
1466
  }
1534
-
1535
1467
  function sortByMaterial( a, b ) {
1536
1468
 
1537
1469
  if ( a.colorCode === b.colorCode ) {
@@ -1554,9 +1486,9 @@
1554
1486
 
1555
1487
  // Creates a THREE.LineSegments (elementSize = 2) or a THREE.Mesh (elementSize = 3 )
1556
1488
  // With per face / segment material, implemented with mesh groups and materials array
1489
+
1557
1490
  // Sort the faces or line segments by color code to make later the mesh groups
1558
1491
  elements.sort( sortByMaterial );
1559
-
1560
1492
  if ( totalElements === null ) {
1561
1493
 
1562
1494
  totalElements = elements.length;
@@ -1572,12 +1504,10 @@
1572
1504
  let index0 = 0;
1573
1505
  let numGroupVerts = 0;
1574
1506
  let offset = 0;
1575
-
1576
1507
  for ( let iElem = 0, nElem = elements.length; iElem < nElem; iElem ++ ) {
1577
1508
 
1578
1509
  const elem = elements[ iElem ];
1579
1510
  let vertices = elem.vertices;
1580
-
1581
1511
  if ( vertices.length === 4 ) {
1582
1512
 
1583
1513
  quadArray[ 0 ] = vertices[ 0 ];
@@ -1598,9 +1528,9 @@
1598
1528
  positions[ index + 1 ] = v.y;
1599
1529
  positions[ index + 2 ] = v.z;
1600
1530
 
1601
- } // create the normals array if this is a set of faces
1602
-
1531
+ }
1603
1532
 
1533
+ // create the normals array if this is a set of faces
1604
1534
  if ( elementSize === 3 ) {
1605
1535
 
1606
1536
  if ( ! elem.faceNormal ) {
@@ -1608,17 +1538,13 @@
1608
1538
  const v0 = vertices[ 0 ];
1609
1539
  const v1 = vertices[ 1 ];
1610
1540
  const v2 = vertices[ 2 ];
1611
-
1612
1541
  _tempVec0.subVectors( v1, v0 );
1613
-
1614
1542
  _tempVec1.subVectors( v2, v1 );
1615
-
1616
1543
  elem.faceNormal = new THREE.Vector3().crossVectors( _tempVec0, _tempVec1 ).normalize();
1617
1544
 
1618
1545
  }
1619
1546
 
1620
1547
  let elemNormals = elem.normals;
1621
-
1622
1548
  if ( elemNormals.length === 4 ) {
1623
1549
 
1624
1550
  quadArray[ 0 ] = elemNormals[ 0 ];
@@ -1635,7 +1561,6 @@
1635
1561
 
1636
1562
  // use face normal if a vertex normal is not provided
1637
1563
  let n = elem.faceNormal;
1638
-
1639
1564
  if ( elemNormals[ j ] ) {
1640
1565
 
1641
1566
  n = elemNormals[ j ].norm;
@@ -1660,7 +1585,6 @@
1660
1585
  }
1661
1586
 
1662
1587
  const material = elem.material;
1663
-
1664
1588
  if ( material !== null ) {
1665
1589
 
1666
1590
  if ( elementSize === 3 ) {
@@ -1710,7 +1634,6 @@
1710
1634
  }
1711
1635
 
1712
1636
  bufferGeometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
1713
-
1714
1637
  if ( normals !== null ) {
1715
1638
 
1716
1639
  bufferGeometry.setAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
@@ -1718,7 +1641,6 @@
1718
1641
  }
1719
1642
 
1720
1643
  let object3d = null;
1721
-
1722
1644
  if ( elementSize === 2 ) {
1723
1645
 
1724
1646
  if ( isConditionalSegments ) {
@@ -1743,7 +1665,6 @@
1743
1665
  const controlArray0 = new Float32Array( elements.length * 3 * 2 );
1744
1666
  const controlArray1 = new Float32Array( elements.length * 3 * 2 );
1745
1667
  const directionArray = new Float32Array( elements.length * 3 * 2 );
1746
-
1747
1668
  for ( let i = 0, l = elements.length; i < l; i ++ ) {
1748
1669
 
1749
1670
  const os = elements[ i ];
@@ -1783,28 +1704,36 @@
1783
1704
 
1784
1705
  return object3d;
1785
1706
 
1786
- } //
1707
+ }
1787
1708
 
1709
+ //
1788
1710
 
1789
1711
  class LDrawLoader extends THREE.Loader {
1790
1712
 
1791
1713
  constructor( manager ) {
1792
1714
 
1793
- super( manager ); // Array of THREE.Material
1715
+ super( manager );
1794
1716
 
1717
+ // Array of THREE.Material
1795
1718
  this.materials = [];
1796
- this.materialLibrary = {}; // This also allows to handle the embedded text files ("0 FILE" lines)
1719
+ this.materialLibrary = {};
1797
1720
 
1798
- this.partsCache = new LDrawPartsGeometryCache( this ); // 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.
1721
+ // This also allows to handle the embedded text files ("0 FILE" lines)
1722
+ this.partsCache = new LDrawPartsGeometryCache( this );
1799
1723
 
1800
- this.fileMap = {}; // Initializes the materials library with default materials
1724
+ // 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.
1725
+ this.fileMap = {};
1801
1726
 
1802
- this.setMaterials( [] ); // If this flag is set to true the vertex normals will be smoothed.
1727
+ // Initializes the materials library with default materials
1728
+ this.setMaterials( [] );
1803
1729
 
1804
- this.smoothNormals = true; // The path to load parts from the LDraw parts library from.
1730
+ // If this flag is set to true the vertex normals will be smoothed.
1731
+ this.smoothNormals = true;
1805
1732
 
1806
- this.partsLibraryPath = ''; // Material assigned to not available colors for meshes and edges
1733
+ // The path to load parts from the LDraw parts library from.
1734
+ this.partsLibraryPath = '';
1807
1735
 
1736
+ // Material assigned to not available colors for meshes and edges
1808
1737
  this.missingColorMaterial = new THREE.MeshStandardMaterial( {
1809
1738
  color: 0xFF00FF,
1810
1739
  roughness: 0.3,
@@ -1824,14 +1753,12 @@
1824
1753
  this.missingEdgeColorMaterial.userData.conditionalEdgeMaterial = this.missingConditionalEdgeColorMaterial;
1825
1754
 
1826
1755
  }
1827
-
1828
1756
  setPartsLibraryPath( path ) {
1829
1757
 
1830
1758
  this.partsLibraryPath = path;
1831
1759
  return this;
1832
1760
 
1833
1761
  }
1834
-
1835
1762
  async preloadMaterials( url ) {
1836
1763
 
1837
1764
  const fileLoader = new THREE.FileLoader( this.manager );
@@ -1842,11 +1769,9 @@
1842
1769
  const colorLineRegex = /^0 !COLOUR/;
1843
1770
  const lines = text.split( /[\n\r]/g );
1844
1771
  const materials = [];
1845
-
1846
1772
  for ( let i = 0, l = lines.length; i < l; i ++ ) {
1847
1773
 
1848
1774
  const line = lines[ i ];
1849
-
1850
1775
  if ( colorLineRegex.test( line ) ) {
1851
1776
 
1852
1777
  const directive = line.replace( colorLineRegex, '' );
@@ -1860,7 +1785,6 @@
1860
1785
  this.setMaterials( materials );
1861
1786
 
1862
1787
  }
1863
-
1864
1788
  load( url, onLoad, onProgress, onError ) {
1865
1789
 
1866
1790
  const fileLoader = new THREE.FileLoader( this.manager );
@@ -1872,7 +1796,7 @@
1872
1796
  this.partsCache.parseModel( text, this.materialLibrary ).then( group => {
1873
1797
 
1874
1798
  this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1875
- this.computeConstructionSteps( group );
1799
+ this.computeBuildingSteps( group );
1876
1800
  group.userData.fileName = url;
1877
1801
  onLoad( group );
1878
1802
 
@@ -1881,50 +1805,45 @@
1881
1805
  }, onProgress, onError );
1882
1806
 
1883
1807
  }
1884
-
1885
1808
  parse( text, onLoad ) {
1886
1809
 
1887
1810
  this.partsCache.parseModel( text, this.materialLibrary ).then( group => {
1888
1811
 
1889
1812
  this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1890
- this.computeConstructionSteps( group );
1813
+ this.computeBuildingSteps( group );
1891
1814
  group.userData.fileName = '';
1892
1815
  onLoad( group );
1893
1816
 
1894
1817
  } );
1895
1818
 
1896
1819
  }
1897
-
1898
1820
  setMaterials( materials ) {
1899
1821
 
1900
1822
  this.materialLibrary = {};
1901
1823
  this.materials = [];
1902
-
1903
1824
  for ( let i = 0, l = materials.length; i < l; i ++ ) {
1904
1825
 
1905
1826
  this.addMaterial( materials[ i ] );
1906
1827
 
1907
- } // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
1908
-
1828
+ }
1909
1829
 
1830
+ // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
1910
1831
  this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Main_Colour CODE 16 VALUE #FF8080 EDGE #333333' ) ) );
1911
1832
  this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333' ) ) );
1912
1833
  return this;
1913
1834
 
1914
1835
  }
1915
-
1916
1836
  setFileMap( fileMap ) {
1917
1837
 
1918
1838
  this.fileMap = fileMap;
1919
1839
  return this;
1920
1840
 
1921
1841
  }
1922
-
1923
1842
  addMaterial( material ) {
1924
1843
 
1925
1844
  // Adds a material to the material library which is on top of the parse scopes stack. And also to the materials array
1926
- const matLib = this.materialLibrary;
1927
1845
 
1846
+ const matLib = this.materialLibrary;
1928
1847
  if ( ! matLib[ material.userData.code ] ) {
1929
1848
 
1930
1849
  this.materials.push( material );
@@ -1935,7 +1854,6 @@
1935
1854
  return this;
1936
1855
 
1937
1856
  }
1938
-
1939
1857
  getMaterial( colorCode ) {
1940
1858
 
1941
1859
  if ( colorCode.startsWith( '0x2' ) ) {
@@ -1948,10 +1866,10 @@
1948
1866
 
1949
1867
  return this.materialLibrary[ colorCode ] || null;
1950
1868
 
1951
- } // Applies the appropriate materials to a prebuilt hierarchy of geometry. Assumes that color codes are present
1952
- // in the material array if they need to be filled in.
1953
-
1869
+ }
1954
1870
 
1871
+ // Applies the appropriate materials to a prebuilt hierarchy of geometry. Assumes that color codes are present
1872
+ // in the material array if they need to be filled in.
1955
1873
  applyMaterialsToMesh( group, parentColorCode, materialHierarchy, finalMaterialPass = false ) {
1956
1874
 
1957
1875
  // find any missing materials as indicated by a color code string and replace it with a material from the current material lib
@@ -1981,10 +1899,11 @@
1981
1899
 
1982
1900
  }
1983
1901
 
1984
- } ); // Returns the appropriate material for the object (line or face) given color code. If the code is "pass through"
1902
+ } );
1903
+
1904
+ // Returns the appropriate material for the object (line or face) given color code. If the code is "pass through"
1985
1905
  // (24 for lines, 16 for edges) then the pass through color code is used. If that is also pass through then it's
1986
1906
  // simply returned for the subsequent material application.
1987
-
1988
1907
  function getMaterial( c, colorCode ) {
1989
1908
 
1990
1909
  // if our parent is a passthrough color code and we don't have the current material color available then
@@ -1997,7 +1916,6 @@
1997
1916
 
1998
1917
  const forEdge = c.isLineSegments || c.isConditionalLine;
1999
1918
  const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
2000
-
2001
1919
  if ( isPassthrough ) {
2002
1920
 
2003
1921
  colorCode = parentColorCode;
@@ -2005,7 +1923,6 @@
2005
1923
  }
2006
1924
 
2007
1925
  let material = null;
2008
-
2009
1926
  if ( colorCode in materialHierarchy ) {
2010
1927
 
2011
1928
  material = materialHierarchy[ colorCode ];
@@ -2015,12 +1932,12 @@
2015
1932
  // see if we can get the final material from from the "getMaterial" function which will attempt to
2016
1933
  // parse the "direct" colors
2017
1934
  material = loader.getMaterial( colorCode );
2018
-
2019
1935
  if ( material === null ) {
2020
1936
 
2021
1937
  // otherwise throw a warning if this is final opportunity to set the material
2022
- console.warn( `LDrawLoader: Material properties for code ${colorCode} not available.` ); // And return the 'missing color' material
1938
+ console.warn( `LDrawLoader: Material properties for code ${colorCode} not available.` );
2023
1939
 
1940
+ // And return the 'missing color' material
2024
1941
  material = loader.missingColorMaterial;
2025
1942
 
2026
1943
  }
@@ -2034,7 +1951,6 @@
2034
1951
  if ( c.isLineSegments ) {
2035
1952
 
2036
1953
  material = material.userData.edgeMaterial;
2037
-
2038
1954
  if ( c.isConditionalLine ) {
2039
1955
 
2040
1956
  material = material.userData.conditionalEdgeMaterial;
@@ -2048,49 +1964,46 @@
2048
1964
  }
2049
1965
 
2050
1966
  }
2051
-
2052
1967
  getMainMaterial() {
2053
1968
 
2054
1969
  return this.getMaterial( MAIN_COLOUR_CODE );
2055
1970
 
2056
1971
  }
2057
-
2058
1972
  getMainEdgeMaterial() {
2059
1973
 
2060
1974
  const mat = this.getMaterial( MAIN_EDGE_COLOUR_CODE );
2061
1975
  return mat ? mat.userData.edgeMaterial : null;
2062
1976
 
2063
1977
  }
2064
-
2065
1978
  parseColorMetaDirective( lineParser ) {
2066
1979
 
2067
1980
  // Parses a color definition and returns a THREE.Material
2068
- let code = null; // Triangle and line colors
2069
1981
 
1982
+ let code = null;
1983
+
1984
+ // Triangle and line colors
2070
1985
  let color = 0xFF00FF;
2071
- let edgeColor = 0xFF00FF; // Transparency
1986
+ let edgeColor = 0xFF00FF;
2072
1987
 
1988
+ // Transparency
2073
1989
  let alpha = 1;
2074
- let isTransparent = false; // Self-illumination:
2075
-
1990
+ let isTransparent = false;
1991
+ // Self-illumination:
2076
1992
  let luminance = 0;
2077
1993
  let finishType = FINISH_TYPE_DEFAULT;
2078
1994
  let edgeMaterial = null;
2079
1995
  const name = lineParser.getToken();
2080
-
2081
1996
  if ( ! name ) {
2082
1997
 
2083
1998
  throw new Error( 'LDrawLoader: Material name was expected after "!COLOUR tag' + lineParser.getLineNumberString() + '.' );
2084
1999
 
2085
- } // Parse tag tokens and their parameters
2086
-
2000
+ }
2087
2001
 
2002
+ // Parse tag tokens and their parameters
2088
2003
  let token = null;
2089
-
2090
2004
  while ( true ) {
2091
2005
 
2092
2006
  token = lineParser.getToken();
2093
-
2094
2007
  if ( ! token ) {
2095
2008
 
2096
2009
  break;
@@ -2104,10 +2017,8 @@
2104
2017
  case 'CODE':
2105
2018
  code = lineParser.getToken();
2106
2019
  break;
2107
-
2108
2020
  case 'VALUE':
2109
2021
  color = lineParser.getToken();
2110
-
2111
2022
  if ( color.startsWith( '0x' ) ) {
2112
2023
 
2113
2024
  color = '#' + color.substring( 2 );
@@ -2119,10 +2030,8 @@
2119
2030
  }
2120
2031
 
2121
2032
  break;
2122
-
2123
2033
  case 'EDGE':
2124
2034
  edgeColor = lineParser.getToken();
2125
-
2126
2035
  if ( edgeColor.startsWith( '0x' ) ) {
2127
2036
 
2128
2037
  edgeColor = '#' + edgeColor.substring( 2 );
@@ -2131,23 +2040,20 @@
2131
2040
 
2132
2041
  // Try to see if edge color is a color code
2133
2042
  edgeMaterial = this.getMaterial( edgeColor );
2134
-
2135
2043
  if ( ! edgeMaterial ) {
2136
2044
 
2137
2045
  throw new Error( 'LDrawLoader: Invalid edge color while parsing material' + lineParser.getLineNumberString() + '.' );
2138
2046
 
2139
- } // Get the edge material for this triangle material
2140
-
2047
+ }
2141
2048
 
2049
+ // Get the edge material for this triangle material
2142
2050
  edgeMaterial = edgeMaterial.userData.edgeMaterial;
2143
2051
 
2144
2052
  }
2145
2053
 
2146
2054
  break;
2147
-
2148
2055
  case 'ALPHA':
2149
2056
  alpha = parseInt( lineParser.getToken() );
2150
-
2151
2057
  if ( isNaN( alpha ) ) {
2152
2058
 
2153
2059
  throw new Error( 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + '.' );
@@ -2155,7 +2061,6 @@
2155
2061
  }
2156
2062
 
2157
2063
  alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
2158
-
2159
2064
  if ( alpha < 1 ) {
2160
2065
 
2161
2066
  isTransparent = true;
@@ -2163,7 +2068,6 @@
2163
2068
  }
2164
2069
 
2165
2070
  break;
2166
-
2167
2071
  case 'LUMINANCE':
2168
2072
  if ( ! parseLuminance( lineParser.getToken() ) ) {
2169
2073
 
@@ -2172,32 +2076,25 @@
2172
2076
  }
2173
2077
 
2174
2078
  break;
2175
-
2176
2079
  case 'CHROME':
2177
2080
  finishType = FINISH_TYPE_CHROME;
2178
2081
  break;
2179
-
2180
2082
  case 'PEARLESCENT':
2181
2083
  finishType = FINISH_TYPE_PEARLESCENT;
2182
2084
  break;
2183
-
2184
2085
  case 'RUBBER':
2185
2086
  finishType = FINISH_TYPE_RUBBER;
2186
2087
  break;
2187
-
2188
2088
  case 'MATTE_METALLIC':
2189
2089
  finishType = FINISH_TYPE_MATTE_METALLIC;
2190
2090
  break;
2191
-
2192
2091
  case 'METAL':
2193
2092
  finishType = FINISH_TYPE_METAL;
2194
2093
  break;
2195
-
2196
2094
  case 'MATERIAL':
2197
2095
  // Not implemented
2198
2096
  lineParser.setToEnd();
2199
2097
  break;
2200
-
2201
2098
  default:
2202
2099
  throw new Error( 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + '.' );
2203
2100
 
@@ -2208,7 +2105,6 @@
2208
2105
  }
2209
2106
 
2210
2107
  let material = null;
2211
-
2212
2108
  switch ( finishType ) {
2213
2109
 
2214
2110
  case FINISH_TYPE_DEFAULT:
@@ -2218,7 +2114,6 @@
2218
2114
  metalness: 0
2219
2115
  } );
2220
2116
  break;
2221
-
2222
2117
  case FINISH_TYPE_PEARLESCENT:
2223
2118
  // Try to imitate pearlescency by making the surface glossy
2224
2119
  material = new THREE.MeshStandardMaterial( {
@@ -2227,7 +2122,6 @@
2227
2122
  metalness: 0.25
2228
2123
  } );
2229
2124
  break;
2230
-
2231
2125
  case FINISH_TYPE_CHROME:
2232
2126
  // Mirror finish surface
2233
2127
  material = new THREE.MeshStandardMaterial( {
@@ -2236,7 +2130,6 @@
2236
2130
  metalness: 1
2237
2131
  } );
2238
2132
  break;
2239
-
2240
2133
  case FINISH_TYPE_RUBBER:
2241
2134
  // Rubber finish
2242
2135
  material = new THREE.MeshStandardMaterial( {
@@ -2245,7 +2138,6 @@
2245
2138
  metalness: 0
2246
2139
  } );
2247
2140
  break;
2248
-
2249
2141
  case FINISH_TYPE_MATTE_METALLIC:
2250
2142
  // Brushed metal finish
2251
2143
  material = new THREE.MeshStandardMaterial( {
@@ -2254,7 +2146,6 @@
2254
2146
  metalness: 0.4
2255
2147
  } );
2256
2148
  break;
2257
-
2258
2149
  case FINISH_TYPE_METAL:
2259
2150
  // Average metal finish
2260
2151
  material = new THREE.MeshStandardMaterial( {
@@ -2263,7 +2154,6 @@
2263
2154
  metalness: 0.85
2264
2155
  } );
2265
2156
  break;
2266
-
2267
2157
  default:
2268
2158
  // Should not happen
2269
2159
  break;
@@ -2277,7 +2167,6 @@
2277
2167
  material.color.convertSRGBToLinear();
2278
2168
  material.polygonOffset = true;
2279
2169
  material.polygonOffsetFactor = 1;
2280
-
2281
2170
  if ( luminance !== 0 ) {
2282
2171
 
2283
2172
  material.emissive.set( material.color ).multiplyScalar( luminance );
@@ -2295,8 +2184,9 @@
2295
2184
  } );
2296
2185
  edgeMaterial.userData.code = code;
2297
2186
  edgeMaterial.name = name + ' - Edge';
2298
- edgeMaterial.color.convertSRGBToLinear(); // This is the material used for conditional edges
2187
+ edgeMaterial.color.convertSRGBToLinear();
2299
2188
 
2189
+ // This is the material used for conditional edges
2300
2190
  edgeMaterial.userData.conditionalEdgeMaterial = new LDrawConditionalLineMaterial( {
2301
2191
  fog: true,
2302
2192
  transparent: isTransparent,
@@ -2315,12 +2205,11 @@
2315
2205
  material.userData.edgeMaterial = edgeMaterial;
2316
2206
  this.addMaterial( material );
2317
2207
  return material;
2318
-
2319
2208
  function parseLuminance( token ) {
2320
2209
 
2321
2210
  // Returns success
2322
- let lum;
2323
2211
 
2212
+ let lum;
2324
2213
  if ( token.startsWith( 'LUMINANCE' ) ) {
2325
2214
 
2326
2215
  lum = parseInt( token.substring( 9 ) );
@@ -2343,27 +2232,27 @@
2343
2232
  }
2344
2233
 
2345
2234
  }
2235
+ computeBuildingSteps( model ) {
2346
2236
 
2347
- computeConstructionSteps( model ) {
2237
+ // Sets userdata.buildingStep number in THREE.Group objects and userData.numBuildingSteps number in the root THREE.Group object.
2348
2238
 
2349
- // Sets userdata.constructionStep number in THREE.Group objects and userData.numConstructionSteps number in the root THREE.Group object.
2350
2239
  let stepNumber = 0;
2351
2240
  model.traverse( c => {
2352
2241
 
2353
2242
  if ( c.isGroup ) {
2354
2243
 
2355
- if ( c.userData.startingConstructionStep ) {
2244
+ if ( c.userData.startingBuildingStep ) {
2356
2245
 
2357
2246
  stepNumber ++;
2358
2247
 
2359
2248
  }
2360
2249
 
2361
- c.userData.constructionStep = stepNumber;
2250
+ c.userData.buildingStep = stepNumber;
2362
2251
 
2363
2252
  }
2364
2253
 
2365
2254
  } );
2366
- model.userData.numConstructionSteps = stepNumber + 1;
2255
+ model.userData.numBuildingSteps = stepNumber + 1;
2367
2256
 
2368
2257
  }
2369
2258