@needle-tools/three 0.145.2 → 0.146.1
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.
- package/README.md +1 -1
- package/build/three.cjs +3559 -6924
- package/build/three.js +3559 -6924
- package/build/three.min.js +1 -2
- package/build/three.module.js +732 -339
- package/examples/js/animation/AnimationClipCreator.js +0 -8
- package/examples/js/animation/CCDIKSolver.js +49 -66
- package/examples/js/animation/MMDAnimationHelper.js +66 -137
- package/examples/js/animation/MMDPhysics.js +70 -134
- package/examples/js/cameras/CinematicCamera.js +33 -22
- package/examples/js/controls/ArcballControls.js +138 -405
- package/examples/js/controls/DragControls.js +8 -33
- package/examples/js/controls/FirstPersonControls.js +32 -54
- package/examples/js/controls/FlyControls.js +29 -55
- package/examples/js/controls/OrbitControls.js +85 -95
- package/examples/js/controls/PointerLockControls.js +5 -14
- package/examples/js/controls/TrackballControls.js +33 -86
- package/examples/js/controls/TransformControls.js +84 -169
- package/examples/js/csm/CSM.js +4 -39
- package/examples/js/csm/CSMFrustum.js +3 -9
- package/examples/js/csm/CSMHelper.js +24 -4
- package/examples/js/csm/CSMShader.js +2 -6
- package/examples/js/curves/CurveExtras.js +27 -27
- package/examples/js/curves/NURBSCurve.js +4 -16
- package/examples/js/curves/NURBSSurface.js +3 -9
- package/examples/js/curves/NURBSUtils.js +8 -45
- package/examples/js/effects/AnaglyphEffect.js +4 -18
- package/examples/js/effects/AsciiEffect.js +32 -31
- package/examples/js/effects/OutlineEffect.js +26 -30
- package/examples/js/effects/ParallaxBarrierEffect.js +0 -13
- package/examples/js/effects/PeppersGhostEffect.js +12 -39
- package/examples/js/effects/StereoEffect.js +0 -4
- package/examples/js/environments/RoomEnvironment.js +12 -10
- package/examples/js/exporters/ColladaExporter.js +48 -65
- package/examples/js/exporters/DRACOExporter.js +22 -22
- package/examples/js/exporters/EXRExporter.js +15 -18
- package/examples/js/exporters/GLTFExporter.js +143 -261
- package/examples/js/exporters/MMDExporter.js +5 -12
- package/examples/js/exporters/OBJExporter.js +42 -33
- package/examples/js/exporters/PLYExporter.js +38 -33
- package/examples/js/exporters/STLExporter.js +5 -7
- package/examples/js/exporters/USDZExporter.js +110 -25
- package/examples/js/geometries/BoxLineGeometry.js +0 -1
- package/examples/js/geometries/ConvexGeometry.js +11 -6
- package/examples/js/geometries/DecalGeometry.js +53 -20
- package/examples/js/geometries/LightningStrike.js +54 -67
- package/examples/js/geometries/ParametricGeometries.js +8 -7
- package/examples/js/geometries/ParametricGeometry.js +25 -12
- package/examples/js/geometries/RoundedBoxGeometry.js +21 -19
- package/examples/js/geometries/TeapotGeometry.js +54 -50
- package/examples/js/geometries/TextGeometry.js +6 -4
- package/examples/js/helpers/LightProbeHelper.js +1 -2
- package/examples/js/helpers/OctreeHelper.js +22 -20
- package/examples/js/helpers/PositionalAudioHelper.js +8 -6
- package/examples/js/helpers/RectAreaLightHelper.js +6 -7
- package/examples/js/helpers/VertexNormalsHelper.js +15 -13
- package/examples/js/helpers/VertexTangentsHelper.js +15 -9
- package/examples/js/helpers/ViewHelper.js +31 -16
- package/examples/js/interactive/HTMLMesh.js +22 -33
- package/examples/js/interactive/InteractiveGroup.js +6 -12
- package/examples/js/interactive/SelectionBox.js +3 -70
- package/examples/js/interactive/SelectionHelper.js +0 -8
- package/examples/js/lights/LightProbeGenerator.js +32 -39
- package/examples/js/lights/RectAreaLightUniformsLib.js +5 -1
- package/examples/js/lines/LineGeometry.js +3 -5
- package/examples/js/lines/LineMaterial.js +4 -11
- package/examples/js/lines/LineSegments2.js +38 -89
- package/examples/js/lines/LineSegmentsGeometry.js +7 -28
- package/examples/js/lines/Wireframe.js +2 -7
- package/examples/js/lines/WireframeGeometry2.js +3 -1
- package/examples/js/loaders/3DMLoader.js +58 -155
- package/examples/js/loaders/3MFLoader.js +72 -106
- package/examples/js/loaders/AMFLoader.js +0 -25
- package/examples/js/loaders/BVHLoader.js +44 -43
- package/examples/js/loaders/BasisTextureLoader.js +16 -46
- package/examples/js/loaders/ColladaLoader.js +201 -359
- package/examples/js/loaders/DDSLoader.js +24 -25
- package/examples/js/loaders/DRACOLoader.js +29 -66
- package/examples/js/loaders/EXRLoader.js +67 -164
- package/examples/js/loaders/FBXLoader.js +286 -441
- package/examples/js/loaders/FontLoader.js +6 -15
- package/examples/js/loaders/GCodeLoader.js +15 -16
- package/examples/js/loaders/GLTFLoader.js +354 -405
- package/examples/js/loaders/HDRCubeTextureLoader.js +0 -6
- package/examples/js/loaders/KMZLoader.js +3 -7
- package/examples/js/loaders/KTXLoader.js +12 -30
- package/examples/js/loaders/LDrawLoader.js +178 -289
- package/examples/js/loaders/LUT3dlLoader.js +7 -11
- package/examples/js/loaders/LUTCubeLoader.js +0 -8
- package/examples/js/loaders/LWOLoader.js +59 -124
- package/examples/js/loaders/LogLuvLoader.js +27 -77
- package/examples/js/loaders/LottieLoader.js +4 -4
- package/examples/js/loaders/MD2Loader.js +26 -27
- package/examples/js/loaders/MDDLoader.js +6 -10
- package/examples/js/loaders/MMDLoader.js +180 -189
- package/examples/js/loaders/MTLLoader.js +18 -47
- package/examples/js/loaders/MaterialXLoader.js +392 -0
- package/examples/js/loaders/NRRDLoader.js +44 -84
- package/examples/js/loaders/OBJLoader.js +50 -65
- package/examples/js/loaders/PCDLoader.js +34 -29
- package/examples/js/loaders/PDBLoader.js +17 -13
- package/examples/js/loaders/PLYLoader.js +9 -39
- package/examples/js/loaders/PRWMLoader.js +11 -22
- package/examples/js/loaders/PVRLoader.js +7 -16
- package/examples/js/loaders/RGBELoader.js +36 -61
- package/examples/js/loaders/RGBMLoader.js +26 -87
- package/examples/js/loaders/STLLoader.js +20 -27
- package/examples/js/loaders/SVGLoader.js +361 -233
- package/examples/js/loaders/TDSLoader.js +81 -118
- package/examples/js/loaders/TGALoader.js +39 -41
- package/examples/js/loaders/TIFFLoader.js +0 -1
- package/examples/js/loaders/TTFLoader.js +0 -8
- package/examples/js/loaders/TiltLoader.js +14 -15
- package/examples/js/loaders/VOXLoader.js +8 -16
- package/examples/js/loaders/VRMLLoader.js +243 -340
- package/examples/js/loaders/VTKLoader.js +101 -118
- package/examples/js/loaders/XYZLoader.js +2 -4
- package/examples/js/loaders/lwo/IFFParser.js +55 -136
- package/examples/js/loaders/lwo/LWO2Parser.js +32 -83
- package/examples/js/loaders/lwo/LWO3Parser.js +31 -73
- package/examples/js/materials/MeshGouraudMaterial.js +15 -13
- package/examples/js/math/Capsule.js +0 -17
- package/examples/js/math/ColorConverter.js +3 -3
- package/examples/js/math/ConvexHull.js +183 -139
- package/examples/js/math/ImprovedNoise.js +1 -1
- package/examples/js/math/Lut.js +8 -15
- package/examples/js/math/MeshSurfaceSampler.js +6 -28
- package/examples/js/math/OBB.js +90 -49
- package/examples/js/math/Octree.js +2 -57
- package/examples/js/math/SimplexNoise.js +74 -88
- package/examples/js/misc/ConvexObjectBreaker.js +37 -48
- package/examples/js/misc/GPUComputationRenderer.js +14 -18
- package/examples/js/misc/Gyroscope.js +5 -9
- package/examples/js/misc/MD2Character.js +14 -23
- package/examples/js/misc/MD2CharacterComplex.js +73 -54
- package/examples/js/misc/MorphAnimMesh.js +0 -6
- package/examples/js/misc/MorphBlendMesh.js +3 -30
- package/examples/js/misc/ProgressiveLightMap.js +47 -43
- package/examples/js/misc/RollerCoaster.js +17 -24
- package/examples/js/misc/TubePainter.js +18 -12
- package/examples/js/misc/Volume.js +16 -45
- package/examples/js/misc/VolumeSlice.js +14 -24
- package/examples/js/modifiers/CurveModifier.js +19 -21
- package/examples/js/modifiers/EdgeSplitModifier.js +0 -30
- package/examples/js/modifiers/SimplifyModifier.js +56 -59
- package/examples/js/modifiers/TessellateModifier.js +2 -9
- package/examples/js/objects/GroundProjectedEnv.js +2 -14
- package/examples/js/objects/Lensflare.js +47 -38
- package/examples/js/objects/LightningStorm.js +10 -13
- package/examples/js/objects/MarchingCubes.js +80 -59
- package/examples/js/objects/Reflector.js +22 -20
- package/examples/js/objects/ReflectorForSSRPass.js +19 -23
- package/examples/js/objects/Refractor.js +52 -30
- package/examples/js/objects/ShadowMesh.js +1 -2
- package/examples/js/objects/Sky.js +2 -7
- package/examples/js/objects/Water.js +23 -18
- package/examples/js/objects/Water2.js +20 -19
- package/examples/js/physics/AmmoPhysics.js +23 -20
- package/examples/js/physics/OimoPhysics.js +19 -17
- package/examples/js/postprocessing/AdaptiveToneMappingPass.js +13 -20
- package/examples/js/postprocessing/AfterimagePass.js +19 -12
- package/examples/js/postprocessing/BloomPass.js +38 -17
- package/examples/js/postprocessing/BokehPass.js +29 -12
- package/examples/js/postprocessing/ClearPass.js +1 -6
- package/examples/js/postprocessing/CubeTexturePass.js +12 -9
- package/examples/js/postprocessing/DotScreenPass.js +7 -5
- package/examples/js/postprocessing/EffectComposer.js +25 -32
- package/examples/js/postprocessing/FilmPass.js +7 -5
- package/examples/js/postprocessing/GlitchPass.js +10 -11
- package/examples/js/postprocessing/HalftonePass.js +9 -9
- package/examples/js/postprocessing/LUTPass.js +2 -15
- package/examples/js/postprocessing/MaskPass.js +20 -17
- package/examples/js/postprocessing/OutlinePass.js +45 -36
- package/examples/js/postprocessing/Pass.js +11 -14
- package/examples/js/postprocessing/RenderPass.js +3 -7
- package/examples/js/postprocessing/SAOPass.js +40 -32
- package/examples/js/postprocessing/SMAAPass.js +34 -17
- package/examples/js/postprocessing/SSAARenderPass.js +14 -14
- package/examples/js/postprocessing/SSAOPass.js +56 -42
- package/examples/js/postprocessing/SSRPass.js +78 -61
- package/examples/js/postprocessing/SavePass.js +14 -6
- package/examples/js/postprocessing/ShaderPass.js +9 -8
- package/examples/js/postprocessing/TAARenderPass.js +11 -9
- package/examples/js/postprocessing/TexturePass.js +7 -4
- package/examples/js/postprocessing/UnrealBloomPass.js +43 -25
- package/examples/js/renderers/CSS2DRenderer.js +2 -21
- package/examples/js/renderers/CSS3DRenderer.js +3 -24
- package/examples/js/renderers/Projector.js +29 -85
- package/examples/js/renderers/SVGRenderer.js +4 -50
- package/examples/js/shaders/ACESFilmicToneMappingShader.js +3 -6
- package/examples/js/shaders/AfterimageShader.js +3 -6
- package/examples/js/shaders/BasicShader.js +3 -6
- package/examples/js/shaders/BleachBypassShader.js +3 -6
- package/examples/js/shaders/BlendShader.js +3 -6
- package/examples/js/shaders/BokehShader.js +3 -6
- package/examples/js/shaders/BokehShader2.js +4 -13
- package/examples/js/shaders/BrightnessContrastShader.js +3 -6
- package/examples/js/shaders/ColorCorrectionShader.js +2 -6
- package/examples/js/shaders/ColorifyShader.js +2 -6
- package/examples/js/shaders/ConvolutionShader.js +5 -10
- package/examples/js/shaders/CopyShader.js +3 -6
- package/examples/js/shaders/DOFMipMapShader.js +3 -6
- package/examples/js/shaders/DepthLimitedBlurShader.js +2 -9
- package/examples/js/shaders/DigitalGlitch.js +3 -6
- package/examples/js/shaders/DotScreenShader.js +2 -6
- package/examples/js/shaders/FXAAShader.js +1 -3
- package/examples/js/shaders/FilmShader.js +3 -6
- package/examples/js/shaders/FocusShader.js +3 -6
- package/examples/js/shaders/FreiChenShader.js +2 -6
- package/examples/js/shaders/GammaCorrectionShader.js +3 -6
- package/examples/js/shaders/GodRaysShader.js +11 -24
- package/examples/js/shaders/HalftoneShader.js +3 -6
- package/examples/js/shaders/HorizontalBlurShader.js +3 -6
- package/examples/js/shaders/HorizontalTiltShiftShader.js +3 -6
- package/examples/js/shaders/HueSaturationShader.js +3 -6
- package/examples/js/shaders/KaleidoShader.js +3 -6
- package/examples/js/shaders/LuminosityHighPassShader.js +2 -6
- package/examples/js/shaders/LuminosityShader.js +3 -6
- package/examples/js/shaders/MMDToonShader.js +2 -6
- package/examples/js/shaders/MirrorShader.js +3 -6
- package/examples/js/shaders/NormalMapShader.js +2 -6
- package/examples/js/shaders/RGBShiftShader.js +3 -6
- package/examples/js/shaders/SAOShader.js +2 -6
- package/examples/js/shaders/SMAAShader.js +6 -18
- package/examples/js/shaders/SSAOShader.js +2 -6
- package/examples/js/shaders/SSRShader.js +6 -18
- package/examples/js/shaders/SepiaShader.js +3 -6
- package/examples/js/shaders/SobelOperatorShader.js +2 -6
- package/examples/js/shaders/TechnicolorShader.js +3 -6
- package/examples/js/shaders/ToneMapShader.js +3 -6
- package/examples/js/shaders/ToonShader.js +8 -24
- package/examples/js/shaders/TriangleBlurShader.js +2 -6
- package/examples/js/shaders/UnpackDepthRGBAShader.js +3 -6
- package/examples/js/shaders/VelocityShader.js +126 -0
- package/examples/js/shaders/VerticalBlurShader.js +3 -6
- package/examples/js/shaders/VerticalTiltShiftShader.js +3 -6
- package/examples/js/shaders/VignetteShader.js +3 -6
- package/examples/js/shaders/VolumeShader.js +2 -6
- package/examples/js/shaders/WaterRefractionShader.js +2 -6
- package/examples/js/textures/FlakesTexture.js +0 -1
- package/examples/js/utils/BufferGeometryUtils.js +234 -168
- package/examples/js/utils/CameraUtils.js +5 -20
- package/examples/js/utils/GPUStatsPanel.js +3 -12
- package/examples/js/utils/GeometryCompressionUtils.js +19 -44
- package/examples/js/utils/GeometryUtils.js +13 -18
- package/examples/js/utils/LDrawUtils.js +8 -11
- package/examples/js/utils/PackedPhongMaterial.js +6 -4
- package/examples/js/utils/SceneUtils.js +117 -6
- package/examples/js/utils/ShadowMapViewer.js +17 -14
- package/examples/js/utils/SkeletonUtils.js +13 -27
- package/examples/js/utils/UVsDebug.js +20 -12
- package/examples/js/utils/WorkerPool.js +1 -11
- package/examples/jsm/animation/CCDIKSolver.js +1 -1
- package/examples/jsm/capabilities/WebGPU.js +3 -1
- package/examples/jsm/controls/OrbitControls.js +44 -4
- package/examples/jsm/exporters/GLTFExporter.js +17 -131
- package/examples/jsm/exporters/USDZExporter.js +94 -28
- package/examples/jsm/interactive/HTMLMesh.js +2 -0
- package/examples/jsm/libs/lottie_canvas.module.js +14844 -0
- package/examples/jsm/loaders/3DMLoader.js +1 -2
- package/examples/jsm/loaders/ColladaLoader.js +28 -0
- package/examples/jsm/loaders/FBXLoader.js +16 -2
- package/examples/jsm/loaders/GLTFLoader.js +204 -377
- package/examples/jsm/loaders/KTX2Loader.js +68 -29
- package/examples/jsm/loaders/LDrawLoader.js +14 -13
- package/examples/jsm/loaders/LottieLoader.js +4 -2
- package/examples/jsm/loaders/MaterialXLoader.js +728 -0
- package/examples/jsm/loaders/PCDLoader.js +1 -1
- package/examples/jsm/loaders/PLYLoader.js +68 -16
- package/examples/jsm/loaders/SVGLoader.js +227 -14
- package/examples/jsm/loaders/USDZLoader.js +31 -16
- package/examples/jsm/nodes/Nodes.js +14 -2
- package/examples/jsm/nodes/accessors/Object3DNode.js +1 -1
- package/examples/jsm/nodes/accessors/PositionNode.js +6 -0
- package/examples/jsm/nodes/accessors/ReferenceNode.js +1 -1
- package/examples/jsm/nodes/accessors/SkinningNode.js +1 -1
- package/examples/jsm/nodes/core/Node.js +1 -1
- package/examples/jsm/nodes/core/NodeBuilder.js +36 -4
- package/examples/jsm/nodes/core/NodeFrame.js +2 -2
- package/examples/jsm/nodes/core/NodeVarying.js +7 -4
- package/examples/jsm/nodes/core/VaryingNode.js +6 -4
- package/examples/jsm/nodes/core/constants.js +13 -13
- package/examples/jsm/nodes/display/PosterizeNode.js +25 -0
- package/examples/jsm/nodes/display/ViewportNode.js +106 -0
- package/examples/jsm/nodes/gpgpu/ComputeNode.js +1 -1
- package/examples/jsm/nodes/lighting/AnalyticLightNode.js +1 -1
- package/examples/jsm/nodes/loaders/NodeMaterialLoader.js +3 -1
- package/examples/jsm/nodes/materials/Materials.js +9 -7
- package/examples/jsm/nodes/materials/NodeMaterial.js +9 -1
- package/examples/jsm/nodes/materialx/MaterialXNodes.js +6 -2
- package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +18 -0
- package/examples/jsm/nodes/math/MathNode.js +5 -0
- package/examples/jsm/nodes/math/OperatorNode.js +6 -1
- package/examples/jsm/nodes/shadernode/ShaderNode.js +26 -13
- package/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js +2 -0
- package/examples/jsm/nodes/shadernode/ShaderNodeElements.js +18 -0
- package/examples/jsm/nodes/utils/EquirectUVNode.js +27 -0
- package/examples/jsm/nodes/utils/JoinNode.js +8 -2
- package/examples/jsm/nodes/utils/MatcapUVNode.js +2 -4
- package/examples/jsm/nodes/utils/MaxMipLevelNode.js +1 -1
- package/examples/jsm/nodes/utils/SpriteSheetUVNode.js +8 -10
- package/examples/jsm/nodes/utils/TimerNode.js +1 -1
- package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +51 -0
- package/examples/jsm/postprocessing/AfterimagePass.js +17 -4
- package/examples/jsm/postprocessing/BloomPass.js +22 -3
- package/examples/jsm/postprocessing/BokehPass.js +18 -4
- package/examples/jsm/postprocessing/CubeTexturePass.js +12 -5
- package/examples/jsm/postprocessing/DotScreenPass.js +8 -0
- package/examples/jsm/postprocessing/EffectComposer.js +9 -0
- package/examples/jsm/postprocessing/FilmPass.js +8 -0
- package/examples/jsm/postprocessing/GlitchPass.js +13 -1
- package/examples/jsm/postprocessing/HalftonePass.js +8 -0
- package/examples/jsm/postprocessing/OutlinePass.js +10 -0
- package/examples/jsm/postprocessing/Pass.js +2 -0
- package/examples/jsm/postprocessing/RenderPixelatedPass.js +234 -0
- package/examples/jsm/postprocessing/SAOPass.js +20 -0
- package/examples/jsm/postprocessing/SMAAPass.js +16 -0
- package/examples/jsm/postprocessing/SSAARenderPass.js +4 -0
- package/examples/jsm/postprocessing/SavePass.js +17 -1
- package/examples/jsm/postprocessing/ShaderPass.js +8 -0
- package/examples/jsm/postprocessing/TAARenderPass.js +9 -0
- package/examples/jsm/postprocessing/TexturePass.js +8 -0
- package/examples/jsm/postprocessing/UnrealBloomPass.js +16 -0
- package/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +39 -16
- package/examples/jsm/renderers/webgpu/WebGPUAnimation.js +58 -0
- package/examples/jsm/renderers/webgpu/WebGPUAttributes.js +63 -5
- package/examples/jsm/renderers/webgpu/WebGPUBackground.js +36 -7
- package/examples/jsm/renderers/webgpu/WebGPURenderer.js +47 -12
- package/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js +35 -5
- package/examples/jsm/shaders/MMDToonShader.js +0 -2
- package/examples/jsm/shaders/VelocityShader.js +128 -0
- package/examples/jsm/utils/BufferGeometryUtils.js +130 -6
- package/examples/jsm/utils/SceneUtils.js +129 -4
- package/examples/jsm/utils/TextureUtils.js +85 -0
- package/examples/jsm/webxr/OculusHandModel.js +1 -1
- package/examples/jsm/webxr/XRHandMeshModel.js +6 -3
- package/package.json +11 -12
- package/src/Three.js +1 -0
- package/src/audio/AudioContext.js +5 -5
- package/src/cameras/CubeCamera.js +14 -14
- package/src/constants.js +1 -1
- package/src/core/InstancedBufferGeometry.js +1 -7
- package/src/extras/Earcut.js +67 -67
- package/src/helpers/DirectionalLightHelper.js +5 -1
- package/src/helpers/HemisphereLightHelper.js +4 -1
- package/src/helpers/PointLightHelper.js +2 -1
- package/src/helpers/SpotLightHelper.js +4 -2
- package/src/lights/PointLight.js +2 -2
- package/src/lights/SpotLight.js +2 -2
- package/src/loaders/FileLoader.js +4 -1
- package/src/loaders/ObjectLoader.js +5 -1
- package/src/materials/Material.js +1 -1
- package/src/math/Color.js +5 -5
- package/src/math/Matrix3.js +53 -18
- package/src/math/Ray.js +2 -5
- package/src/math/Sphere.js +19 -26
- package/src/objects/InstancedMesh.js +7 -0
- package/src/objects/LOD.js +25 -6
- package/src/renderers/WebGL3DRenderTarget.js +1 -1
- package/src/renderers/WebGLArrayRenderTarget.js +1 -1
- package/src/renderers/WebGLCubeRenderTarget.js +1 -1
- package/src/renderers/WebGLMultipleRenderTargets.js +1 -1
- package/src/renderers/WebGLRenderTarget.js +1 -1
- package/src/renderers/WebGLRenderer.js +36 -62
- package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +0 -4
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +0 -1
- package/src/renderers/shaders/ShaderChunk/lights_lambert_pars_fragment.glsl.js +0 -2
- package/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl.js +0 -2
- package/src/renderers/shaders/ShaderChunk/lights_toon_pars_fragment.glsl.js +0 -2
- package/src/renderers/shaders/ShaderChunk/packing.glsl.js +8 -0
- package/src/renderers/shaders/ShaderChunk.js +3 -0
- package/src/renderers/shaders/ShaderLib/background.glsl.js +7 -2
- package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +62 -0
- package/src/renderers/shaders/ShaderLib/cube.glsl.js +4 -6
- package/src/renderers/shaders/ShaderLib.js +20 -6
- package/src/renderers/shaders/UniformsLib.js +1 -1
- package/src/renderers/shaders/UniformsUtils.js +15 -0
- package/src/renderers/webgl/WebGLAttributes.js +2 -0
- package/src/renderers/webgl/WebGLBackground.js +15 -7
- package/src/renderers/webgl/WebGLCubeUVMaps.js +1 -1
- package/src/renderers/webgl/WebGLLights.js +0 -4
- package/src/renderers/webgl/WebGLMaterials.js +2 -1
- package/src/renderers/webgl/WebGLShadowMap.js +3 -1
- package/src/renderers/webgl/WebGLState.js +31 -1
- package/src/renderers/webgl/WebGLTextures.js +71 -18
- package/src/renderers/webgl/WebGLUniforms.js +116 -20
- package/src/renderers/webgl/WebGLUtils.js +1 -1
- package/src/renderers/webxr/WebXRController.js +46 -13
- package/src/renderers/webxr/WebXRManager.js +85 -3
- package/src/scenes/Scene.js +8 -0
- package/src/textures/CompressedArrayTexture.js +18 -0
- package/examples/js/libs/lottie_canvas.js +0 -12751
- package/examples/js/shaders/PixelShader.js +0 -51
- 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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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 )
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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();
|
|
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
|
-
}
|
|
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 );
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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;
|
|
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
|
-
}
|
|
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 = [];
|
|
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 );
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
} );
|
|
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
|
-
} );
|
|
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
|
-
}
|
|
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 ) );
|
|
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();
|
|
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
|
-
} );
|
|
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
|
-
}
|
|
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;
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
|
|
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;
|
|
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
|
-
}
|
|
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 = [];
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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 );
|
|
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();
|
|
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;
|
|
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
|
-
}
|
|
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;
|
|
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
|
-
}
|
|
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 = [];
|
|
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 );
|
|
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
|
-
} );
|
|
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 );
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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();
|
|
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();
|
|
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
|
-
}
|
|
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
|
-
}
|
|
2898
|
-
|
|
2790
|
+
}
|
|
2899
2791
|
|
|
2900
|
-
|
|
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 );
|
|
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;
|
|
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
|
-
}
|
|
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 ];
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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 = {};
|
|
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 );
|
|
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
|
-
}
|
|
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 ] : '';
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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 = [];
|
|
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();
|
|
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 ) );
|
|
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 ) );
|
|
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 );
|
|
3716
|
-
|
|
3554
|
+
const lLRM = lPreRotationM.clone().multiply( lRotationM ).multiply( lPostRotationM );
|
|
3555
|
+
// Global Rotation
|
|
3717
3556
|
const lParentGRM = new THREE.Matrix4();
|
|
3718
|
-
lParentGRM.extractRotation( lParentGX );
|
|
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();
|
|
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 );
|
|
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
|
-
}
|
|
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',
|
|
3764
|
-
|
|
3765
|
-
'
|
|
3766
|
-
|
|
3767
|
-
'
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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 ) );
|