@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
@@ -18,7 +18,6 @@
18
18
  let fbxTree;
19
19
  let connections;
20
20
  let sceneGraph;
21
-
22
21
  class FBXLoader extends THREE.Loader {
23
22
 
24
23
  constructor( manager ) {
@@ -26,7 +25,6 @@
26
25
  super( manager );
27
26
 
28
27
  }
29
-
30
28
  load( url, onLoad, onProgress, onError ) {
31
29
 
32
30
  const scope = this;
@@ -61,7 +59,6 @@
61
59
  }, onProgress, onError );
62
60
 
63
61
  }
64
-
65
62
  parse( FBXBuffer, path ) {
66
63
 
67
64
  if ( isFbxFormatBinary( FBXBuffer ) ) {
@@ -71,7 +68,6 @@
71
68
  } else {
72
69
 
73
70
  const FBXText = convertArrayBufferToString( FBXBuffer );
74
-
75
71
  if ( ! isFbxFormatASCII( FBXText ) ) {
76
72
 
77
73
  throw new Error( 'THREE.FBXLoader: Unknown format.' );
@@ -86,17 +82,18 @@
86
82
 
87
83
  fbxTree = new TextParser().parse( FBXText );
88
84
 
89
- } // console.log( fbxTree );
85
+ }
90
86
 
87
+ // console.log( fbxTree );
91
88
 
92
89
  const textureLoader = new THREE.TextureLoader( this.manager ).setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );
93
90
  return new FBXTreeParser( textureLoader, this.manager ).parse( fbxTree );
94
91
 
95
92
  }
96
93
 
97
- } // Parse the FBXTree object returned by the BinaryParser or TextParser and return a THREE.Group
98
-
94
+ }
99
95
 
96
+ // Parse the FBXTree object returned by the BinaryParser or TextParser and return a THREE.Group
100
97
  class FBXTreeParser {
101
98
 
102
99
  constructor( textureLoader, manager ) {
@@ -105,7 +102,6 @@
105
102
  this.manager = manager;
106
103
 
107
104
  }
108
-
109
105
  parse() {
110
106
 
111
107
  connections = this.parseConnections();
@@ -117,14 +113,13 @@
117
113
  this.parseScene( deformers, geometryMap, materials );
118
114
  return sceneGraph;
119
115
 
120
- } // Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )
121
- // and details the connection type
122
-
116
+ }
123
117
 
118
+ // Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )
119
+ // and details the connection type
124
120
  parseConnections() {
125
121
 
126
122
  const connectionMap = new Map();
127
-
128
123
  if ( 'Connections' in fbxTree ) {
129
124
 
130
125
  const rawConnections = fbxTree.Connections.connections;
@@ -133,7 +128,6 @@
133
128
  const fromID = rawConnection[ 0 ];
134
129
  const toID = rawConnection[ 1 ];
135
130
  const relationship = rawConnection[ 2 ];
136
-
137
131
  if ( ! connectionMap.has( fromID ) ) {
138
132
 
139
133
  connectionMap.set( fromID, {
@@ -148,7 +142,6 @@
148
142
  relationship: relationship
149
143
  };
150
144
  connectionMap.get( fromID ).parents.push( parentRelationship );
151
-
152
145
  if ( ! connectionMap.has( toID ) ) {
153
146
 
154
147
  connectionMap.set( toID, {
@@ -170,31 +163,29 @@
170
163
 
171
164
  return connectionMap;
172
165
 
173
- } // Parse FBXTree.Objects.Video for embedded image data
166
+ }
167
+
168
+ // Parse FBXTree.Objects.Video for embedded image data
174
169
  // These images are connected to textures in FBXTree.Objects.Textures
175
170
  // via FBXTree.Connections.
176
-
177
-
178
171
  parseImages() {
179
172
 
180
173
  const images = {};
181
174
  const blobs = {};
182
-
183
175
  if ( 'Video' in fbxTree.Objects ) {
184
176
 
185
177
  const videoNodes = fbxTree.Objects.Video;
186
-
187
178
  for ( const nodeID in videoNodes ) {
188
179
 
189
180
  const videoNode = videoNodes[ nodeID ];
190
181
  const id = parseInt( nodeID );
191
- images[ id ] = videoNode.RelativeFilename || videoNode.Filename; // raw image data is in videoNode.Content
182
+ images[ id ] = videoNode.RelativeFilename || videoNode.Filename;
192
183
 
184
+ // raw image data is in videoNode.Content
193
185
  if ( 'Content' in videoNode ) {
194
186
 
195
187
  const arrayBufferContent = videoNode.Content instanceof ArrayBuffer && videoNode.Content.byteLength > 0;
196
188
  const base64Content = typeof videoNode.Content === 'string' && videoNode.Content !== '';
197
-
198
189
  if ( arrayBufferContent || base64Content ) {
199
190
 
200
191
  const image = this.parseImage( videoNodes[ nodeID ] );
@@ -217,35 +208,30 @@
217
208
 
218
209
  return images;
219
210
 
220
- } // Parse embedded image data in FBXTree.Video.Content
221
-
211
+ }
222
212
 
213
+ // Parse embedded image data in FBXTree.Video.Content
223
214
  parseImage( videoNode ) {
224
215
 
225
216
  const content = videoNode.Content;
226
217
  const fileName = videoNode.RelativeFilename || videoNode.Filename;
227
218
  const extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
228
219
  let type;
229
-
230
220
  switch ( extension ) {
231
221
 
232
222
  case 'bmp':
233
223
  type = 'image/bmp';
234
224
  break;
235
-
236
225
  case 'jpg':
237
226
  case 'jpeg':
238
227
  type = 'image/jpeg';
239
228
  break;
240
-
241
229
  case 'png':
242
230
  type = 'image/png';
243
231
  break;
244
-
245
232
  case 'tif':
246
233
  type = 'image/tiff';
247
234
  break;
248
-
249
235
  case 'tga':
250
236
  if ( this.manager.getHandler( '.tga' ) === null ) {
251
237
 
@@ -255,7 +241,6 @@
255
241
 
256
242
  type = 'image/tga';
257
243
  break;
258
-
259
244
  default:
260
245
  console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
261
246
  return;
@@ -265,11 +250,13 @@
265
250
  if ( typeof content === 'string' ) {
266
251
 
267
252
  // ASCII format
253
+
268
254
  return 'data:' + type + ';base64,' + content;
269
255
 
270
256
  } else {
271
257
 
272
258
  // Binary Format
259
+
273
260
  const array = new Uint8Array( content );
274
261
  return window.URL.createObjectURL( new Blob( [ array ], {
275
262
  type: type
@@ -277,19 +264,17 @@
277
264
 
278
265
  }
279
266
 
280
- } // Parse nodes in FBXTree.Objects.Texture
267
+ }
268
+
269
+ // Parse nodes in FBXTree.Objects.Texture
281
270
  // These contain details such as UV scaling, cropping, rotation etc and are connected
282
271
  // to images in FBXTree.Objects.Video
283
-
284
-
285
272
  parseTextures( images ) {
286
273
 
287
274
  const textureMap = new Map();
288
-
289
275
  if ( 'Texture' in fbxTree.Objects ) {
290
276
 
291
277
  const textureNodes = fbxTree.Objects.Texture;
292
-
293
278
  for ( const nodeID in textureNodes ) {
294
279
 
295
280
  const texture = this.parseTexture( textureNodes[ nodeID ], images );
@@ -301,9 +286,9 @@
301
286
 
302
287
  return textureMap;
303
288
 
304
- } // Parse individual node in FBXTree.Objects.Texture
305
-
289
+ }
306
290
 
291
+ // Parse individual node in FBXTree.Objects.Texture
307
292
  parseTexture( textureNode, images ) {
308
293
 
309
294
  const texture = this.loadTexture( textureNode, images );
@@ -312,12 +297,13 @@
312
297
  const wrapModeU = textureNode.WrapModeU;
313
298
  const wrapModeV = textureNode.WrapModeV;
314
299
  const valueU = wrapModeU !== undefined ? wrapModeU.value : 0;
315
- const valueV = wrapModeV !== undefined ? wrapModeV.value : 0; // http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
300
+ const valueV = wrapModeV !== undefined ? wrapModeV.value : 0;
301
+
302
+ // http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
316
303
  // 0: repeat(default), 1: clamp
317
304
 
318
305
  texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
319
306
  texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
320
-
321
307
  if ( 'Scaling' in textureNode ) {
322
308
 
323
309
  const values = textureNode.Scaling.value;
@@ -336,19 +322,17 @@
336
322
 
337
323
  return texture;
338
324
 
339
- } // load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader
340
-
325
+ }
341
326
 
327
+ // load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader
342
328
  loadTexture( textureNode, images ) {
343
329
 
344
330
  let fileName;
345
331
  const currentPath = this.textureLoader.path;
346
332
  const children = connections.get( textureNode.id ).children;
347
-
348
333
  if ( children !== undefined && children.length > 0 && images[ children[ 0 ].ID ] !== undefined ) {
349
334
 
350
335
  fileName = images[ children[ 0 ].ID ];
351
-
352
336
  if ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {
353
337
 
354
338
  this.textureLoader.setPath( undefined );
@@ -359,11 +343,9 @@
359
343
 
360
344
  let texture;
361
345
  const extension = textureNode.FileName.slice( - 3 ).toLowerCase();
362
-
363
346
  if ( extension === 'tga' ) {
364
347
 
365
348
  const loader = this.manager.getHandler( '.tga' );
366
-
367
349
  if ( loader === null ) {
368
350
 
369
351
  console.warn( 'FBXLoader: TGA loader not found, creating placeholder texture for', textureNode.RelativeFilename );
@@ -390,17 +372,15 @@
390
372
  this.textureLoader.setPath( currentPath );
391
373
  return texture;
392
374
 
393
- } // Parse nodes in FBXTree.Objects.Material
394
-
375
+ }
395
376
 
377
+ // Parse nodes in FBXTree.Objects.Material
396
378
  parseMaterials( textureMap ) {
397
379
 
398
380
  const materialMap = new Map();
399
-
400
381
  if ( 'Material' in fbxTree.Objects ) {
401
382
 
402
383
  const materialNodes = fbxTree.Objects.Material;
403
-
404
384
  for ( const nodeID in materialNodes ) {
405
385
 
406
386
  const material = this.parseMaterial( materialNodes[ nodeID ], textureMap );
@@ -412,38 +392,36 @@
412
392
 
413
393
  return materialMap;
414
394
 
415
- } // Parse single node in FBXTree.Objects.Material
395
+ }
396
+
397
+ // Parse single node in FBXTree.Objects.Material
416
398
  // Materials are connected to texture maps in FBXTree.Objects.Textures
417
399
  // FBX format currently only supports Lambert and Phong shading models
418
-
419
-
420
400
  parseMaterial( materialNode, textureMap ) {
421
401
 
422
402
  const ID = materialNode.id;
423
403
  const name = materialNode.attrName;
424
- let type = materialNode.ShadingModel; // Case where FBX wraps shading model in property object.
404
+ let type = materialNode.ShadingModel;
425
405
 
406
+ // Case where FBX wraps shading model in property object.
426
407
  if ( typeof type === 'object' ) {
427
408
 
428
409
  type = type.value;
429
410
 
430
- } // Ignore unused materials which don't have any connections.
431
-
411
+ }
432
412
 
413
+ // Ignore unused materials which don't have any connections.
433
414
  if ( ! connections.has( ID ) ) return null;
434
415
  const parameters = this.parseParameters( materialNode, textureMap, ID );
435
416
  let material;
436
-
437
417
  switch ( type.toLowerCase() ) {
438
418
 
439
419
  case 'phong':
440
420
  material = new THREE.MeshPhongMaterial();
441
421
  break;
442
-
443
422
  case 'lambert':
444
423
  material = new THREE.MeshLambertMaterial();
445
424
  break;
446
-
447
425
  default:
448
426
  console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to THREE.MeshPhongMaterial.', type );
449
427
  material = new THREE.MeshPhongMaterial();
@@ -455,14 +433,13 @@
455
433
  material.name = name;
456
434
  return material;
457
435
 
458
- } // Parse FBX material and return parameters suitable for a three.js material
459
- // Also parse the texture map and return any textures associated with the material
460
-
436
+ }
461
437
 
438
+ // Parse FBX material and return parameters suitable for a three.js material
439
+ // Also parse the texture map and return any textures associated with the material
462
440
  parseParameters( materialNode, textureMap, ID ) {
463
441
 
464
442
  const parameters = {};
465
-
466
443
  if ( materialNode.BumpFactor ) {
467
444
 
468
445
  parameters.bumpScale = materialNode.BumpFactor.value;
@@ -542,21 +519,17 @@
542
519
  connections.get( ID ).children.forEach( function ( child ) {
543
520
 
544
521
  const type = child.relationship;
545
-
546
522
  switch ( type ) {
547
523
 
548
524
  case 'Bump':
549
525
  parameters.bumpMap = scope.getTexture( textureMap, child.ID );
550
526
  break;
551
-
552
527
  case 'Maya|TEX_ao_map':
553
528
  parameters.aoMap = scope.getTexture( textureMap, child.ID );
554
529
  break;
555
-
556
530
  case 'DiffuseColor':
557
531
  case 'Maya|TEX_color_map':
558
532
  parameters.map = scope.getTexture( textureMap, child.ID );
559
-
560
533
  if ( parameters.map !== undefined ) {
561
534
 
562
535
  parameters.map.encoding = THREE.sRGBEncoding;
@@ -564,14 +537,11 @@
564
537
  }
565
538
 
566
539
  break;
567
-
568
540
  case 'DisplacementColor':
569
541
  parameters.displacementMap = scope.getTexture( textureMap, child.ID );
570
542
  break;
571
-
572
543
  case 'EmissiveColor':
573
544
  parameters.emissiveMap = scope.getTexture( textureMap, child.ID );
574
-
575
545
  if ( parameters.emissiveMap !== undefined ) {
576
546
 
577
547
  parameters.emissiveMap.encoding = THREE.sRGBEncoding;
@@ -579,15 +549,12 @@
579
549
  }
580
550
 
581
551
  break;
582
-
583
552
  case 'NormalMap':
584
553
  case 'Maya|TEX_normal_map':
585
554
  parameters.normalMap = scope.getTexture( textureMap, child.ID );
586
555
  break;
587
-
588
556
  case 'ReflectionColor':
589
557
  parameters.envMap = scope.getTexture( textureMap, child.ID );
590
-
591
558
  if ( parameters.envMap !== undefined ) {
592
559
 
593
560
  parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
@@ -596,10 +563,8 @@
596
563
  }
597
564
 
598
565
  break;
599
-
600
566
  case 'SpecularColor':
601
567
  parameters.specularMap = scope.getTexture( textureMap, child.ID );
602
-
603
568
  if ( parameters.specularMap !== undefined ) {
604
569
 
605
570
  parameters.specularMap.encoding = THREE.sRGBEncoding;
@@ -607,20 +572,15 @@
607
572
  }
608
573
 
609
574
  break;
610
-
611
575
  case 'TransparentColor':
612
576
  case 'TransparencyFactor':
613
577
  parameters.alphaMap = scope.getTexture( textureMap, child.ID );
614
578
  parameters.transparent = true;
615
579
  break;
616
-
617
580
  case 'AmbientColor':
618
581
  case 'ShininessExponent': // AKA glossiness map
619
-
620
582
  case 'SpecularFactor': // AKA specularLevel
621
-
622
583
  case 'VectorDisplacementColor': // NOTE: Seems to be a copy of DisplacementColor
623
-
624
584
  default:
625
585
  console.warn( 'THREE.FBXLoader: %s map is not supported in three.js, skipping texture.', type );
626
586
  break;
@@ -630,9 +590,9 @@
630
590
  } );
631
591
  return parameters;
632
592
 
633
- } // get a texture from the textureMap for use by a material.
634
-
593
+ }
635
594
 
595
+ // get a texture from the textureMap for use by a material.
636
596
  getTexture( textureMap, id ) {
637
597
 
638
598
  // if the texture is a layered texture, just use the first layer and issue a warning
@@ -645,25 +605,22 @@
645
605
 
646
606
  return textureMap.get( id );
647
607
 
648
- } // Parse nodes in FBXTree.Objects.Deformer
608
+ }
609
+
610
+ // Parse nodes in FBXTree.Objects.Deformer
649
611
  // Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here
650
612
  // Generates map of THREE.Skeleton-like objects for use later when generating and binding skeletons.
651
-
652
-
653
613
  parseDeformers() {
654
614
 
655
615
  const skeletons = {};
656
616
  const morphTargets = {};
657
-
658
617
  if ( 'Deformer' in fbxTree.Objects ) {
659
618
 
660
619
  const DeformerNodes = fbxTree.Objects.Deformer;
661
-
662
620
  for ( const nodeID in DeformerNodes ) {
663
621
 
664
622
  const deformerNode = DeformerNodes[ nodeID ];
665
623
  const relationships = connections.get( parseInt( nodeID ) );
666
-
667
624
  if ( deformerNode.attrType === 'Skin' ) {
668
625
 
669
626
  const skeleton = this.parseSkeleton( relationships, DeformerNodes );
@@ -693,11 +650,11 @@
693
650
  morphTargets: morphTargets
694
651
  };
695
652
 
696
- } // Parse single nodes in FBXTree.Objects.Deformer
653
+ }
654
+
655
+ // Parse single nodes in FBXTree.Objects.Deformer
697
656
  // The top level skeleton node has type 'Skin' and sub nodes have type 'Cluster'
698
657
  // Each skin node represents a skeleton and each cluster node represents a bone
699
-
700
-
701
658
  parseSkeleton( relationships, deformerNodes ) {
702
659
 
703
660
  const rawBones = [];
@@ -709,9 +666,9 @@
709
666
  ID: child.ID,
710
667
  indices: [],
711
668
  weights: [],
712
- transformLink: new THREE.Matrix4().fromArray( boneNode.TransformLink.a ) // transform: new THREE.Matrix4().fromArray( boneNode.Transform.a ),
669
+ transformLink: new THREE.Matrix4().fromArray( boneNode.TransformLink.a )
670
+ // transform: new THREE.Matrix4().fromArray( boneNode.Transform.a ),
713
671
  // linkMode: boneNode.Mode,
714
-
715
672
  };
716
673
 
717
674
  if ( 'Indexes' in boneNode ) {
@@ -729,13 +686,12 @@
729
686
  bones: []
730
687
  };
731
688
 
732
- } // The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel"
733
-
689
+ }
734
690
 
691
+ // The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel"
735
692
  parseMorphTargets( relationships, deformerNodes ) {
736
693
 
737
694
  const rawMorphTargets = [];
738
-
739
695
  for ( let i = 0; i < relationships.children.length; i ++ ) {
740
696
 
741
697
  const child = relationships.children[ i ];
@@ -758,9 +714,9 @@
758
714
 
759
715
  return rawMorphTargets;
760
716
 
761
- } // create the main THREE.Group() to be returned by the loader
762
-
717
+ }
763
718
 
719
+ // create the main THREE.Group() to be returned by the loader
764
720
  parseScene( deformers, geometryMap, materialMap ) {
765
721
 
766
722
  sceneGraph = new THREE.Group();
@@ -778,7 +734,6 @@
778
734
  if ( parent !== undefined ) parent.add( model );
779
735
 
780
736
  } );
781
-
782
737
  if ( model.parent === null ) {
783
738
 
784
739
  sceneGraph.add( model );
@@ -806,8 +761,9 @@
806
761
  }
807
762
 
808
763
  } );
809
- const animations = new AnimationParser().parse(); // if all the models where already combined in a single group, just return that
764
+ const animations = new AnimationParser().parse();
810
765
 
766
+ // if all the models where already combined in a single group, just return that
811
767
  if ( sceneGraph.children.length === 1 && sceneGraph.children[ 0 ].isGroup ) {
812
768
 
813
769
  sceneGraph.children[ 0 ].animations = animations;
@@ -817,21 +773,19 @@
817
773
 
818
774
  sceneGraph.animations = animations;
819
775
 
820
- } // parse nodes in FBXTree.Objects.Model
821
-
776
+ }
822
777
 
778
+ // parse nodes in FBXTree.Objects.Model
823
779
  parseModels( skeletons, geometryMap, materialMap ) {
824
780
 
825
781
  const modelMap = new Map();
826
782
  const modelNodes = fbxTree.Objects.Model;
827
-
828
783
  for ( const nodeID in modelNodes ) {
829
784
 
830
785
  const id = parseInt( nodeID );
831
786
  const node = modelNodes[ nodeID ];
832
787
  const relationships = connections.get( id );
833
788
  let model = this.buildSkeleton( relationships, skeletons, id, node.attrName );
834
-
835
789
  if ( ! model ) {
836
790
 
837
791
  switch ( node.attrType ) {
@@ -839,24 +793,19 @@
839
793
  case 'Camera':
840
794
  model = this.createCamera( relationships );
841
795
  break;
842
-
843
796
  case 'Light':
844
797
  model = this.createLight( relationships );
845
798
  break;
846
-
847
799
  case 'Mesh':
848
800
  model = this.createMesh( relationships, geometryMap, materialMap );
849
801
  break;
850
-
851
802
  case 'NurbsCurve':
852
803
  model = this.createCurve( relationships, geometryMap );
853
804
  break;
854
-
855
805
  case 'LimbNode':
856
806
  case 'Root':
857
807
  model = new THREE.Bone();
858
808
  break;
859
-
860
809
  case 'Null':
861
810
  default:
862
811
  model = new THREE.Group();
@@ -877,7 +826,6 @@
877
826
  return modelMap;
878
827
 
879
828
  }
880
-
881
829
  buildSkeleton( relationships, skeletons, id, name ) {
882
830
 
883
831
  let bone = null;
@@ -892,13 +840,16 @@
892
840
 
893
841
  const subBone = bone;
894
842
  bone = new THREE.Bone();
895
- bone.matrixWorld.copy( rawBone.transformLink ); // set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
843
+ bone.matrixWorld.copy( rawBone.transformLink );
844
+
845
+ // set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
896
846
 
897
847
  bone.name = name ? THREE.PropertyBinding.sanitizeNodeName( name ) : '';
898
848
  bone.ID = id;
899
- skeleton.bones[ i ] = bone; // In cases where a bone is shared between multiple meshes
900
- // duplicate the bone here and and it as a child of the first bone
849
+ skeleton.bones[ i ] = bone;
901
850
 
851
+ // In cases where a bone is shared between multiple meshes
852
+ // duplicate the bone here and and it as a child of the first bone
902
853
  if ( subBone !== null ) {
903
854
 
904
855
  bone.add( subBone );
@@ -914,9 +865,9 @@
914
865
  } );
915
866
  return bone;
916
867
 
917
- } // create a THREE.PerspectiveCamera or THREE.OrthographicCamera
918
-
868
+ }
919
869
 
870
+ // create a THREE.PerspectiveCamera or THREE.OrthographicCamera
920
871
  createCamera( relationships ) {
921
872
 
922
873
  let model;
@@ -924,7 +875,6 @@
924
875
  relationships.children.forEach( function ( child ) {
925
876
 
926
877
  const attr = fbxTree.Objects.NodeAttribute[ child.ID ];
927
-
928
878
  if ( attr !== undefined ) {
929
879
 
930
880
  cameraAttribute = attr;
@@ -932,7 +882,6 @@
932
882
  }
933
883
 
934
884
  } );
935
-
936
885
  if ( cameraAttribute === undefined ) {
937
886
 
938
887
  model = new THREE.Object3D();
@@ -940,7 +889,6 @@
940
889
  } else {
941
890
 
942
891
  let type = 0;
943
-
944
892
  if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) {
945
893
 
946
894
  type = 1;
@@ -948,7 +896,6 @@
948
896
  }
949
897
 
950
898
  let nearClippingPlane = 1;
951
-
952
899
  if ( cameraAttribute.NearPlane !== undefined ) {
953
900
 
954
901
  nearClippingPlane = cameraAttribute.NearPlane.value / 1000;
@@ -956,7 +903,6 @@
956
903
  }
957
904
 
958
905
  let farClippingPlane = 1000;
959
-
960
906
  if ( cameraAttribute.FarPlane !== undefined ) {
961
907
 
962
908
  farClippingPlane = cameraAttribute.FarPlane.value / 1000;
@@ -965,7 +911,6 @@
965
911
 
966
912
  let width = window.innerWidth;
967
913
  let height = window.innerHeight;
968
-
969
914
  if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {
970
915
 
971
916
  width = cameraAttribute.AspectWidth.value;
@@ -975,7 +920,6 @@
975
920
 
976
921
  const aspect = width / height;
977
922
  let fov = 45;
978
-
979
923
  if ( cameraAttribute.FieldOfView !== undefined ) {
980
924
 
981
925
  fov = cameraAttribute.FieldOfView.value;
@@ -983,7 +927,6 @@
983
927
  }
984
928
 
985
929
  const focalLength = cameraAttribute.FocalLength ? cameraAttribute.FocalLength.value : null;
986
-
987
930
  switch ( type ) {
988
931
 
989
932
  case 0:
@@ -991,12 +934,10 @@
991
934
  model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );
992
935
  if ( focalLength !== null ) model.setFocalLength( focalLength );
993
936
  break;
994
-
995
937
  case 1:
996
938
  // Orthographic
997
939
  model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
998
940
  break;
999
-
1000
941
  default:
1001
942
  console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );
1002
943
  model = new THREE.Object3D();
@@ -1008,9 +949,9 @@
1008
949
 
1009
950
  return model;
1010
951
 
1011
- } // Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight
1012
-
952
+ }
1013
953
 
954
+ // Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight
1014
955
  createLight( relationships ) {
1015
956
 
1016
957
  let model;
@@ -1018,7 +959,6 @@
1018
959
  relationships.children.forEach( function ( child ) {
1019
960
 
1020
961
  const attr = fbxTree.Objects.NodeAttribute[ child.ID ];
1021
-
1022
962
  if ( attr !== undefined ) {
1023
963
 
1024
964
  lightAttribute = attr;
@@ -1026,15 +966,15 @@
1026
966
  }
1027
967
 
1028
968
  } );
1029
-
1030
969
  if ( lightAttribute === undefined ) {
1031
970
 
1032
971
  model = new THREE.Object3D();
1033
972
 
1034
973
  } else {
1035
974
 
1036
- let type; // LightType can be undefined for Point lights
975
+ let type;
1037
976
 
977
+ // LightType can be undefined for Point lights
1038
978
  if ( lightAttribute.LightType === undefined ) {
1039
979
 
1040
980
  type = 0;
@@ -1046,15 +986,15 @@
1046
986
  }
1047
987
 
1048
988
  let color = 0xffffff;
1049
-
1050
989
  if ( lightAttribute.Color !== undefined ) {
1051
990
 
1052
991
  color = new THREE.Color().fromArray( lightAttribute.Color.value );
1053
992
 
1054
993
  }
1055
994
 
1056
- let intensity = lightAttribute.Intensity === undefined ? 1 : lightAttribute.Intensity.value / 100; // light disabled
995
+ let intensity = lightAttribute.Intensity === undefined ? 1 : lightAttribute.Intensity.value / 100;
1057
996
 
997
+ // light disabled
1058
998
  if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) {
1059
999
 
1060
1000
  intensity = 0;
@@ -1062,7 +1002,6 @@
1062
1002
  }
1063
1003
 
1064
1004
  let distance = 0;
1065
-
1066
1005
  if ( lightAttribute.FarAttenuationEnd !== undefined ) {
1067
1006
 
1068
1007
  if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) {
@@ -1075,27 +1014,23 @@
1075
1014
 
1076
1015
  }
1077
1016
 
1078
- } // TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?
1079
-
1017
+ }
1080
1018
 
1019
+ // TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?
1081
1020
  const decay = 1;
1082
-
1083
1021
  switch ( type ) {
1084
1022
 
1085
1023
  case 0:
1086
1024
  // Point
1087
1025
  model = new THREE.PointLight( color, intensity, distance, decay );
1088
1026
  break;
1089
-
1090
1027
  case 1:
1091
1028
  // Directional
1092
1029
  model = new THREE.DirectionalLight( color, intensity );
1093
1030
  break;
1094
-
1095
1031
  case 2:
1096
1032
  // Spot
1097
1033
  let angle = Math.PI / 3;
1098
-
1099
1034
  if ( lightAttribute.InnerAngle !== undefined ) {
1100
1035
 
1101
1036
  angle = THREE.MathUtils.degToRad( lightAttribute.InnerAngle.value );
@@ -1103,7 +1038,6 @@
1103
1038
  }
1104
1039
 
1105
1040
  let penumbra = 0;
1106
-
1107
1041
  if ( lightAttribute.OuterAngle !== undefined ) {
1108
1042
 
1109
1043
  // TODO: this is not correct - FBX calculates outer and inner angle in degrees
@@ -1116,7 +1050,6 @@
1116
1050
 
1117
1051
  model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay );
1118
1052
  break;
1119
-
1120
1053
  default:
1121
1054
  console.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a THREE.PointLight.' );
1122
1055
  model = new THREE.PointLight( color, intensity );
@@ -1135,14 +1068,14 @@
1135
1068
  return model;
1136
1069
 
1137
1070
  }
1138
-
1139
1071
  createMesh( relationships, geometryMap, materialMap ) {
1140
1072
 
1141
1073
  let model;
1142
1074
  let geometry = null;
1143
1075
  let material = null;
1144
- const materials = []; // get geometry and materials(s) from connections
1076
+ const materials = [];
1145
1077
 
1078
+ // get geometry and materials(s) from connections
1146
1079
  relationships.children.forEach( function ( child ) {
1147
1080
 
1148
1081
  if ( geometryMap.has( child.ID ) ) {
@@ -1158,7 +1091,6 @@
1158
1091
  }
1159
1092
 
1160
1093
  } );
1161
-
1162
1094
  if ( materials.length > 1 ) {
1163
1095
 
1164
1096
  material = materials;
@@ -1200,7 +1132,6 @@
1200
1132
  return model;
1201
1133
 
1202
1134
  }
1203
-
1204
1135
  createCurve( relationships, geometryMap ) {
1205
1136
 
1206
1137
  const geometry = relationships.children.reduce( function ( geo, child ) {
@@ -1208,17 +1139,18 @@
1208
1139
  if ( geometryMap.has( child.ID ) ) geo = geometryMap.get( child.ID );
1209
1140
  return geo;
1210
1141
 
1211
- }, null ); // FBX does not list materials for Nurbs lines, so we'll just put our own in here.
1142
+ }, null );
1212
1143
 
1144
+ // FBX does not list materials for Nurbs lines, so we'll just put our own in here.
1213
1145
  const material = new THREE.LineBasicMaterial( {
1214
1146
  color: 0x3300ff,
1215
1147
  linewidth: 1
1216
1148
  } );
1217
1149
  return new THREE.Line( geometry, material );
1218
1150
 
1219
- } // parse the model node for transform data
1220
-
1151
+ }
1221
1152
 
1153
+ // parse the model node for transform data
1222
1154
  getTransformData( model, modelNode ) {
1223
1155
 
1224
1156
  const transformData = {};
@@ -1236,7 +1168,6 @@
1236
1168
  model.userData.transformData = transformData;
1237
1169
 
1238
1170
  }
1239
-
1240
1171
  setLookAtProperties( model, modelNode ) {
1241
1172
 
1242
1173
  if ( 'LookAtProperty' in modelNode ) {
@@ -1247,11 +1178,11 @@
1247
1178
  if ( child.relationship === 'LookAtProperty' ) {
1248
1179
 
1249
1180
  const lookAtTarget = fbxTree.Objects.Model[ child.ID ];
1250
-
1251
1181
  if ( 'Lcl_Translation' in lookAtTarget ) {
1252
1182
 
1253
- const pos = lookAtTarget.Lcl_Translation.value; // THREE.DirectionalLight, THREE.SpotLight
1183
+ const pos = lookAtTarget.Lcl_Translation.value;
1254
1184
 
1185
+ // THREE.DirectionalLight, THREE.SpotLight
1255
1186
  if ( model.target !== undefined ) {
1256
1187
 
1257
1188
  model.target.position.fromArray( pos );
@@ -1260,6 +1191,7 @@
1260
1191
  } else {
1261
1192
 
1262
1193
  // Cameras and other Object3Ds
1194
+
1263
1195
  model.lookAt( new THREE.Vector3().fromArray( pos ) );
1264
1196
 
1265
1197
  }
@@ -1273,11 +1205,9 @@
1273
1205
  }
1274
1206
 
1275
1207
  }
1276
-
1277
1208
  bindSkeleton( skeletons, geometryMap, modelMap ) {
1278
1209
 
1279
1210
  const bindMatrices = this.parsePoseNodes();
1280
-
1281
1211
  for ( const ID in skeletons ) {
1282
1212
 
1283
1213
  const skeleton = skeletons[ ID ];
@@ -1306,21 +1236,17 @@
1306
1236
  }
1307
1237
 
1308
1238
  }
1309
-
1310
1239
  parsePoseNodes() {
1311
1240
 
1312
1241
  const bindMatrices = {};
1313
-
1314
1242
  if ( 'Pose' in fbxTree.Objects ) {
1315
1243
 
1316
1244
  const BindPoseNode = fbxTree.Objects.Pose;
1317
-
1318
1245
  for ( const nodeID in BindPoseNode ) {
1319
1246
 
1320
1247
  if ( BindPoseNode[ nodeID ].attrType === 'BindPose' && BindPoseNode[ nodeID ].NbPoseNodes > 0 ) {
1321
1248
 
1322
1249
  const poseNodes = BindPoseNode[ nodeID ].PoseNode;
1323
-
1324
1250
  if ( Array.isArray( poseNodes ) ) {
1325
1251
 
1326
1252
  poseNodes.forEach( function ( poseNode ) {
@@ -1343,9 +1269,9 @@
1343
1269
 
1344
1270
  return bindMatrices;
1345
1271
 
1346
- } // Parse ambient color in FBXTree.GlobalSettings - if it's not set to black (default), create an ambient light
1347
-
1272
+ }
1348
1273
 
1274
+ // Parse ambient color in FBXTree.GlobalSettings - if it's not set to black (default), create an ambient light
1349
1275
  createAmbientLight() {
1350
1276
 
1351
1277
  if ( 'GlobalSettings' in fbxTree && 'AmbientColor' in fbxTree.GlobalSettings ) {
@@ -1354,7 +1280,6 @@
1354
1280
  const r = ambientColor[ 0 ];
1355
1281
  const g = ambientColor[ 1 ];
1356
1282
  const b = ambientColor[ 2 ];
1357
-
1358
1283
  if ( r !== 0 || g !== 0 || b !== 0 ) {
1359
1284
 
1360
1285
  const color = new THREE.Color( r, g, b );
@@ -1366,20 +1291,24 @@
1366
1291
 
1367
1292
  }
1368
1293
 
1369
- } // parse Geometry data from FBXTree and return map of BufferGeometries
1370
-
1294
+ }
1371
1295
 
1296
+ // parse Geometry data from FBXTree and return map of BufferGeometries
1372
1297
  class GeometryParser {
1373
1298
 
1299
+ constructor() {
1300
+
1301
+ this.negativeMaterialIndices = false;
1302
+
1303
+ }
1304
+
1374
1305
  // Parse nodes in FBXTree.Objects.Geometry
1375
1306
  parse( deformers ) {
1376
1307
 
1377
1308
  const geometryMap = new Map();
1378
-
1379
1309
  if ( 'Geometry' in fbxTree.Objects ) {
1380
1310
 
1381
1311
  const geoNodes = fbxTree.Objects.Geometry;
1382
-
1383
1312
  for ( const nodeID in geoNodes ) {
1384
1313
 
1385
1314
  const relationships = connections.get( parseInt( nodeID ) );
@@ -1390,11 +1319,19 @@
1390
1319
 
1391
1320
  }
1392
1321
 
1393
- return geometryMap;
1322
+ // report warnings
1323
+
1324
+ if ( this.negativeMaterialIndices === true ) {
1325
+
1326
+ console.warn( 'THREE.FBXLoader: The FBX file contains invalid (negative) material indices. The asset might not render as expected.' );
1327
+
1328
+ }
1394
1329
 
1395
- } // Parse single node in FBXTree.Objects.Geometry
1330
+ return geometryMap;
1396
1331
 
1332
+ }
1397
1333
 
1334
+ // Parse single node in FBXTree.Objects.Geometry
1398
1335
  parseGeometry( relationships, geoNode, deformers ) {
1399
1336
 
1400
1337
  switch ( geoNode.attrType ) {
@@ -1402,16 +1339,15 @@
1402
1339
  case 'Mesh':
1403
1340
  return this.parseMeshGeometry( relationships, geoNode, deformers );
1404
1341
  break;
1405
-
1406
1342
  case 'NurbsCurve':
1407
1343
  return this.parseNurbsGeometry( geoNode );
1408
1344
  break;
1409
1345
 
1410
1346
  }
1411
1347
 
1412
- } // Parse single node mesh geometry in FBXTree.Objects.Geometry
1413
-
1348
+ }
1414
1349
 
1350
+ // Parse single node mesh geometry in FBXTree.Objects.Geometry
1415
1351
  parseMeshGeometry( relationships, geoNode, deformers ) {
1416
1352
 
1417
1353
  const skeletons = deformers.skeletons;
@@ -1420,8 +1356,9 @@
1420
1356
 
1421
1357
  return fbxTree.Objects.Model[ parent.ID ];
1422
1358
 
1423
- } ); // don't create geometry if it is not associated with any models
1359
+ } );
1424
1360
 
1361
+ // don't create geometry if it is not associated with any models
1425
1362
  if ( modelNodes.length === 0 ) return;
1426
1363
  const skeleton = relationships.children.reduce( function ( skeleton, child ) {
1427
1364
 
@@ -1437,9 +1374,10 @@
1437
1374
 
1438
1375
  }
1439
1376
 
1440
- } ); // Assume one model and get the preRotation from that
1441
- // if there is more than one model associated with the geometry this may cause problems
1377
+ } );
1442
1378
 
1379
+ // Assume one model and get the preRotation from that
1380
+ // if there is more than one model associated with the geometry this may cause problems
1443
1381
  const modelNode = modelNodes[ 0 ];
1444
1382
  const transformData = {};
1445
1383
  if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );
@@ -1450,9 +1388,9 @@
1450
1388
  const transform = generateTransform( transformData );
1451
1389
  return this.genGeometry( geoNode, skeleton, morphTargets, transform );
1452
1390
 
1453
- } // Generate a THREE.BufferGeometry from a node in FBXTree.Objects.Geometry
1454
-
1391
+ }
1455
1392
 
1393
+ // Generate a THREE.BufferGeometry from a node in FBXTree.Objects.Geometry
1456
1394
  genGeometry( geoNode, skeleton, morphTargets, preTransform ) {
1457
1395
 
1458
1396
  const geo = new THREE.BufferGeometry();
@@ -1462,7 +1400,6 @@
1462
1400
  const positionAttribute = new THREE.Float32BufferAttribute( buffers.vertex, 3 );
1463
1401
  positionAttribute.applyMatrix4( preTransform );
1464
1402
  geo.setAttribute( 'position', positionAttribute );
1465
-
1466
1403
  if ( buffers.colors.length > 0 ) {
1467
1404
 
1468
1405
  geo.setAttribute( 'color', new THREE.Float32BufferAttribute( buffers.colors, 3 ) );
@@ -1472,8 +1409,9 @@
1472
1409
  if ( skeleton ) {
1473
1410
 
1474
1411
  geo.setAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( buffers.weightsIndices, 4 ) );
1475
- geo.setAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffers.vertexWeights, 4 ) ); // used later to bind the skeleton to the model
1412
+ geo.setAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffers.vertexWeights, 4 ) );
1476
1413
 
1414
+ // used later to bind the skeleton to the model
1477
1415
  geo.FBX_Deformer = skeleton;
1478
1416
 
1479
1417
  }
@@ -1490,8 +1428,9 @@
1490
1428
  buffers.uvs.forEach( function ( uvBuffer, i ) {
1491
1429
 
1492
1430
  // subsequent uv buffers are called 'uv1', 'uv2', ...
1493
- let name = 'uv' + ( i + 1 ).toString(); // the first uv buffer is just called 'uv'
1431
+ let name = 'uv' + ( i + 1 ).toString();
1494
1432
 
1433
+ // the first uv buffer is just called 'uv'
1495
1434
  if ( i === 0 ) {
1496
1435
 
1497
1436
  name = 'uv';
@@ -1501,7 +1440,6 @@
1501
1440
  geo.setAttribute( name, new THREE.Float32BufferAttribute( buffers.uvs[ i ], 2 ) );
1502
1441
 
1503
1442
  } );
1504
-
1505
1443
  if ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {
1506
1444
 
1507
1445
  // Convert the material indices of each vertex into rendering groups on the geometry.
@@ -1517,23 +1455,23 @@
1517
1455
 
1518
1456
  }
1519
1457
 
1520
- } ); // the loop above doesn't add the last group, do that here.
1458
+ } );
1521
1459
 
1460
+ // the loop above doesn't add the last group, do that here.
1522
1461
  if ( geo.groups.length > 0 ) {
1523
1462
 
1524
1463
  const lastGroup = geo.groups[ geo.groups.length - 1 ];
1525
1464
  const lastIndex = lastGroup.start + lastGroup.count;
1526
-
1527
1465
  if ( lastIndex !== buffers.materialIndex.length ) {
1528
1466
 
1529
1467
  geo.addGroup( lastIndex, buffers.materialIndex.length - lastIndex, prevMaterialIndex );
1530
1468
 
1531
1469
  }
1532
1470
 
1533
- } // case where there are multiple materials but the whole geometry is only
1534
- // using one of them
1535
-
1471
+ }
1536
1472
 
1473
+ // case where there are multiple materials but the whole geometry is only
1474
+ // using one of them
1537
1475
  if ( geo.groups.length === 0 ) {
1538
1476
 
1539
1477
  geo.addGroup( 0, buffers.materialIndex.length, buffers.materialIndex[ 0 ] );
@@ -1546,13 +1484,11 @@
1546
1484
  return geo;
1547
1485
 
1548
1486
  }
1549
-
1550
1487
  parseGeoNode( geoNode, skeleton ) {
1551
1488
 
1552
1489
  const geoInfo = {};
1553
1490
  geoInfo.vertexPositions = geoNode.Vertices !== undefined ? geoNode.Vertices.a : [];
1554
1491
  geoInfo.vertexIndices = geoNode.PolygonVertexIndex !== undefined ? geoNode.PolygonVertexIndex.a : [];
1555
-
1556
1492
  if ( geoNode.LayerElementColor ) {
1557
1493
 
1558
1494
  geoInfo.color = this.parseVertexColors( geoNode.LayerElementColor[ 0 ] );
@@ -1575,7 +1511,6 @@
1575
1511
 
1576
1512
  geoInfo.uv = [];
1577
1513
  let i = 0;
1578
-
1579
1514
  while ( geoNode.LayerElementUV[ i ] ) {
1580
1515
 
1581
1516
  if ( geoNode.LayerElementUV[ i ].UV ) {
@@ -1591,7 +1526,6 @@
1591
1526
  }
1592
1527
 
1593
1528
  geoInfo.weightTable = {};
1594
-
1595
1529
  if ( skeleton !== null ) {
1596
1530
 
1597
1531
  geoInfo.skeleton = skeleton;
@@ -1615,7 +1549,6 @@
1615
1549
  return geoInfo;
1616
1550
 
1617
1551
  }
1618
-
1619
1552
  genBuffers( geoInfo ) {
1620
1553
 
1621
1554
  const buffers = {
@@ -1629,8 +1562,9 @@
1629
1562
  };
1630
1563
  let polygonIndex = 0;
1631
1564
  let faceLength = 0;
1632
- let displayedWeightsWarning = false; // these will hold data for a single face
1565
+ let displayedWeightsWarning = false;
1633
1566
 
1567
+ // these will hold data for a single face
1634
1568
  let facePositionIndexes = [];
1635
1569
  let faceNormals = [];
1636
1570
  let faceColors = [];
@@ -1641,18 +1575,18 @@
1641
1575
  geoInfo.vertexIndices.forEach( function ( vertexIndex, polygonVertexIndex ) {
1642
1576
 
1643
1577
  let materialIndex;
1644
- let endOfFace = false; // Face index and vertex index arrays are combined in a single array
1578
+ let endOfFace = false;
1579
+
1580
+ // Face index and vertex index arrays are combined in a single array
1645
1581
  // A cube with quad faces looks like this:
1646
1582
  // PolygonVertexIndex: *24 {
1647
1583
  // a: 0, 1, 3, -3, 2, 3, 5, -5, 4, 5, 7, -7, 6, 7, 1, -1, 1, 7, 5, -4, 6, 0, 2, -5
1648
1584
  // }
1649
1585
  // Negative numbers mark the end of a face - first face here is 0, 1, 3, -3
1650
1586
  // to find index of last vertex bit shift the index: ^ - 1
1651
-
1652
1587
  if ( vertexIndex < 0 ) {
1653
1588
 
1654
1589
  vertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1
1655
-
1656
1590
  endOfFace = true;
1657
1591
 
1658
1592
  }
@@ -1660,7 +1594,6 @@
1660
1594
  let weightIndices = [];
1661
1595
  let weights = [];
1662
1596
  facePositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );
1663
-
1664
1597
  if ( geoInfo.color ) {
1665
1598
 
1666
1599
  const data = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.color );
@@ -1714,9 +1647,9 @@
1714
1647
  weightIndices = wIndex;
1715
1648
  weights = Weight;
1716
1649
 
1717
- } // if the weight array is shorter than 4 pad with 0s
1718
-
1650
+ }
1719
1651
 
1652
+ // if the weight array is shorter than 4 pad with 0s
1720
1653
  while ( weights.length < 4 ) {
1721
1654
 
1722
1655
  weights.push( 0 );
@@ -1743,11 +1676,10 @@
1743
1676
  if ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {
1744
1677
 
1745
1678
  materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.material )[ 0 ];
1746
-
1747
1679
  if ( materialIndex < 0 ) {
1748
1680
 
1749
- console.warn( 'THREE.FBXLoader: Invalid material index:', materialIndex );
1750
- materialIndex = 0;
1681
+ scope.negativeMaterialIndices = true;
1682
+ materialIndex = 0; // fallback
1751
1683
 
1752
1684
  }
1753
1685
 
@@ -1758,7 +1690,6 @@
1758
1690
  geoInfo.uv.forEach( function ( uv, i ) {
1759
1691
 
1760
1692
  const data = getData( polygonVertexIndex, polygonIndex, vertexIndex, uv );
1761
-
1762
1693
  if ( faceUVs[ i ] === undefined ) {
1763
1694
 
1764
1695
  faceUVs[ i ] = [];
@@ -1773,13 +1704,13 @@
1773
1704
  }
1774
1705
 
1775
1706
  faceLength ++;
1776
-
1777
1707
  if ( endOfFace ) {
1778
1708
 
1779
1709
  scope.genFace( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength );
1780
1710
  polygonIndex ++;
1781
- faceLength = 0; // reset arrays for the next face
1711
+ faceLength = 0;
1782
1712
 
1713
+ // reset arrays for the next face
1783
1714
  facePositionIndexes = [];
1784
1715
  faceNormals = [];
1785
1716
  faceColors = [];
@@ -1792,9 +1723,9 @@
1792
1723
  } );
1793
1724
  return buffers;
1794
1725
 
1795
- } // Generate data for a single face in a geometry. If the face is a quad then split it into 2 tris
1796
-
1726
+ }
1797
1727
 
1728
+ // Generate data for a single face in a geometry. If the face is a quad then split it into 2 tris
1798
1729
  genFace( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength ) {
1799
1730
 
1800
1731
  for ( let i = 2; i < faceLength; i ++ ) {
@@ -1808,7 +1739,6 @@
1808
1739
  buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 ] ] );
1809
1740
  buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 + 1 ] ] );
1810
1741
  buffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i * 3 + 2 ] ] );
1811
-
1812
1742
  if ( geoInfo.skeleton ) {
1813
1743
 
1814
1744
  buffers.vertexWeights.push( faceWeights[ 0 ] );
@@ -1893,12 +1823,12 @@
1893
1823
  }
1894
1824
 
1895
1825
  }
1896
-
1897
1826
  addMorphTargets( parentGeo, parentGeoNode, morphTargets, preTransform ) {
1898
1827
 
1899
1828
  if ( morphTargets.length === 0 ) return;
1900
1829
  parentGeo.morphTargetsRelative = true;
1901
- parentGeo.morphAttributes.position = []; // parentGeo.morphAttributes.normal = []; // not implemented
1830
+ parentGeo.morphAttributes.position = [];
1831
+ // parentGeo.morphAttributes.normal = []; // not implemented
1902
1832
 
1903
1833
  const scope = this;
1904
1834
  morphTargets.forEach( function ( morphTarget ) {
@@ -1906,7 +1836,6 @@
1906
1836
  morphTarget.rawTargets.forEach( function ( rawTarget ) {
1907
1837
 
1908
1838
  const morphGeoNode = fbxTree.Objects.Geometry[ rawTarget.geoID ];
1909
-
1910
1839
  if ( morphGeoNode !== undefined ) {
1911
1840
 
1912
1841
  scope.genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, rawTarget.name );
@@ -1917,12 +1846,12 @@
1917
1846
 
1918
1847
  } );
1919
1848
 
1920
- } // a morph geometry node is similar to a standard node, and the node is also contained
1849
+ }
1850
+
1851
+ // a morph geometry node is similar to a standard node, and the node is also contained
1921
1852
  // in FBXTree.Objects.Geometry, however it can only have attributes for position, normal
1922
1853
  // and a special attribute Index defining which vertices of the original geometry are affected
1923
1854
  // Normal and position attributes only have data for the vertices that are affected by the morph
1924
-
1925
-
1926
1855
  genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
1927
1856
 
1928
1857
  const vertexIndices = parentGeoNode.PolygonVertexIndex !== undefined ? parentGeoNode.PolygonVertexIndex.a : [];
@@ -1930,7 +1859,6 @@
1930
1859
  const indices = morphGeoNode.Indexes !== undefined ? morphGeoNode.Indexes.a : [];
1931
1860
  const length = parentGeo.attributes.position.count * 3;
1932
1861
  const morphPositions = new Float32Array( length );
1933
-
1934
1862
  for ( let i = 0; i < indices.length; i ++ ) {
1935
1863
 
1936
1864
  const morphIndex = indices[ i ] * 3;
@@ -1938,9 +1866,9 @@
1938
1866
  morphPositions[ morphIndex + 1 ] = morphPositionsSparse[ i * 3 + 1 ];
1939
1867
  morphPositions[ morphIndex + 2 ] = morphPositionsSparse[ i * 3 + 2 ];
1940
1868
 
1941
- } // TODO: add morph normal support
1942
-
1869
+ }
1943
1870
 
1871
+ // TODO: add morph normal support
1944
1872
  const morphGeoInfo = {
1945
1873
  vertexIndices: vertexIndices,
1946
1874
  vertexPositions: morphPositions
@@ -1951,16 +1879,15 @@
1951
1879
  positionAttribute.applyMatrix4( preTransform );
1952
1880
  parentGeo.morphAttributes.position.push( positionAttribute );
1953
1881
 
1954
- } // Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists
1955
-
1882
+ }
1956
1883
 
1884
+ // Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists
1957
1885
  parseNormals( NormalNode ) {
1958
1886
 
1959
1887
  const mappingType = NormalNode.MappingInformationType;
1960
1888
  const referenceType = NormalNode.ReferenceInformationType;
1961
1889
  const buffer = NormalNode.Normals.a;
1962
1890
  let indexBuffer = [];
1963
-
1964
1891
  if ( referenceType === 'IndexToDirect' ) {
1965
1892
 
1966
1893
  if ( 'NormalIndex' in NormalNode ) {
@@ -1983,16 +1910,15 @@
1983
1910
  referenceType: referenceType
1984
1911
  };
1985
1912
 
1986
- } // Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists
1987
-
1913
+ }
1988
1914
 
1915
+ // Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists
1989
1916
  parseUVs( UVNode ) {
1990
1917
 
1991
1918
  const mappingType = UVNode.MappingInformationType;
1992
1919
  const referenceType = UVNode.ReferenceInformationType;
1993
1920
  const buffer = UVNode.UV.a;
1994
1921
  let indexBuffer = [];
1995
-
1996
1922
  if ( referenceType === 'IndexToDirect' ) {
1997
1923
 
1998
1924
  indexBuffer = UVNode.UVIndex.a;
@@ -2007,16 +1933,15 @@
2007
1933
  referenceType: referenceType
2008
1934
  };
2009
1935
 
2010
- } // Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists
2011
-
1936
+ }
2012
1937
 
1938
+ // Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists
2013
1939
  parseVertexColors( ColorNode ) {
2014
1940
 
2015
1941
  const mappingType = ColorNode.MappingInformationType;
2016
1942
  const referenceType = ColorNode.ReferenceInformationType;
2017
1943
  const buffer = ColorNode.Colors.a;
2018
1944
  let indexBuffer = [];
2019
-
2020
1945
  if ( referenceType === 'IndexToDirect' ) {
2021
1946
 
2022
1947
  indexBuffer = ColorNode.ColorIndex.a;
@@ -2031,14 +1956,13 @@
2031
1956
  referenceType: referenceType
2032
1957
  };
2033
1958
 
2034
- } // Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists
2035
-
1959
+ }
2036
1960
 
1961
+ // Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists
2037
1962
  parseMaterialIndices( MaterialNode ) {
2038
1963
 
2039
1964
  const mappingType = MaterialNode.MappingInformationType;
2040
1965
  const referenceType = MaterialNode.ReferenceInformationType;
2041
-
2042
1966
  if ( mappingType === 'NoMappingInformation' ) {
2043
1967
 
2044
1968
  return {
@@ -2051,12 +1975,12 @@
2051
1975
 
2052
1976
  }
2053
1977
 
2054
- const materialIndexBuffer = MaterialNode.Materials.a; // Since materials are stored as indices, there's a bit of a mismatch between FBX and what
1978
+ const materialIndexBuffer = MaterialNode.Materials.a;
1979
+
1980
+ // Since materials are stored as indices, there's a bit of a mismatch between FBX and what
2055
1981
  // we expect.So we create an intermediate buffer that points to the index in the buffer,
2056
1982
  // for conforming with the other functions we've written for other data.
2057
-
2058
1983
  const materialIndices = [];
2059
-
2060
1984
  for ( let i = 0; i < materialIndexBuffer.length; ++ i ) {
2061
1985
 
2062
1986
  materialIndices.push( i );
@@ -2071,9 +1995,9 @@
2071
1995
  referenceType: referenceType
2072
1996
  };
2073
1997
 
2074
- } // Generate a NurbGeometry from a node in FBXTree.Objects.Geometry
2075
-
1998
+ }
2076
1999
 
2000
+ // Generate a NurbGeometry from a node in FBXTree.Objects.Geometry
2077
2001
  parseNurbsGeometry( geoNode ) {
2078
2002
 
2079
2003
  if ( THREE.NURBSCurve === undefined ) {
@@ -2084,7 +2008,6 @@
2084
2008
  }
2085
2009
 
2086
2010
  const order = parseInt( geoNode.Order );
2087
-
2088
2011
  if ( isNaN( order ) ) {
2089
2012
 
2090
2013
  console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geoNode.Order, geoNode.id );
@@ -2096,7 +2019,6 @@
2096
2019
  const knots = geoNode.KnotVector.a;
2097
2020
  const controlPoints = [];
2098
2021
  const pointsValues = geoNode.Points.a;
2099
-
2100
2022
  for ( let i = 0, l = pointsValues.length; i < l; i += 4 ) {
2101
2023
 
2102
2024
  controlPoints.push( new THREE.Vector4().fromArray( pointsValues, i ) );
@@ -2104,7 +2026,6 @@
2104
2026
  }
2105
2027
 
2106
2028
  let startKnot, endKnot;
2107
-
2108
2029
  if ( geoNode.Form === 'Closed' ) {
2109
2030
 
2110
2031
  controlPoints.push( controlPoints[ 0 ] );
@@ -2113,7 +2034,6 @@
2113
2034
 
2114
2035
  startKnot = degree;
2115
2036
  endKnot = knots.length - 1 - startKnot;
2116
-
2117
2037
  for ( let i = 0; i < degree; ++ i ) {
2118
2038
 
2119
2039
  controlPoints.push( controlPoints[ i ] );
@@ -2128,9 +2048,9 @@
2128
2048
 
2129
2049
  }
2130
2050
 
2131
- } // parse animation data from FBXTree
2132
-
2051
+ }
2133
2052
 
2053
+ // parse animation data from FBXTree
2134
2054
  class AnimationParser {
2135
2055
 
2136
2056
  // take raw animation clips and turn them into three.js animation clips
@@ -2138,7 +2058,6 @@
2138
2058
 
2139
2059
  const animationClips = [];
2140
2060
  const rawClips = this.parseClips();
2141
-
2142
2061
  if ( rawClips !== undefined ) {
2143
2062
 
2144
2063
  for ( const key in rawClips ) {
@@ -2154,7 +2073,6 @@
2154
2073
  return animationClips;
2155
2074
 
2156
2075
  }
2157
-
2158
2076
  parseClips() {
2159
2077
 
2160
2078
  // since the actual transformation data is stored in FBXTree.Objects.AnimationCurve,
@@ -2166,20 +2084,18 @@
2166
2084
  const rawClips = this.parseAnimStacks( layersMap );
2167
2085
  return rawClips;
2168
2086
 
2169
- } // parse nodes in FBXTree.Objects.AnimationCurveNode
2087
+ }
2088
+
2089
+ // parse nodes in FBXTree.Objects.AnimationCurveNode
2170
2090
  // each AnimationCurveNode holds data for an animation transform for a model (e.g. left arm rotation )
2171
2091
  // and is referenced by an AnimationLayer
2172
-
2173
-
2174
2092
  parseAnimationCurveNodes() {
2175
2093
 
2176
2094
  const rawCurveNodes = fbxTree.Objects.AnimationCurveNode;
2177
2095
  const curveNodesMap = new Map();
2178
-
2179
2096
  for ( const nodeID in rawCurveNodes ) {
2180
2097
 
2181
2098
  const rawCurveNode = rawCurveNodes[ nodeID ];
2182
-
2183
2099
  if ( rawCurveNode.attrName.match( /S|R|T|DeformPercent/ ) !== null ) {
2184
2100
 
2185
2101
  const curveNode = {
@@ -2195,14 +2111,16 @@
2195
2111
 
2196
2112
  return curveNodesMap;
2197
2113
 
2198
- } // parse nodes in FBXTree.Objects.AnimationCurve and connect them up to
2114
+ }
2115
+
2116
+ // parse nodes in FBXTree.Objects.AnimationCurve and connect them up to
2199
2117
  // previously parsed AnimationCurveNodes. Each AnimationCurve holds data for a single animated
2200
2118
  // axis ( e.g. times and values of x rotation)
2201
-
2202
-
2203
2119
  parseAnimationCurves( curveNodesMap ) {
2204
2120
 
2205
- const rawCurves = fbxTree.Objects.AnimationCurve; // TODO: Many values are identical up to roundoff error, but won't be optimised
2121
+ const rawCurves = fbxTree.Objects.AnimationCurve;
2122
+
2123
+ // TODO: Many values are identical up to roundoff error, but won't be optimised
2206
2124
  // e.g. position times: [0, 0.4, 0. 8]
2207
2125
  // position values: [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.235384487103147e-7, 93.67520904541016, -0.9982695579528809]
2208
2126
  // clearly, this should be optimised to
@@ -2217,12 +2135,10 @@
2217
2135
  values: rawCurves[ nodeID ].KeyValueFloat.a
2218
2136
  };
2219
2137
  const relationships = connections.get( animationCurve.id );
2220
-
2221
2138
  if ( relationships !== undefined ) {
2222
2139
 
2223
2140
  const animationCurveID = relationships.parents[ 0 ].ID;
2224
2141
  const animationCurveRelationship = relationships.parents[ 0 ].relationship;
2225
-
2226
2142
  if ( animationCurveRelationship.match( /X/ ) ) {
2227
2143
 
2228
2144
  curveNodesMap.get( animationCurveID ).curves[ 'x' ] = animationCurve;
@@ -2245,21 +2161,19 @@
2245
2161
 
2246
2162
  }
2247
2163
 
2248
- } // parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references
2164
+ }
2165
+
2166
+ // parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references
2249
2167
  // to various AnimationCurveNodes and is referenced by an AnimationStack node
2250
2168
  // note: theoretically a stack can have multiple layers, however in practice there always seems to be one per stack
2251
-
2252
-
2253
2169
  parseAnimationLayers( curveNodesMap ) {
2254
2170
 
2255
2171
  const rawLayers = fbxTree.Objects.AnimationLayer;
2256
2172
  const layersMap = new Map();
2257
-
2258
2173
  for ( const nodeID in rawLayers ) {
2259
2174
 
2260
2175
  const layerCurveNodes = [];
2261
2176
  const connection = connections.get( parseInt( nodeID ) );
2262
-
2263
2177
  if ( connection !== undefined ) {
2264
2178
 
2265
2179
  // all the animationCurveNodes used in the layer
@@ -2268,8 +2182,9 @@
2268
2182
 
2269
2183
  if ( curveNodesMap.has( child.ID ) ) {
2270
2184
 
2271
- const curveNode = curveNodesMap.get( child.ID ); // check that the curves are defined for at least one axis, otherwise ignore the curveNode
2185
+ const curveNode = curveNodesMap.get( child.ID );
2272
2186
 
2187
+ // check that the curves are defined for at least one axis, otherwise ignore the curveNode
2273
2188
  if ( curveNode.curves.x !== undefined || curveNode.curves.y !== undefined || curveNode.curves.z !== undefined ) {
2274
2189
 
2275
2190
  if ( layerCurveNodes[ i ] === undefined ) {
@@ -2279,11 +2194,9 @@
2279
2194
  return parent.relationship !== undefined;
2280
2195
 
2281
2196
  } )[ 0 ].ID;
2282
-
2283
2197
  if ( modelID !== undefined ) {
2284
2198
 
2285
2199
  const rawModel = fbxTree.Objects.Model[ modelID.toString() ];
2286
-
2287
2200
  if ( rawModel === undefined ) {
2288
2201
 
2289
2202
  console.warn( 'THREE.FBXLoader: Encountered a unused curve.', child );
@@ -2308,9 +2221,10 @@
2308
2221
  }
2309
2222
 
2310
2223
  } );
2311
- if ( ! node.transform ) node.transform = new THREE.Matrix4(); // if the animated model is pre rotated, we'll have to apply the pre rotations to every
2312
- // animation value as well
2224
+ if ( ! node.transform ) node.transform = new THREE.Matrix4();
2313
2225
 
2226
+ // if the animated model is pre rotated, we'll have to apply the pre rotations to every
2227
+ // animation value as well
2314
2228
  if ( 'PreRotation' in rawModel ) node.preRotation = rawModel.PreRotation.value;
2315
2229
  if ( 'PostRotation' in rawModel ) node.postRotation = rawModel.PostRotation.value;
2316
2230
  layerCurveNodes[ i ] = node;
@@ -2331,8 +2245,9 @@
2331
2245
 
2332
2246
  } )[ 0 ].ID;
2333
2247
  const morpherID = connections.get( deformerID ).parents[ 0 ].ID;
2334
- const geoID = connections.get( morpherID ).parents[ 0 ].ID; // assuming geometry is not used in more than one model
2248
+ const geoID = connections.get( morpherID ).parents[ 0 ].ID;
2335
2249
 
2250
+ // assuming geometry is not used in more than one model
2336
2251
  const modelID = connections.get( geoID ).parents[ 0 ].ID;
2337
2252
  const rawModel = fbxTree.Objects.Model[ modelID ];
2338
2253
  const node = {
@@ -2358,20 +2273,19 @@
2358
2273
 
2359
2274
  return layersMap;
2360
2275
 
2361
- } // parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation
2362
- // hierarchy. Each Stack node will be used to create a THREE.AnimationClip
2363
-
2276
+ }
2364
2277
 
2278
+ // parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation
2279
+ // hierarchy. Each Stack node will be used to create a THREE.AnimationClip
2365
2280
  parseAnimStacks( layersMap ) {
2366
2281
 
2367
- const rawStacks = fbxTree.Objects.AnimationStack; // connect the stacks (clips) up to the layers
2282
+ const rawStacks = fbxTree.Objects.AnimationStack;
2368
2283
 
2284
+ // connect the stacks (clips) up to the layers
2369
2285
  const rawClips = {};
2370
-
2371
2286
  for ( const nodeID in rawStacks ) {
2372
2287
 
2373
2288
  const children = connections.get( parseInt( nodeID ) ).children;
2374
-
2375
2289
  if ( children.length > 1 ) {
2376
2290
 
2377
2291
  // it seems like stacks will always be associated with a single layer. But just in case there are files
@@ -2391,7 +2305,6 @@
2391
2305
  return rawClips;
2392
2306
 
2393
2307
  }
2394
-
2395
2308
  addClip( rawClip ) {
2396
2309
 
2397
2310
  let tracks = [];
@@ -2404,7 +2317,6 @@
2404
2317
  return new THREE.AnimationClip( rawClip.name, - 1, tracks );
2405
2318
 
2406
2319
  }
2407
-
2408
2320
  generateTracks( rawTracks ) {
2409
2321
 
2410
2322
  const tracks = [];
@@ -2415,7 +2327,6 @@
2415
2327
  initialPosition = initialPosition.toArray();
2416
2328
  initialRotation = new THREE.Euler().setFromQuaternion( initialRotation, rawTracks.eulerOrder ).toArray();
2417
2329
  initialScale = initialScale.toArray();
2418
-
2419
2330
  if ( rawTracks.T !== undefined && Object.keys( rawTracks.T.curves ).length > 0 ) {
2420
2331
 
2421
2332
  const positionTrack = this.generateVectorTrack( rawTracks.modelName, rawTracks.T.curves, initialPosition, 'position' );
@@ -2447,7 +2358,6 @@
2447
2358
  return tracks;
2448
2359
 
2449
2360
  }
2450
-
2451
2361
  generateVectorTrack( modelName, curves, initialValue, type ) {
2452
2362
 
2453
2363
  const times = this.getTimesForAllAxes( curves );
@@ -2455,7 +2365,6 @@
2455
2365
  return new THREE.VectorKeyframeTrack( modelName + '.' + type, times, values );
2456
2366
 
2457
2367
  }
2458
-
2459
2368
  generateRotationTrack( modelName, curves, initialValue, preRotation, postRotation, eulerOrder ) {
2460
2369
 
2461
2370
  if ( curves.x !== undefined ) {
@@ -2481,7 +2390,6 @@
2481
2390
 
2482
2391
  const times = this.getTimesForAllAxes( curves );
2483
2392
  const values = this.getKeyframeTrackValues( times, curves, initialValue );
2484
-
2485
2393
  if ( preRotation !== undefined ) {
2486
2394
 
2487
2395
  preRotation = preRotation.map( THREE.MathUtils.degToRad );
@@ -2503,7 +2411,6 @@
2503
2411
  const quaternion = new THREE.Quaternion();
2504
2412
  const euler = new THREE.Euler();
2505
2413
  const quaternionValues = [];
2506
-
2507
2414
  for ( let i = 0; i < values.length; i += 3 ) {
2508
2415
 
2509
2416
  euler.set( values[ i ], values[ i + 1 ], values[ i + 2 ], eulerOrder );
@@ -2517,7 +2424,6 @@
2517
2424
  return new THREE.QuaternionKeyframeTrack( modelName + '.quaternion', times, quaternionValues );
2518
2425
 
2519
2426
  }
2520
-
2521
2427
  generateMorphTrack( rawTracks ) {
2522
2428
 
2523
2429
  const curves = rawTracks.DeformPercent.curves.morph;
@@ -2529,33 +2435,34 @@
2529
2435
  const morphNum = sceneGraph.getObjectByName( rawTracks.modelName ).morphTargetDictionary[ rawTracks.morphName ];
2530
2436
  return new THREE.NumberKeyframeTrack( rawTracks.modelName + '.morphTargetInfluences[' + morphNum + ']', curves.times, values );
2531
2437
 
2532
- } // For all animated objects, times are defined separately for each axis
2533
- // Here we'll combine the times into one sorted array without duplicates
2534
-
2438
+ }
2535
2439
 
2440
+ // For all animated objects, times are defined separately for each axis
2441
+ // Here we'll combine the times into one sorted array without duplicates
2536
2442
  getTimesForAllAxes( curves ) {
2537
2443
 
2538
- let times = []; // first join together the times for each axis, if defined
2444
+ let times = [];
2539
2445
 
2446
+ // first join together the times for each axis, if defined
2540
2447
  if ( curves.x !== undefined ) times = times.concat( curves.x.times );
2541
2448
  if ( curves.y !== undefined ) times = times.concat( curves.y.times );
2542
- if ( curves.z !== undefined ) times = times.concat( curves.z.times ); // then sort them
2449
+ if ( curves.z !== undefined ) times = times.concat( curves.z.times );
2543
2450
 
2451
+ // then sort them
2544
2452
  times = times.sort( function ( a, b ) {
2545
2453
 
2546
2454
  return a - b;
2547
2455
 
2548
- } ); // and remove duplicates
2456
+ } );
2549
2457
 
2458
+ // and remove duplicates
2550
2459
  if ( times.length > 1 ) {
2551
2460
 
2552
2461
  let targetIndex = 1;
2553
2462
  let lastValue = times[ 0 ];
2554
-
2555
2463
  for ( let i = 1; i < times.length; i ++ ) {
2556
2464
 
2557
2465
  const currentValue = times[ i ];
2558
-
2559
2466
  if ( currentValue !== lastValue ) {
2560
2467
 
2561
2468
  times[ targetIndex ] = currentValue;
@@ -2573,7 +2480,6 @@
2573
2480
  return times;
2574
2481
 
2575
2482
  }
2576
-
2577
2483
  getKeyframeTrackValues( times, curves, initialValue ) {
2578
2484
 
2579
2485
  const prevValue = initialValue;
@@ -2585,8 +2491,9 @@
2585
2491
 
2586
2492
  if ( curves.x ) xIndex = curves.x.times.indexOf( time );
2587
2493
  if ( curves.y ) yIndex = curves.y.times.indexOf( time );
2588
- if ( curves.z ) zIndex = curves.z.times.indexOf( time ); // if there is an x value defined for this frame, use that
2494
+ if ( curves.z ) zIndex = curves.z.times.indexOf( time );
2589
2495
 
2496
+ // if there is an x value defined for this frame, use that
2590
2497
  if ( xIndex !== - 1 ) {
2591
2498
 
2592
2499
  const xValue = curves.x.values[ xIndex ];
@@ -2627,11 +2534,11 @@
2627
2534
  } );
2628
2535
  return values;
2629
2536
 
2630
- } // Rotations are defined as THREE.Euler angles which can have values of any size
2537
+ }
2538
+
2539
+ // Rotations are defined as THREE.Euler angles which can have values of any size
2631
2540
  // These will be converted to quaternions which don't support values greater than
2632
2541
  // PI, so we'll interpolate large rotations
2633
-
2634
-
2635
2542
  interpolateRotations( curve ) {
2636
2543
 
2637
2544
  for ( let i = 1; i < curve.values.length; i ++ ) {
@@ -2639,7 +2546,6 @@
2639
2546
  const initialValue = curve.values[ i - 1 ];
2640
2547
  const valuesSpan = curve.values[ i ] - initialValue;
2641
2548
  const absoluteSpan = Math.abs( valuesSpan );
2642
-
2643
2549
  if ( absoluteSpan >= 180 ) {
2644
2550
 
2645
2551
  const numSubIntervals = absoluteSpan / 180;
@@ -2651,7 +2557,6 @@
2651
2557
  let nextTime = initialTime + interval;
2652
2558
  const interpolatedTimes = [];
2653
2559
  const interpolatedValues = [];
2654
-
2655
2560
  while ( nextTime < curve.times[ i ] ) {
2656
2561
 
2657
2562
  interpolatedTimes.push( nextTime );
@@ -2670,9 +2575,9 @@
2670
2575
 
2671
2576
  }
2672
2577
 
2673
- } // parse an FBX file in ASCII format
2674
-
2578
+ }
2675
2579
 
2580
+ // parse an FBX file in ASCII format
2676
2581
  class TextParser {
2677
2582
 
2678
2583
  getPrevNode() {
@@ -2680,40 +2585,34 @@
2680
2585
  return this.nodeStack[ this.currentIndent - 2 ];
2681
2586
 
2682
2587
  }
2683
-
2684
2588
  getCurrentNode() {
2685
2589
 
2686
2590
  return this.nodeStack[ this.currentIndent - 1 ];
2687
2591
 
2688
2592
  }
2689
-
2690
2593
  getCurrentProp() {
2691
2594
 
2692
2595
  return this.currentProp;
2693
2596
 
2694
2597
  }
2695
-
2696
2598
  pushStack( node ) {
2697
2599
 
2698
2600
  this.nodeStack.push( node );
2699
2601
  this.currentIndent += 1;
2700
2602
 
2701
2603
  }
2702
-
2703
2604
  popStack() {
2704
2605
 
2705
2606
  this.nodeStack.pop();
2706
2607
  this.currentIndent -= 1;
2707
2608
 
2708
2609
  }
2709
-
2710
2610
  setCurrentProp( val, name ) {
2711
2611
 
2712
2612
  this.currentProp = val;
2713
2613
  this.currentPropName = name;
2714
2614
 
2715
2615
  }
2716
-
2717
2616
  parse( text ) {
2718
2617
 
2719
2618
  this.currentIndent = 0;
@@ -2731,7 +2630,6 @@
2731
2630
  const matchBeginning = line.match( '^\\t{' + scope.currentIndent + '}(\\w+):(.*){', '' );
2732
2631
  const matchProperty = line.match( '^\\t{' + scope.currentIndent + '}(\\w+):[\\s\\t\\r\\n](.*)' );
2733
2632
  const matchEnd = line.match( '^\\t{' + ( scope.currentIndent - 1 ) + '}}' );
2734
-
2735
2633
  if ( matchBeginning ) {
2736
2634
 
2737
2635
  scope.parseNodeBegin( line, matchBeginning );
@@ -2756,7 +2654,6 @@
2756
2654
  return this.allNodes;
2757
2655
 
2758
2656
  }
2759
-
2760
2657
  parseNodeBegin( line, property ) {
2761
2658
 
2762
2659
  const nodeName = property[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
@@ -2769,8 +2666,9 @@
2769
2666
  name: nodeName
2770
2667
  };
2771
2668
  const attrs = this.parseNodeAttr( nodeAttrs );
2772
- const currentNode = this.getCurrentNode(); // a top node
2669
+ const currentNode = this.getCurrentNode();
2773
2670
 
2671
+ // a top node
2774
2672
  if ( this.currentIndent === 0 ) {
2775
2673
 
2776
2674
  this.allNodes.add( nodeName, node );
@@ -2778,6 +2676,7 @@
2778
2676
  } else {
2779
2677
 
2780
2678
  // a subnode
2679
+
2781
2680
  // if the subnode already exists, append it
2782
2681
  if ( nodeName in currentNode ) {
2783
2682
 
@@ -2814,15 +2713,12 @@
2814
2713
  this.pushStack( node );
2815
2714
 
2816
2715
  }
2817
-
2818
2716
  parseNodeAttr( attrs ) {
2819
2717
 
2820
2718
  let id = attrs[ 0 ];
2821
-
2822
2719
  if ( attrs[ 0 ] !== '' ) {
2823
2720
 
2824
2721
  id = parseInt( attrs[ 0 ] );
2825
-
2826
2722
  if ( isNaN( id ) ) {
2827
2723
 
2828
2724
  id = attrs[ 0 ];
@@ -2833,7 +2729,6 @@
2833
2729
 
2834
2730
  let name = '',
2835
2731
  type = '';
2836
-
2837
2732
  if ( attrs.length > 1 ) {
2838
2733
 
2839
2734
  name = attrs[ 1 ].replace( /^(\w+)::/, '' );
@@ -2848,14 +2743,14 @@
2848
2743
  };
2849
2744
 
2850
2745
  }
2851
-
2852
2746
  parseNodeProperty( line, property, contentLine ) {
2853
2747
 
2854
2748
  let propName = property[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
2855
- let propValue = property[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim(); // for special case: base64 image data follows "Content: ," line
2749
+ let propValue = property[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
2750
+
2751
+ // for special case: base64 image data follows "Content: ," line
2856
2752
  // Content: ,
2857
2753
  // "/9j/4RDaRXhpZgAATU0A..."
2858
-
2859
2754
  if ( propName === 'Content' && propValue === ',' ) {
2860
2755
 
2861
2756
  propValue = contentLine.replace( /"/g, '' ).replace( /,$/, '' ).trim();
@@ -2864,15 +2759,14 @@
2864
2759
 
2865
2760
  const currentNode = this.getCurrentNode();
2866
2761
  const parentName = currentNode.name;
2867
-
2868
2762
  if ( parentName === 'Properties70' ) {
2869
2763
 
2870
2764
  this.parseNodeSpecialProperty( line, propName, propValue );
2871
2765
  return;
2872
2766
 
2873
- } // Connections
2874
-
2767
+ }
2875
2768
 
2769
+ // Connections
2876
2770
  if ( propName === 'C' ) {
2877
2771
 
2878
2772
  const connProps = propValue.split( ',' ).slice( 1 );
@@ -2887,18 +2781,18 @@
2887
2781
  propName = 'connections';
2888
2782
  propValue = [ from, to ];
2889
2783
  append( propValue, rest );
2890
-
2891
2784
  if ( currentNode[ propName ] === undefined ) {
2892
2785
 
2893
2786
  currentNode[ propName ] = [];
2894
2787
 
2895
2788
  }
2896
2789
 
2897
- } // Node
2898
-
2790
+ }
2899
2791
 
2900
- if ( propName === 'Node' ) currentNode.id = propValue; // connections
2792
+ // Node
2793
+ if ( propName === 'Node' ) currentNode.id = propValue;
2901
2794
 
2795
+ // connections
2902
2796
  if ( propName in currentNode && Array.isArray( currentNode[ propName ] ) ) {
2903
2797
 
2904
2798
  currentNode[ propName ].push( propValue );
@@ -2909,8 +2803,9 @@
2909
2803
 
2910
2804
  }
2911
2805
 
2912
- this.setCurrentProp( currentNode, propName ); // convert string to array, unless it ends in ',' in which case more will be added to it
2806
+ this.setCurrentProp( currentNode, propName );
2913
2807
 
2808
+ // convert string to array, unless it ends in ',' in which case more will be added to it
2914
2809
  if ( propName === 'a' && propValue.slice( - 1 ) !== ',' ) {
2915
2810
 
2916
2811
  currentNode.a = parseNumberArray( propValue );
@@ -2918,22 +2813,22 @@
2918
2813
  }
2919
2814
 
2920
2815
  }
2921
-
2922
2816
  parseNodePropertyContinued( line ) {
2923
2817
 
2924
2818
  const currentNode = this.getCurrentNode();
2925
- currentNode.a += line; // if the line doesn't end in ',' we have reached the end of the property value
2926
- // so convert the string to an array
2819
+ currentNode.a += line;
2927
2820
 
2821
+ // if the line doesn't end in ',' we have reached the end of the property value
2822
+ // so convert the string to an array
2928
2823
  if ( line.slice( - 1 ) !== ',' ) {
2929
2824
 
2930
2825
  currentNode.a = parseNumberArray( currentNode.a );
2931
2826
 
2932
2827
  }
2933
2828
 
2934
- } // parse "Property70"
2935
-
2829
+ }
2936
2830
 
2831
+ // parse "Property70"
2937
2832
  parseNodeSpecialProperty( line, propName, propValue ) {
2938
2833
 
2939
2834
  // split this
@@ -2949,8 +2844,9 @@
2949
2844
  const innerPropType1 = props[ 1 ];
2950
2845
  const innerPropType2 = props[ 2 ];
2951
2846
  const innerPropFlag = props[ 3 ];
2952
- let innerPropValue = props[ 4 ]; // cast values where needed, otherwise leave as strings
2847
+ let innerPropValue = props[ 4 ];
2953
2848
 
2849
+ // cast values where needed, otherwise leave as strings
2954
2850
  switch ( innerPropType1 ) {
2955
2851
 
2956
2852
  case 'int':
@@ -2962,7 +2858,6 @@
2962
2858
  case 'FieldOfView':
2963
2859
  innerPropValue = parseFloat( innerPropValue );
2964
2860
  break;
2965
-
2966
2861
  case 'Color':
2967
2862
  case 'ColorRGB':
2968
2863
  case 'Vector3D':
@@ -2972,9 +2867,9 @@
2972
2867
  innerPropValue = parseNumberArray( innerPropValue );
2973
2868
  break;
2974
2869
 
2975
- } // CAUTION: these props must append to parent's parent
2976
-
2870
+ }
2977
2871
 
2872
+ // CAUTION: these props must append to parent's parent
2978
2873
  this.getPrevNode()[ innerPropName ] = {
2979
2874
  'type': innerPropType1,
2980
2875
  'type2': innerPropType2,
@@ -2985,9 +2880,9 @@
2985
2880
 
2986
2881
  }
2987
2882
 
2988
- } // Parse an FBX file in Binary format
2989
-
2883
+ }
2990
2884
 
2885
+ // Parse an FBX file in Binary format
2991
2886
  class BinaryParser {
2992
2887
 
2993
2888
  parse( buffer ) {
@@ -2996,7 +2891,6 @@
2996
2891
  reader.skip( 23 ); // skip magic 23 bytes
2997
2892
 
2998
2893
  const version = reader.getUint32();
2999
-
3000
2894
  if ( version < 6400 ) {
3001
2895
 
3002
2896
  throw new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + version );
@@ -3004,7 +2898,6 @@
3004
2898
  }
3005
2899
 
3006
2900
  const allNodes = new FBXTree();
3007
-
3008
2901
  while ( ! this.endOfContent( reader ) ) {
3009
2902
 
3010
2903
  const node = this.parseNode( reader, version );
@@ -3014,9 +2907,9 @@
3014
2907
 
3015
2908
  return allNodes;
3016
2909
 
3017
- } // Check if reader has reached the end of content.
3018
-
2910
+ }
3019
2911
 
2912
+ // Check if reader has reached the end of content.
3020
2913
  endOfContent( reader ) {
3021
2914
 
3022
2915
  // footer size: 160bytes + 16-byte alignment padding
@@ -3037,37 +2930,38 @@
3037
2930
 
3038
2931
  }
3039
2932
 
3040
- } // recursively parse nodes until the end of the file is reached
3041
-
2933
+ }
3042
2934
 
2935
+ // recursively parse nodes until the end of the file is reached
3043
2936
  parseNode( reader, version ) {
3044
2937
 
3045
- const node = {}; // The first three data sizes depends on version.
2938
+ const node = {};
3046
2939
 
2940
+ // The first three data sizes depends on version.
3047
2941
  const endOffset = version >= 7500 ? reader.getUint64() : reader.getUint32();
3048
2942
  const numProperties = version >= 7500 ? reader.getUint64() : reader.getUint32();
3049
2943
  version >= 7500 ? reader.getUint64() : reader.getUint32(); // the returned propertyListLen is not used
3050
2944
 
3051
2945
  const nameLen = reader.getUint8();
3052
- const name = reader.getString( nameLen ); // Regards this node as NULL-record if endOffset is zero
2946
+ const name = reader.getString( nameLen );
3053
2947
 
2948
+ // Regards this node as NULL-record if endOffset is zero
3054
2949
  if ( endOffset === 0 ) return null;
3055
2950
  const propertyList = [];
3056
-
3057
2951
  for ( let i = 0; i < numProperties; i ++ ) {
3058
2952
 
3059
2953
  propertyList.push( this.parseProperty( reader ) );
3060
2954
 
3061
- } // Regards the first three elements in propertyList as id, attrName, and attrType
3062
-
2955
+ }
3063
2956
 
2957
+ // Regards the first three elements in propertyList as id, attrName, and attrType
3064
2958
  const id = propertyList.length > 0 ? propertyList[ 0 ] : '';
3065
2959
  const attrName = propertyList.length > 1 ? propertyList[ 1 ] : '';
3066
- const attrType = propertyList.length > 2 ? propertyList[ 2 ] : ''; // check if this node represents just a single property
3067
- // like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
2960
+ const attrType = propertyList.length > 2 ? propertyList[ 2 ] : '';
3068
2961
 
2962
+ // check if this node represents just a single property
2963
+ // like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
3069
2964
  node.singleProperty = numProperties === 1 && reader.getOffset() === endOffset ? true : false;
3070
-
3071
2965
  while ( endOffset > reader.getOffset() ) {
3072
2966
 
3073
2967
  const subNode = this.parseNode( reader, version );
@@ -3084,14 +2978,12 @@
3084
2978
  return node;
3085
2979
 
3086
2980
  }
3087
-
3088
2981
  parseSubNode( name, node, subNode ) {
3089
2982
 
3090
2983
  // special case: child node is single property
3091
2984
  if ( subNode.singleProperty === true ) {
3092
2985
 
3093
2986
  const value = subNode.propertyList[ 0 ];
3094
-
3095
2987
  if ( Array.isArray( value ) ) {
3096
2988
 
3097
2989
  node[ subNode.name ] = subNode;
@@ -3112,7 +3004,6 @@
3112
3004
  if ( i !== 0 ) array.push( property );
3113
3005
 
3114
3006
  } );
3115
-
3116
3007
  if ( node.connections === undefined ) {
3117
3008
 
3118
3009
  node.connections = [];
@@ -3139,7 +3030,6 @@
3139
3030
  let innerPropValue;
3140
3031
  if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
3141
3032
  if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
3142
-
3143
3033
  if ( innerPropType1 === 'Color' || innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
3144
3034
 
3145
3035
  innerPropValue = [ subNode.propertyList[ 4 ], subNode.propertyList[ 5 ], subNode.propertyList[ 6 ] ];
@@ -3148,9 +3038,9 @@
3148
3038
 
3149
3039
  innerPropValue = subNode.propertyList[ 4 ];
3150
3040
 
3151
- } // this will be copied to parent, see above
3152
-
3041
+ }
3153
3042
 
3043
+ // this will be copied to parent, see above
3154
3044
  node[ innerPropName ] = {
3155
3045
  'type': innerPropType1,
3156
3046
  'type2': innerPropType2,
@@ -3192,40 +3082,30 @@
3192
3082
  }
3193
3083
 
3194
3084
  }
3195
-
3196
3085
  parseProperty( reader ) {
3197
3086
 
3198
3087
  const type = reader.getString( 1 );
3199
3088
  let length;
3200
-
3201
3089
  switch ( type ) {
3202
3090
 
3203
3091
  case 'C':
3204
3092
  return reader.getBoolean();
3205
-
3206
3093
  case 'D':
3207
3094
  return reader.getFloat64();
3208
-
3209
3095
  case 'F':
3210
3096
  return reader.getFloat32();
3211
-
3212
3097
  case 'I':
3213
3098
  return reader.getInt32();
3214
-
3215
3099
  case 'L':
3216
3100
  return reader.getInt64();
3217
-
3218
3101
  case 'R':
3219
3102
  length = reader.getUint32();
3220
3103
  return reader.getArrayBuffer( length );
3221
-
3222
3104
  case 'S':
3223
3105
  length = reader.getUint32();
3224
3106
  return reader.getString( length );
3225
-
3226
3107
  case 'Y':
3227
3108
  return reader.getInt16();
3228
-
3229
3109
  case 'b':
3230
3110
  case 'c':
3231
3111
  case 'd':
@@ -3234,9 +3114,7 @@
3234
3114
  case 'l':
3235
3115
  const arrayLength = reader.getUint32();
3236
3116
  const encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
3237
-
3238
3117
  const compressedLength = reader.getUint32();
3239
-
3240
3118
  if ( encoding === 0 ) {
3241
3119
 
3242
3120
  switch ( type ) {
@@ -3244,16 +3122,12 @@
3244
3122
  case 'b':
3245
3123
  case 'c':
3246
3124
  return reader.getBooleanArray( arrayLength );
3247
-
3248
3125
  case 'd':
3249
3126
  return reader.getFloat64Array( arrayLength );
3250
-
3251
3127
  case 'f':
3252
3128
  return reader.getFloat32Array( arrayLength );
3253
-
3254
3129
  case 'i':
3255
3130
  return reader.getInt32Array( arrayLength );
3256
-
3257
3131
  case 'l':
3258
3132
  return reader.getInt64Array( arrayLength );
3259
3133
 
@@ -3268,24 +3142,18 @@
3268
3142
  }
3269
3143
 
3270
3144
  const data = fflate.unzlibSync( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
3271
-
3272
3145
  const reader2 = new BinaryReader( data.buffer );
3273
-
3274
3146
  switch ( type ) {
3275
3147
 
3276
3148
  case 'b':
3277
3149
  case 'c':
3278
3150
  return reader2.getBooleanArray( arrayLength );
3279
-
3280
3151
  case 'd':
3281
3152
  return reader2.getFloat64Array( arrayLength );
3282
-
3283
3153
  case 'f':
3284
3154
  return reader2.getFloat32Array( arrayLength );
3285
-
3286
3155
  case 'i':
3287
3156
  return reader2.getInt32Array( arrayLength );
3288
-
3289
3157
  case 'l':
3290
3158
  return reader2.getInt64Array( arrayLength );
3291
3159
 
@@ -3302,7 +3170,6 @@
3302
3170
  }
3303
3171
 
3304
3172
  }
3305
-
3306
3173
  class BinaryReader {
3307
3174
 
3308
3175
  constructor( buffer, littleEndian ) {
@@ -3312,38 +3179,33 @@
3312
3179
  this.littleEndian = littleEndian !== undefined ? littleEndian : true;
3313
3180
 
3314
3181
  }
3315
-
3316
3182
  getOffset() {
3317
3183
 
3318
3184
  return this.offset;
3319
3185
 
3320
3186
  }
3321
-
3322
3187
  size() {
3323
3188
 
3324
3189
  return this.dv.buffer.byteLength;
3325
3190
 
3326
3191
  }
3327
-
3328
3192
  skip( length ) {
3329
3193
 
3330
3194
  this.offset += length;
3331
3195
 
3332
- } // seems like true/false representation depends on exporter.
3196
+ }
3197
+
3198
+ // seems like true/false representation depends on exporter.
3333
3199
  // true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
3334
3200
  // then sees LSB.
3335
-
3336
-
3337
3201
  getBoolean() {
3338
3202
 
3339
3203
  return ( this.getUint8() & 1 ) === 1;
3340
3204
 
3341
3205
  }
3342
-
3343
3206
  getBooleanArray( size ) {
3344
3207
 
3345
3208
  const a = [];
3346
-
3347
3209
  for ( let i = 0; i < size; i ++ ) {
3348
3210
 
3349
3211
  a.push( this.getBoolean() );
@@ -3353,7 +3215,6 @@
3353
3215
  return a;
3354
3216
 
3355
3217
  }
3356
-
3357
3218
  getUint8() {
3358
3219
 
3359
3220
  const value = this.dv.getUint8( this.offset );
@@ -3361,7 +3222,6 @@
3361
3222
  return value;
3362
3223
 
3363
3224
  }
3364
-
3365
3225
  getInt16() {
3366
3226
 
3367
3227
  const value = this.dv.getInt16( this.offset, this.littleEndian );
@@ -3369,7 +3229,6 @@
3369
3229
  return value;
3370
3230
 
3371
3231
  }
3372
-
3373
3232
  getInt32() {
3374
3233
 
3375
3234
  const value = this.dv.getInt32( this.offset, this.littleEndian );
@@ -3377,11 +3236,9 @@
3377
3236
  return value;
3378
3237
 
3379
3238
  }
3380
-
3381
3239
  getInt32Array( size ) {
3382
3240
 
3383
3241
  const a = [];
3384
-
3385
3242
  for ( let i = 0; i < size; i ++ ) {
3386
3243
 
3387
3244
  a.push( this.getInt32() );
@@ -3391,24 +3248,22 @@
3391
3248
  return a;
3392
3249
 
3393
3250
  }
3394
-
3395
3251
  getUint32() {
3396
3252
 
3397
3253
  const value = this.dv.getUint32( this.offset, this.littleEndian );
3398
3254
  this.offset += 4;
3399
3255
  return value;
3400
3256
 
3401
- } // JavaScript doesn't support 64-bit integer so calculate this here
3257
+ }
3258
+
3259
+ // JavaScript doesn't support 64-bit integer so calculate this here
3402
3260
  // 1 << 32 will return 1 so using multiply operation instead here.
3403
3261
  // There's a possibility that this method returns wrong value if the value
3404
3262
  // is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
3405
3263
  // TODO: safely handle 64-bit integer
3406
-
3407
-
3408
3264
  getInt64() {
3409
3265
 
3410
3266
  let low, high;
3411
-
3412
3267
  if ( this.littleEndian ) {
3413
3268
 
3414
3269
  low = this.getUint32();
@@ -3419,9 +3274,9 @@
3419
3274
  high = this.getUint32();
3420
3275
  low = this.getUint32();
3421
3276
 
3422
- } // calculate negative value
3423
-
3277
+ }
3424
3278
 
3279
+ // calculate negative value
3425
3280
  if ( high & 0x80000000 ) {
3426
3281
 
3427
3282
  high = ~ high & 0xFFFFFFFF;
@@ -3435,11 +3290,9 @@
3435
3290
  return high * 0x100000000 + low;
3436
3291
 
3437
3292
  }
3438
-
3439
3293
  getInt64Array( size ) {
3440
3294
 
3441
3295
  const a = [];
3442
-
3443
3296
  for ( let i = 0; i < size; i ++ ) {
3444
3297
 
3445
3298
  a.push( this.getInt64() );
@@ -3448,13 +3301,12 @@
3448
3301
 
3449
3302
  return a;
3450
3303
 
3451
- } // Note: see getInt64() comment
3452
-
3304
+ }
3453
3305
 
3306
+ // Note: see getInt64() comment
3454
3307
  getUint64() {
3455
3308
 
3456
3309
  let low, high;
3457
-
3458
3310
  if ( this.littleEndian ) {
3459
3311
 
3460
3312
  low = this.getUint32();
@@ -3470,7 +3322,6 @@
3470
3322
  return high * 0x100000000 + low;
3471
3323
 
3472
3324
  }
3473
-
3474
3325
  getFloat32() {
3475
3326
 
3476
3327
  const value = this.dv.getFloat32( this.offset, this.littleEndian );
@@ -3478,11 +3329,9 @@
3478
3329
  return value;
3479
3330
 
3480
3331
  }
3481
-
3482
3332
  getFloat32Array( size ) {
3483
3333
 
3484
3334
  const a = [];
3485
-
3486
3335
  for ( let i = 0; i < size; i ++ ) {
3487
3336
 
3488
3337
  a.push( this.getFloat32() );
@@ -3492,7 +3341,6 @@
3492
3341
  return a;
3493
3342
 
3494
3343
  }
3495
-
3496
3344
  getFloat64() {
3497
3345
 
3498
3346
  const value = this.dv.getFloat64( this.offset, this.littleEndian );
@@ -3500,11 +3348,9 @@
3500
3348
  return value;
3501
3349
 
3502
3350
  }
3503
-
3504
3351
  getFloat64Array( size ) {
3505
3352
 
3506
3353
  const a = [];
3507
-
3508
3354
  for ( let i = 0; i < size; i ++ ) {
3509
3355
 
3510
3356
  a.push( this.getFloat64() );
@@ -3514,7 +3360,6 @@
3514
3360
  return a;
3515
3361
 
3516
3362
  }
3517
-
3518
3363
  getArrayBuffer( size ) {
3519
3364
 
3520
3365
  const value = this.dv.buffer.slice( this.offset, this.offset + size );
@@ -3522,12 +3367,10 @@
3522
3367
  return value;
3523
3368
 
3524
3369
  }
3525
-
3526
3370
  getString( size ) {
3527
3371
 
3528
3372
  // note: safari 9 doesn't support Uint8Array.indexOf; create intermediate array instead
3529
3373
  let a = [];
3530
-
3531
3374
  for ( let i = 0; i < size; i ++ ) {
3532
3375
 
3533
3376
  a[ i ] = this.getUint8();
@@ -3540,10 +3383,10 @@
3540
3383
 
3541
3384
  }
3542
3385
 
3543
- } // FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
3544
- // and BinaryParser( FBX Binary format)
3545
-
3386
+ }
3546
3387
 
3388
+ // FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
3389
+ // and BinaryParser( FBX Binary format)
3547
3390
  class FBXTree {
3548
3391
 
3549
3392
  add( key, val ) {
@@ -3552,8 +3395,9 @@
3552
3395
 
3553
3396
  }
3554
3397
 
3555
- } // ************** UTILITY FUNCTIONS **************
3398
+ }
3556
3399
 
3400
+ // ************** UTILITY FUNCTIONS **************
3557
3401
 
3558
3402
  function isFbxFormatBinary( buffer ) {
3559
3403
 
@@ -3566,7 +3410,6 @@
3566
3410
 
3567
3411
  const CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
3568
3412
  let cursor = 0;
3569
-
3570
3413
  function read( offset ) {
3571
3414
 
3572
3415
  const result = text[ offset - 1 ];
@@ -3579,7 +3422,6 @@
3579
3422
  for ( let i = 0; i < CORRECT.length; ++ i ) {
3580
3423
 
3581
3424
  const num = read( 1 );
3582
-
3583
3425
  if ( num === CORRECT[ i ] ) {
3584
3426
 
3585
3427
  return false;
@@ -3596,7 +3438,6 @@
3596
3438
 
3597
3439
  const versionRegExp = /FBXVersion: (\d+)/;
3598
3440
  const match = text.match( versionRegExp );
3599
-
3600
3441
  if ( match ) {
3601
3442
 
3602
3443
  const version = parseInt( match[ 1 ] );
@@ -3606,39 +3447,35 @@
3606
3447
 
3607
3448
  throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
3608
3449
 
3609
- } // Converts FBX ticks into real time seconds.
3610
-
3450
+ }
3611
3451
 
3452
+ // Converts FBX ticks into real time seconds.
3612
3453
  function convertFBXTimeToSeconds( time ) {
3613
3454
 
3614
3455
  return time / 46186158000;
3615
3456
 
3616
3457
  }
3617
3458
 
3618
- const dataArray = []; // extracts the data from the correct position in the FBX array based on indexing type
3459
+ const dataArray = [];
3619
3460
 
3461
+ // extracts the data from the correct position in the FBX array based on indexing type
3620
3462
  function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
3621
3463
 
3622
3464
  let index;
3623
-
3624
3465
  switch ( infoObject.mappingType ) {
3625
3466
 
3626
3467
  case 'ByPolygonVertex':
3627
3468
  index = polygonVertexIndex;
3628
3469
  break;
3629
-
3630
3470
  case 'ByPolygon':
3631
3471
  index = polygonIndex;
3632
3472
  break;
3633
-
3634
3473
  case 'ByVertice':
3635
3474
  index = vertexIndex;
3636
3475
  break;
3637
-
3638
3476
  case 'AllSame':
3639
3477
  index = infoObject.indices[ 0 ];
3640
3478
  break;
3641
-
3642
3479
  default:
3643
3480
  console.warn( 'THREE.FBXLoader: unknown attribute mapping type ' + infoObject.mappingType );
3644
3481
 
@@ -3652,10 +3489,11 @@
3652
3489
  }
3653
3490
 
3654
3491
  const tempEuler = new THREE.Euler();
3655
- const tempVec = new THREE.Vector3(); // generate transformation from FBX transform data
3492
+ const tempVec = new THREE.Vector3();
3493
+
3494
+ // generate transformation from FBX transform data
3656
3495
  // ref: https://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm
3657
3496
  // ref: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/_transformations_2main_8cxx-example.html,topicNumber=cpp_ref__transformations_2main_8cxx_example_htmlfc10a1e1-b18d-4e72-9dc0-70d0f1959f5e
3658
-
3659
3497
  function generateTransform( transformData ) {
3660
3498
 
3661
3499
  const lTranslationM = new THREE.Matrix4();
@@ -3672,7 +3510,6 @@
3672
3510
  const lGlobalT = new THREE.Matrix4();
3673
3511
  const inheritType = transformData.inheritType ? transformData.inheritType : 0;
3674
3512
  if ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) );
3675
-
3676
3513
  if ( transformData.preRotation ) {
3677
3514
 
3678
3515
  const array = transformData.preRotation.map( THREE.MathUtils.degToRad );
@@ -3698,13 +3535,15 @@
3698
3535
 
3699
3536
  }
3700
3537
 
3701
- if ( transformData.scale ) lScalingM.scale( tempVec.fromArray( transformData.scale ) ); // Pivots and offsets
3538
+ if ( transformData.scale ) lScalingM.scale( tempVec.fromArray( transformData.scale ) );
3702
3539
 
3540
+ // Pivots and offsets
3703
3541
  if ( transformData.scalingOffset ) lScalingOffsetM.setPosition( tempVec.fromArray( transformData.scalingOffset ) );
3704
3542
  if ( transformData.scalingPivot ) lScalingPivotM.setPosition( tempVec.fromArray( transformData.scalingPivot ) );
3705
3543
  if ( transformData.rotationOffset ) lRotationOffsetM.setPosition( tempVec.fromArray( transformData.rotationOffset ) );
3706
- if ( transformData.rotationPivot ) lRotationPivotM.setPosition( tempVec.fromArray( transformData.rotationPivot ) ); // parent transform
3544
+ if ( transformData.rotationPivot ) lRotationPivotM.setPosition( tempVec.fromArray( transformData.rotationPivot ) );
3707
3545
 
3546
+ // parent transform
3708
3547
  if ( transformData.parentMatrixWorld ) {
3709
3548
 
3710
3549
  lParentLX.copy( transformData.parentMatrix );
@@ -3712,18 +3551,18 @@
3712
3551
 
3713
3552
  }
3714
3553
 
3715
- const lLRM = lPreRotationM.clone().multiply( lRotationM ).multiply( lPostRotationM ); // Global Rotation
3716
-
3554
+ const lLRM = lPreRotationM.clone().multiply( lRotationM ).multiply( lPostRotationM );
3555
+ // Global Rotation
3717
3556
  const lParentGRM = new THREE.Matrix4();
3718
- lParentGRM.extractRotation( lParentGX ); // Global Shear*Scaling
3557
+ lParentGRM.extractRotation( lParentGX );
3719
3558
 
3559
+ // Global Shear*Scaling
3720
3560
  const lParentTM = new THREE.Matrix4();
3721
3561
  lParentTM.copyPosition( lParentGX );
3722
3562
  const lParentGRSM = lParentTM.clone().invert().multiply( lParentGX );
3723
3563
  const lParentGSM = lParentGRM.clone().invert().multiply( lParentGRSM );
3724
3564
  const lLSM = lScalingM;
3725
3565
  const lGlobalRS = new THREE.Matrix4();
3726
-
3727
3566
  if ( inheritType === 0 ) {
3728
3567
 
3729
3568
  lGlobalRS.copy( lParentGRM ).multiply( lLRM ).multiply( lParentGSM ).multiply( lLSM );
@@ -3742,29 +3581,35 @@
3742
3581
  }
3743
3582
 
3744
3583
  const lRotationPivotM_inv = lRotationPivotM.clone().invert();
3745
- const lScalingPivotM_inv = lScalingPivotM.clone().invert(); // Calculate the local transform matrix
3746
-
3584
+ const lScalingPivotM_inv = lScalingPivotM.clone().invert();
3585
+ // Calculate the local transform matrix
3747
3586
  let lTransform = lTranslationM.clone().multiply( lRotationOffsetM ).multiply( lRotationPivotM ).multiply( lPreRotationM ).multiply( lRotationM ).multiply( lPostRotationM ).multiply( lRotationPivotM_inv ).multiply( lScalingOffsetM ).multiply( lScalingPivotM ).multiply( lScalingM ).multiply( lScalingPivotM_inv );
3748
3587
  const lLocalTWithAllPivotAndOffsetInfo = new THREE.Matrix4().copyPosition( lTransform );
3749
3588
  const lGlobalTranslation = lParentGX.clone().multiply( lLocalTWithAllPivotAndOffsetInfo );
3750
3589
  lGlobalT.copyPosition( lGlobalTranslation );
3751
- lTransform = lGlobalT.clone().multiply( lGlobalRS ); // from global to local
3590
+ lTransform = lGlobalT.clone().multiply( lGlobalRS );
3752
3591
 
3592
+ // from global to local
3753
3593
  lTransform.premultiply( lParentGX.invert() );
3754
3594
  return lTransform;
3755
3595
 
3756
- } // Returns the three.js intrinsic THREE.Euler order corresponding to FBX extrinsic THREE.Euler order
3757
- // ref: http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html
3758
-
3596
+ }
3759
3597
 
3598
+ // Returns the three.js intrinsic THREE.Euler order corresponding to FBX extrinsic THREE.Euler order
3599
+ // ref: http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html
3760
3600
  function getEulerOrder( order ) {
3761
3601
 
3762
3602
  order = order || 0;
3763
- const enums = [ 'ZYX', // -> XYZ extrinsic
3764
- 'YZX', // -> XZY extrinsic
3765
- 'XZY', // -> YZX extrinsic
3766
- 'ZXY', // -> YXZ extrinsic
3767
- 'YXZ', // -> ZXY extrinsic
3603
+ const enums = [ 'ZYX',
3604
+ // -> XYZ extrinsic
3605
+ 'YZX',
3606
+ // -> XZY extrinsic
3607
+ 'XZY',
3608
+ // -> YZX extrinsic
3609
+ 'ZXY',
3610
+ // -> YXZ extrinsic
3611
+ 'YXZ',
3612
+ // -> ZXY extrinsic
3768
3613
  'XYZ' // -> ZYX extrinsic
3769
3614
  //'SphericXYZ', // not possible to support
3770
3615
  ];
@@ -3778,10 +3623,10 @@
3778
3623
 
3779
3624
  return enums[ order ];
3780
3625
 
3781
- } // Parses comma separated list of numbers and returns them an array.
3782
- // Used internally by the TextParser
3783
-
3626
+ }
3784
3627
 
3628
+ // Parses comma separated list of numbers and returns them an array.
3629
+ // Used internally by the TextParser
3785
3630
  function parseNumberArray( value ) {
3786
3631
 
3787
3632
  const array = value.split( ',' ).map( function ( val ) {
@@ -3821,9 +3666,9 @@
3821
3666
 
3822
3667
  return a;
3823
3668
 
3824
- } // inject array a2 into array a1 at index
3825
-
3669
+ }
3826
3670
 
3671
+ // inject array a2 into array a1 at index
3827
3672
  function inject( a1, index, a2 ) {
3828
3673
 
3829
3674
  return a1.slice( 0, index ).concat( a2 ).concat( a1.slice( index ) );