@needle-tools/three 0.146.10 → 0.153.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/LICENSE +1 -1
- package/build/three.cjs +40124 -20919
- package/build/three.js +40120 -20914
- package/build/three.min.js +8 -6
- package/build/three.module.js +7298 -6003
- package/build/three.module.min.js +7 -0
- package/examples/jsm/animation/AnimationClipCreator.js +5 -3
- package/examples/jsm/cameras/CinematicCamera.js +1 -2
- package/examples/jsm/capabilities/WebGPU.js +17 -5
- package/examples/jsm/controls/ArcballControls.js +1828 -1821
- package/examples/jsm/controls/MapControls.js +28 -0
- package/examples/jsm/controls/OrbitControls.js +26 -53
- package/examples/jsm/controls/PointerLockControls.js +70 -65
- package/examples/jsm/controls/TrackballControls.js +18 -4
- package/examples/jsm/controls/TransformControls.js +0 -1
- package/examples/jsm/csm/CSM.js +11 -5
- package/examples/jsm/csm/CSMShader.js +7 -6
- package/examples/jsm/effects/AnaglyphEffect.js +6 -20
- package/examples/jsm/effects/AsciiEffect.js +3 -6
- package/examples/jsm/effects/OutlineEffect.js +1 -15
- package/examples/jsm/effects/ParallaxBarrierEffect.js +3 -0
- package/examples/jsm/exporters/DRACOExporter.js +53 -11
- package/examples/jsm/exporters/EXRExporter.js +3 -9
- package/examples/jsm/exporters/GLTFExporter.js +561 -154
- package/examples/jsm/exporters/KTX2Exporter.js +34 -23
- package/examples/jsm/exporters/MMDExporter.js +1 -1
- package/examples/jsm/exporters/PLYExporter.js +8 -1
- package/examples/jsm/exporters/STLExporter.js +8 -4
- package/examples/jsm/exporters/USDZExporter.js +305 -792
- package/examples/jsm/geometries/ConvexGeometry.js +0 -6
- package/examples/jsm/geometries/ParametricGeometry.js +10 -0
- package/examples/jsm/helpers/OctreeHelper.js +1 -0
- package/examples/jsm/helpers/ViewHelper.js +71 -57
- package/examples/jsm/interactive/HTMLMesh.js +16 -3
- package/examples/jsm/interactive/InteractiveGroup.js +1 -1
- package/examples/{js → jsm}/libs/basis/README.md +4 -4
- package/examples/jsm/libs/draco/draco_decoder.js +34 -0
- package/examples/jsm/libs/draco/draco_decoder.wasm +0 -0
- package/examples/jsm/libs/draco/draco_wasm_wrapper.js +117 -0
- package/examples/jsm/libs/draco/gltf/draco_decoder.js +33 -0
- package/examples/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
- package/examples/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/examples/jsm/libs/lil-gui.module.min.js +2 -2
- package/examples/jsm/libs/tween.module.js +803 -0
- package/examples/jsm/lights/IESSpotLight.js +25 -0
- package/examples/jsm/lights/LightProbeGenerator.js +11 -9
- package/examples/jsm/lines/LineSegments2.js +16 -10
- package/examples/jsm/loaders/3DMLoader.js +8 -5
- package/examples/jsm/loaders/3MFLoader.js +12 -11
- package/examples/jsm/loaders/AMFLoader.js +2 -3
- package/examples/jsm/loaders/BVHLoader.js +2 -2
- package/examples/jsm/loaders/ColladaLoader.js +15 -16
- package/examples/jsm/loaders/DRACOLoader.js +69 -18
- package/examples/jsm/loaders/EXRLoader.js +23 -24
- package/examples/jsm/loaders/FBXLoader.js +34 -50
- package/examples/jsm/loaders/GCodeLoader.js +1 -2
- package/examples/jsm/loaders/GLTFLoader.js +417 -895
- package/examples/jsm/loaders/GLTFLoaderAnimationPointer.js +684 -0
- package/examples/jsm/loaders/HDRCubeTextureLoader.js +4 -4
- package/examples/jsm/loaders/IESLoader.js +337 -0
- package/examples/jsm/loaders/KMZLoader.js +4 -4
- package/examples/jsm/loaders/KTX2Loader.js +145 -69
- package/examples/jsm/loaders/LDrawLoader.js +20 -18
- package/examples/jsm/loaders/LWOLoader.js +12 -29
- package/examples/jsm/loaders/LottieLoader.js +3 -1
- package/examples/jsm/loaders/MMDLoader.js +49 -18
- package/examples/jsm/loaders/MTLLoader.js +2 -2
- package/examples/jsm/loaders/MaterialXLoader.js +9 -3
- package/examples/jsm/loaders/NRRDLoader.js +33 -5
- package/examples/jsm/loaders/OBJLoader.js +1 -1
- package/examples/jsm/loaders/PCDLoader.js +26 -12
- package/examples/jsm/loaders/PDBLoader.js +7 -2
- package/examples/jsm/loaders/PLYLoader.js +254 -109
- package/examples/jsm/loaders/RGBELoader.js +3 -3
- package/examples/jsm/loaders/STLLoader.js +9 -5
- package/examples/jsm/loaders/SVGLoader.js +36 -27
- package/examples/jsm/loaders/TTFLoader.js +1 -8
- package/examples/jsm/loaders/TiltLoader.js +13 -7
- package/examples/jsm/loaders/USDZLoader.js +6 -6
- package/examples/jsm/loaders/VOXLoader.js +8 -2
- package/examples/jsm/loaders/VRMLLoader.js +44 -16
- package/examples/jsm/loaders/VTKLoader.js +19 -10
- package/examples/jsm/loaders/XYZLoader.js +9 -3
- package/examples/jsm/loaders/lwo/IFFParser.js +19 -19
- package/examples/jsm/materials/MeshGouraudMaterial.js +0 -3
- package/examples/jsm/math/ConvexHull.js +3 -3
- package/examples/jsm/math/Lut.js +5 -4
- package/examples/jsm/math/MeshSurfaceSampler.js +7 -9
- package/examples/jsm/math/Octree.js +1 -1
- package/examples/jsm/misc/ConvexObjectBreaker.js +2 -8
- package/examples/jsm/misc/GPUComputationRenderer.js +6 -5
- package/examples/jsm/misc/MD2Character.js +2 -2
- package/examples/jsm/misc/MD2CharacterComplex.js +2 -2
- package/examples/jsm/misc/ProgressiveLightMap.js +12 -10
- package/examples/jsm/misc/RollerCoaster.js +7 -1
- package/examples/jsm/misc/Volume.js +20 -5
- package/examples/jsm/misc/VolumeSlice.js +3 -1
- package/examples/jsm/modifiers/CurveModifier.js +1 -0
- package/examples/jsm/modifiers/TessellateModifier.js +19 -19
- package/examples/jsm/nodes/Nodes.js +144 -335
- package/examples/jsm/nodes/accessors/BitangentNode.js +43 -16
- package/examples/jsm/nodes/accessors/BufferAttributeNode.js +86 -0
- package/examples/jsm/nodes/accessors/BufferNode.js +6 -0
- package/examples/jsm/nodes/accessors/CameraNode.js +12 -2
- package/examples/jsm/nodes/accessors/CubeTextureNode.js +27 -33
- package/examples/jsm/nodes/accessors/ExtendedMaterialNode.js +58 -0
- package/examples/jsm/nodes/accessors/InstanceNode.js +41 -26
- package/examples/jsm/nodes/accessors/MaterialNode.js +155 -38
- package/examples/jsm/nodes/accessors/MaterialReferenceNode.js +16 -0
- package/examples/jsm/nodes/accessors/ModelNode.js +11 -0
- package/examples/jsm/nodes/accessors/ModelViewProjectionNode.js +13 -14
- package/examples/jsm/nodes/accessors/NormalNode.js +35 -19
- package/examples/jsm/nodes/accessors/Object3DNode.js +32 -12
- package/examples/jsm/nodes/accessors/PointUVNode.js +6 -1
- package/examples/jsm/nodes/accessors/PositionNode.js +38 -23
- package/examples/jsm/nodes/accessors/ReferenceNode.js +21 -14
- package/examples/jsm/nodes/accessors/ReflectVectorNode.js +11 -7
- package/examples/jsm/nodes/accessors/SkinningNode.js +43 -40
- package/examples/jsm/nodes/accessors/StorageBufferNode.js +6 -0
- package/examples/jsm/nodes/accessors/TangentNode.js +28 -20
- package/examples/jsm/nodes/accessors/TextureNode.js +80 -12
- package/examples/jsm/nodes/accessors/UVNode.js +6 -0
- package/examples/jsm/nodes/accessors/UserDataNode.js +6 -0
- package/examples/jsm/nodes/code/CodeNode.js +75 -0
- package/examples/jsm/nodes/code/ExpressionNode.js +37 -0
- package/examples/jsm/nodes/{core → code}/FunctionCallNode.js +15 -1
- package/examples/jsm/nodes/{core → code}/FunctionNode.js +8 -7
- package/examples/jsm/nodes/code/ScriptableNode.js +488 -0
- package/examples/jsm/nodes/code/ScriptableValueNode.js +167 -0
- package/examples/jsm/nodes/core/ArrayUniformNode.js +3 -0
- package/examples/jsm/nodes/core/AttributeNode.js +17 -9
- package/examples/jsm/nodes/core/BypassNode.js +9 -2
- package/examples/jsm/nodes/core/CacheNode.js +46 -0
- package/examples/jsm/nodes/core/ConstNode.js +3 -0
- package/examples/jsm/nodes/core/ContextNode.js +8 -1
- package/examples/jsm/nodes/core/InputNode.js +26 -5
- package/examples/jsm/nodes/core/InstanceIndexNode.js +26 -2
- package/examples/jsm/nodes/core/LightingModel.js +16 -0
- package/examples/jsm/nodes/core/Node.js +129 -35
- package/examples/jsm/nodes/core/NodeAttribute.js +2 -1
- package/examples/jsm/nodes/core/NodeBuilder.js +271 -121
- package/examples/jsm/nodes/core/NodeCache.js +26 -0
- package/examples/jsm/nodes/core/NodeFrame.js +56 -5
- package/examples/jsm/nodes/core/NodeUtils.js +115 -28
- package/examples/jsm/nodes/core/PropertyNode.js +19 -2
- package/examples/jsm/nodes/core/StackNode.js +99 -0
- package/examples/jsm/nodes/core/TempNode.js +11 -3
- package/examples/jsm/nodes/core/UniformNode.js +16 -1
- package/examples/jsm/nodes/core/VarNode.js +21 -29
- package/examples/jsm/nodes/core/VaryingNode.js +15 -2
- package/examples/jsm/nodes/core/constants.js +6 -0
- package/examples/jsm/nodes/display/BlendModeNode.js +25 -11
- package/examples/jsm/nodes/display/ColorAdjustmentNode.js +30 -14
- package/examples/jsm/nodes/display/ColorSpaceNode.js +39 -27
- package/examples/jsm/nodes/display/FrontFacingNode.js +7 -1
- package/examples/jsm/nodes/display/NormalMapNode.js +31 -18
- package/examples/jsm/nodes/display/PosterizeNode.js +10 -3
- package/examples/jsm/nodes/display/ToneMappingNode.js +101 -11
- package/examples/jsm/nodes/display/ViewportNode.js +27 -18
- package/examples/jsm/nodes/display/ViewportSharedTextureNode.js +30 -0
- package/examples/jsm/nodes/display/ViewportTextureNode.js +67 -0
- package/examples/jsm/nodes/fog/FogExp2Node.js +35 -0
- package/examples/jsm/nodes/fog/FogNode.js +12 -6
- package/examples/jsm/nodes/fog/FogRangeNode.js +12 -5
- package/examples/jsm/nodes/functions/BSDF/BRDF_BlinnPhong.js +30 -0
- package/examples/jsm/nodes/functions/BSDF/BRDF_GGX.js +10 -13
- package/examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js +2 -2
- package/examples/jsm/nodes/functions/BSDF/DFGApprox.js +8 -6
- package/examples/jsm/nodes/functions/BSDF/D_GGX.js +4 -4
- package/examples/jsm/nodes/functions/BSDF/F_Schlick.js +3 -3
- package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +7 -5
- package/examples/jsm/nodes/functions/PhongLightingModel.js +28 -0
- package/examples/jsm/nodes/functions/PhysicalLightingModel.js +35 -36
- package/examples/jsm/nodes/functions/material/getGeometryRoughness.js +4 -3
- package/examples/jsm/nodes/functions/material/getRoughness.js +4 -4
- package/examples/jsm/nodes/geometry/RangeNode.js +50 -55
- package/examples/jsm/nodes/gpgpu/ComputeNode.js +9 -2
- package/examples/jsm/nodes/lighting/AONode.js +5 -3
- package/examples/jsm/nodes/lighting/AmbientLightNode.js +27 -0
- package/examples/jsm/nodes/lighting/AnalyticLightNode.js +114 -5
- package/examples/jsm/nodes/lighting/DirectionalLightNode.js +43 -0
- package/examples/jsm/nodes/lighting/EnvironmentNode.js +121 -35
- package/examples/jsm/nodes/lighting/HemisphereLightNode.js +15 -10
- package/examples/jsm/nodes/lighting/IESSpotLightNode.js +39 -0
- package/examples/jsm/nodes/lighting/LightNode.js +57 -0
- package/examples/jsm/nodes/lighting/LightUtils.js +17 -0
- package/examples/jsm/nodes/lighting/LightingContextNode.js +30 -8
- package/examples/jsm/nodes/lighting/LightingNode.js +3 -1
- package/examples/jsm/nodes/lighting/LightsNode.js +18 -10
- package/examples/jsm/nodes/lighting/PointLightNode.js +71 -0
- package/examples/jsm/nodes/lighting/SpotLightNode.js +92 -0
- package/examples/jsm/nodes/loaders/NodeLoader.js +5 -4
- package/examples/jsm/nodes/loaders/NodeMaterialLoader.js +4 -20
- package/examples/jsm/nodes/materials/LineBasicNodeMaterial.js +6 -9
- package/examples/jsm/nodes/materials/Materials.js +11 -55
- package/examples/jsm/nodes/materials/MeshBasicNodeMaterial.js +5 -11
- package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +48 -0
- package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +74 -0
- package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +6 -6
- package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +21 -96
- package/examples/jsm/nodes/materials/NodeMaterial.js +284 -62
- package/examples/jsm/nodes/materials/PointsNodeMaterial.js +7 -1
- package/examples/jsm/nodes/materials/SpriteNodeMaterial.js +29 -25
- package/examples/jsm/nodes/materialx/MaterialXNodes.js +31 -22
- package/examples/jsm/nodes/materialx/lib/mx_hsv.js +1 -1
- package/examples/jsm/nodes/materialx/lib/mx_noise.js +2 -1
- package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +2 -1
- package/examples/jsm/nodes/math/CondNode.js +43 -17
- package/examples/jsm/nodes/math/MathNode.js +178 -73
- package/examples/jsm/nodes/math/OperatorNode.js +52 -2
- package/examples/jsm/nodes/procedural/CheckerNode.js +14 -6
- package/examples/jsm/nodes/shadernode/ShaderNode.js +186 -63
- package/examples/jsm/nodes/utils/ArrayElementNode.js +4 -2
- package/examples/jsm/nodes/utils/ConvertNode.js +19 -1
- package/examples/jsm/nodes/utils/DiscardNode.js +26 -0
- package/examples/jsm/nodes/utils/EquirectUVNode.js +10 -4
- package/examples/jsm/nodes/utils/JoinNode.js +4 -1
- package/examples/jsm/nodes/utils/LoopNode.js +186 -0
- package/examples/jsm/nodes/utils/MatcapUVNode.js +11 -4
- package/examples/jsm/nodes/utils/MaxMipLevelNode.js +18 -5
- package/examples/jsm/nodes/utils/OscNode.js +21 -14
- package/examples/jsm/nodes/utils/PackingNode.js +55 -0
- package/examples/jsm/nodes/utils/RemapNode.js +13 -5
- package/examples/jsm/nodes/utils/RotateUVNode.js +18 -7
- package/examples/jsm/nodes/utils/SpecularMIPLevelNode.js +37 -0
- package/examples/jsm/nodes/utils/SplitNode.js +7 -5
- package/examples/jsm/nodes/utils/SpriteSheetUVNode.js +15 -30
- package/examples/jsm/nodes/utils/TimerNode.js +16 -6
- package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +21 -10
- package/examples/jsm/objects/GroundProjectedSkybox.js +172 -0
- package/examples/jsm/objects/Lensflare.js +3 -4
- package/examples/jsm/objects/MarchingCubes.js +5 -1
- package/examples/jsm/objects/Reflector.js +7 -4
- package/examples/jsm/objects/Refractor.js +4 -4
- package/examples/jsm/objects/ShadowMesh.js +3 -3
- package/examples/jsm/objects/Water.js +2 -1
- package/examples/jsm/physics/AmmoPhysics.js +27 -28
- package/examples/jsm/physics/RapierPhysics.js +199 -0
- package/examples/jsm/postprocessing/AfterimagePass.js +3 -2
- package/examples/jsm/postprocessing/BloomPass.js +7 -4
- package/examples/jsm/postprocessing/BokehPass.js +3 -8
- package/examples/jsm/postprocessing/DotScreenPass.js +1 -2
- package/examples/jsm/postprocessing/EffectComposer.js +5 -95
- package/examples/jsm/postprocessing/FilmPass.js +1 -2
- package/examples/jsm/postprocessing/GlitchPass.js +0 -2
- package/examples/jsm/postprocessing/HalftonePass.js +0 -6
- package/examples/jsm/postprocessing/OutlinePass.js +7 -7
- package/examples/jsm/postprocessing/OutputPass.js +72 -0
- package/examples/jsm/postprocessing/Pass.js +2 -0
- package/examples/jsm/postprocessing/RenderPixelatedPass.js +4 -3
- package/examples/jsm/postprocessing/SAOPass.js +4 -26
- package/examples/jsm/postprocessing/SMAAPass.js +5 -8
- package/examples/jsm/postprocessing/SSAARenderPass.js +15 -6
- package/examples/jsm/postprocessing/SSAOPass.js +4 -14
- package/examples/jsm/postprocessing/SSRPass.js +3 -7
- package/examples/jsm/postprocessing/SavePass.js +2 -3
- package/examples/jsm/postprocessing/ShaderPass.js +1 -0
- package/examples/jsm/postprocessing/TAARenderPass.js +3 -2
- package/examples/jsm/postprocessing/TexturePass.js +0 -2
- package/examples/jsm/postprocessing/UnrealBloomPass.js +4 -11
- package/examples/jsm/renderers/CSS2DRenderer.js +6 -1
- package/examples/jsm/renderers/CSS3DRenderer.js +27 -5
- package/examples/jsm/renderers/{webgpu/WebGPUAnimation.js → common/Animation.js} +4 -4
- package/examples/jsm/renderers/common/Attributes.js +75 -0
- package/examples/jsm/renderers/common/Backend.js +160 -0
- package/examples/jsm/renderers/common/Background.js +133 -0
- package/examples/jsm/renderers/common/Binding.js +11 -0
- package/examples/jsm/renderers/common/Bindings.js +169 -0
- package/examples/jsm/renderers/common/Buffer.js +38 -0
- package/examples/jsm/renderers/{webgpu/WebGPUBufferUtils.js → common/BufferUtils.js} +2 -2
- package/examples/jsm/renderers/common/ChainMap.js +89 -0
- package/examples/jsm/renderers/common/ComputePipeline.js +17 -0
- package/examples/jsm/renderers/common/Constants.js +14 -0
- package/examples/jsm/renderers/common/CubeRenderTarget.js +65 -0
- package/examples/jsm/renderers/common/DataMap.js +54 -0
- package/examples/jsm/renderers/common/Geometries.js +215 -0
- package/examples/jsm/renderers/{webgpu/WebGPUInfo.js → common/Info.js} +2 -3
- package/examples/jsm/renderers/common/Pipeline.js +13 -0
- package/examples/jsm/renderers/common/Pipelines.js +309 -0
- package/examples/jsm/renderers/common/ProgrammableStage.js +18 -0
- package/examples/jsm/renderers/common/RenderContext.js +37 -0
- package/examples/jsm/renderers/common/RenderContexts.js +38 -0
- package/examples/jsm/renderers/{webgpu/WebGPURenderLists.js → common/RenderList.js} +26 -47
- package/examples/jsm/renderers/common/RenderLists.js +38 -0
- package/examples/jsm/renderers/common/RenderObject.js +95 -0
- package/examples/jsm/renderers/common/RenderObjects.js +92 -0
- package/examples/jsm/renderers/common/RenderPipeline.js +16 -0
- package/examples/jsm/renderers/common/RenderTarget.js +15 -0
- package/examples/jsm/renderers/common/Renderer.js +822 -0
- package/examples/jsm/renderers/common/SampledTexture.js +80 -0
- package/examples/jsm/renderers/common/Sampler.js +18 -0
- package/examples/jsm/renderers/common/StorageBuffer.js +17 -0
- package/examples/jsm/renderers/common/Textures.js +206 -0
- package/examples/jsm/renderers/{webgpu/WebGPUUniform.js → common/Uniform.js} +13 -9
- package/examples/jsm/renderers/common/UniformBuffer.js +15 -0
- package/examples/jsm/renderers/{webgpu/WebGPUUniformsGroup.js → common/UniformsGroup.js} +13 -13
- package/examples/jsm/renderers/common/nodes/NodeRender.js +302 -0
- package/examples/jsm/renderers/{webgpu/nodes/WebGPUNodeSampledTexture.js → common/nodes/NodeSampledTexture.js} +4 -4
- package/examples/jsm/renderers/{webgpu/nodes/WebGPUNodeSampler.js → common/nodes/NodeSampler.js} +3 -3
- package/examples/jsm/renderers/{webgpu/nodes/WebGPUNodeUniform.js → common/nodes/NodeUniform.js} +1 -1
- package/examples/jsm/renderers/common/nodes/Nodes.js +319 -0
- package/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +35 -31
- package/examples/jsm/renderers/webgpu/WebGPUBackend.js +765 -0
- package/examples/jsm/renderers/webgpu/WebGPURenderer.js +15 -987
- package/examples/jsm/renderers/webgpu/nodes/{WebGPUNodeBuilder.js → WGSLNodeBuilder.js} +117 -90
- package/examples/jsm/{nodes/parsers → renderers/webgpu/nodes}/WGSLNodeFunction.js +2 -2
- package/examples/jsm/{nodes/parsers → renderers/webgpu/nodes}/WGSLNodeParser.js +1 -1
- package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +251 -0
- package/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +145 -0
- package/examples/jsm/renderers/webgpu/{constants.js → utils/WebGPUConstants.js} +73 -12
- package/examples/jsm/renderers/webgpu/{WebGPURenderPipeline.js → utils/WebGPUPipelineUtils.js} +135 -285
- package/examples/jsm/renderers/webgpu/{WebGPUTextureUtils.js → utils/WebGPUTextureMipmapUtils.js} +5 -25
- package/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +855 -0
- package/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js +88 -0
- package/examples/jsm/shaders/BleachBypassShader.js +2 -0
- package/examples/jsm/shaders/BokehShader2.js +3 -0
- package/examples/jsm/shaders/ColorifyShader.js +2 -0
- package/examples/jsm/shaders/ConvolutionShader.js +2 -0
- package/examples/jsm/shaders/CopyShader.js +2 -0
- package/examples/jsm/shaders/DotScreenShader.js +2 -0
- package/examples/jsm/shaders/ExposureShader.js +44 -0
- package/examples/jsm/shaders/FilmShader.js +2 -0
- package/examples/jsm/shaders/GammaCorrectionShader.js +2 -0
- package/examples/jsm/shaders/HorizontalBlurShader.js +2 -0
- package/examples/jsm/shaders/MMDToonShader.js +15 -4
- package/examples/jsm/shaders/OutputShader.js +61 -0
- package/examples/jsm/shaders/RGBShiftShader.js +4 -2
- package/examples/jsm/shaders/SepiaShader.js +2 -0
- package/examples/jsm/shaders/ToonShader.js +13 -5
- package/examples/jsm/shaders/VelocityShader.js +1 -1
- package/examples/jsm/shaders/VerticalBlurShader.js +2 -0
- package/examples/jsm/shaders/VignetteShader.js +2 -0
- package/examples/jsm/shaders/WaterRefractionShader.js +5 -2
- package/examples/jsm/utils/BufferGeometryUtils.js +54 -36
- package/examples/jsm/utils/LDrawUtils.js +4 -4
- package/examples/jsm/utils/PackedPhongMaterial.js +5 -78
- package/examples/jsm/utils/SceneUtils.js +8 -4
- package/examples/jsm/utils/SkeletonUtils.js +27 -210
- package/examples/jsm/utils/TextureUtils.js +41 -40
- package/examples/jsm/webxr/VRButton.js +1 -2
- package/examples/jsm/webxr/XRButton.js +198 -0
- package/examples/jsm/webxr/XRHandPrimitiveModel.js +1 -0
- package/examples/jsm/webxr/XRPlanes.js +100 -0
- package/package.json +34 -87
- package/src/Three.Legacy.js +19 -110
- package/src/Three.js +4 -3
- package/src/animation/AnimationUtils.js +13 -1
- package/src/audio/Audio.js +7 -2
- package/src/audio/PositionalAudio.js +8 -0
- package/src/cameras/Camera.js +5 -0
- package/src/cameras/CubeCamera.js +76 -13
- package/src/cameras/OrthographicCamera.js +1 -1
- package/src/cameras/PerspectiveCamera.js +1 -1
- package/src/constants.js +22 -2
- package/src/core/BufferAttribute.js +150 -9
- package/src/core/BufferGeometry.js +4 -10
- package/src/core/GLBufferAttribute.js +2 -0
- package/src/core/InterleavedBufferAttribute.js +5 -5
- package/src/core/Object3D.js +37 -8
- package/src/extras/DataUtils.js +7 -1
- package/src/extras/ImageUtils.js +2 -2
- package/src/extras/PMREMGenerator.js +5 -5
- package/src/extras/core/Curve.js +1 -1
- package/src/extras/curves/LineCurve.js +6 -4
- package/src/extras/curves/LineCurve3.js +13 -0
- package/src/geometries/BoxGeometry.js +10 -0
- package/src/geometries/CircleGeometry.js +11 -1
- package/src/geometries/ConeGeometry.js +1 -1
- package/src/geometries/CylinderGeometry.js +11 -1
- package/src/geometries/EdgesGeometry.js +10 -0
- package/src/geometries/ExtrudeGeometry.js +11 -1
- package/src/geometries/LatheGeometry.js +10 -0
- package/src/geometries/PlaneGeometry.js +10 -0
- package/src/geometries/PolyhedronGeometry.js +11 -1
- package/src/geometries/RingGeometry.js +11 -1
- package/src/geometries/ShapeGeometry.js +11 -1
- package/src/geometries/SphereGeometry.js +12 -2
- package/src/geometries/TorusGeometry.js +11 -1
- package/src/geometries/TorusKnotGeometry.js +10 -0
- package/src/geometries/TubeGeometry.js +10 -0
- package/src/geometries/WireframeGeometry.js +10 -0
- package/src/helpers/Box3Helper.js +1 -2
- package/src/lights/DirectionalLight.js +1 -1
- package/src/lights/HemisphereLight.js +1 -1
- package/src/lights/SpotLight.js +1 -1
- package/src/loaders/AudioLoader.js +14 -8
- package/src/loaders/CubeTextureLoader.js +2 -0
- package/src/loaders/DataTextureLoader.js +5 -1
- package/src/loaders/MaterialLoader.js +8 -0
- package/src/loaders/ObjectLoader.js +10 -2
- package/src/materials/LineBasicMaterial.js +4 -0
- package/src/materials/Material.js +16 -4
- package/src/materials/MeshDistanceMaterial.js +0 -9
- package/src/materials/MeshPhysicalMaterial.js +32 -6
- package/src/materials/ShaderMaterial.js +6 -1
- package/src/math/Box2.js +3 -2
- package/src/math/Box3.js +49 -64
- package/src/math/Color.js +88 -66
- package/src/math/ColorManagement.js +75 -16
- package/src/math/Euler.js +2 -11
- package/src/math/Frustum.js +29 -5
- package/src/math/MathUtils.js +43 -1
- package/src/math/Matrix3.js +26 -6
- package/src/math/Matrix4.js +74 -19
- package/src/math/Plane.js +2 -2
- package/src/math/Quaternion.js +6 -0
- package/src/math/Ray.js +7 -7
- package/src/math/Triangle.js +37 -7
- package/src/math/Vector2.js +16 -0
- package/src/math/Vector3.js +10 -0
- package/src/math/interpolants/CubicInterpolant.js +1 -2
- package/src/objects/InstancedMesh.js +82 -1
- package/src/objects/Mesh.js +108 -76
- package/src/objects/Skeleton.js +1 -1
- package/src/objects/SkinnedMesh.js +123 -8
- package/src/objects/Sprite.js +1 -1
- package/src/renderers/WebGLCubeRenderTarget.js +12 -3
- package/src/renderers/WebGLMultipleRenderTargets.js +4 -2
- package/src/renderers/WebGLRenderTarget.js +14 -2
- package/src/renderers/WebGLRenderer.js +1433 -1236
- package/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/aomap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +0 -271
- package/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl.js +5 -5
- package/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js +2 -10
- package/src/renderers/shaders/ShaderChunk/clearcoat_pars_fragment.glsl.js +5 -5
- package/src/renderers/shaders/ShaderChunk/common.glsl.js +32 -0
- package/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +26 -3
- package/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +3 -3
- package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +10 -2
- package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +11 -11
- package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +39 -13
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +306 -10
- package/src/renderers/shaders/ShaderChunk/map_fragment.glsl.js +2 -10
- package/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl.js +9 -1
- package/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl.js +10 -2
- package/src/renderers/shaders/ShaderChunk/metalnessmap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js +32 -10
- package/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js +5 -13
- package/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js +7 -7
- package/src/renderers/shaders/ShaderChunk/output_fragment.glsl.js +1 -2
- package/src/renderers/shaders/ShaderChunk/packing.glsl.js +11 -5
- package/src/renderers/shaders/ShaderChunk/roughnessmap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +4 -11
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js +2 -2
- package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +39 -34
- package/src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/tonemapping_pars_fragment.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +5 -5
- package/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js +101 -16
- package/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js +113 -1
- package/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js +134 -6
- package/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js +116 -1
- package/src/renderers/shaders/ShaderChunk.js +0 -6
- package/src/renderers/shaders/ShaderLib/background.glsl.js +0 -8
- package/src/renderers/shaders/ShaderLib/linedashed.glsl.js +5 -0
- package/src/renderers/shaders/ShaderLib/meshbasic.glsl.js +1 -4
- package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +0 -3
- package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +3 -3
- package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +0 -3
- package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +16 -12
- package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +0 -3
- package/src/renderers/shaders/ShaderLib/points.glsl.js +13 -0
- package/src/renderers/shaders/ShaderLib/shadow.glsl.js +5 -0
- package/src/renderers/shaders/ShaderLib.js +18 -4
- package/src/renderers/shaders/UniformsLib.js +27 -15
- package/src/renderers/shaders/UniformsUtils.js +12 -3
- package/src/renderers/webgl/WebGLBackground.js +23 -12
- package/src/renderers/webgl/WebGLBindingStates.js +13 -5
- package/src/renderers/webgl/WebGLCapabilities.js +1 -2
- package/src/renderers/webgl/WebGLClipping.js +7 -3
- package/src/renderers/webgl/WebGLGeometries.js +12 -0
- package/src/renderers/webgl/WebGLInfo.js +0 -1
- package/src/renderers/webgl/WebGLLights.js +2 -2
- package/src/renderers/webgl/WebGLMaterials.js +123 -234
- package/src/renderers/webgl/WebGLMorphtargets.js +1 -1
- package/src/renderers/webgl/WebGLProgram.js +130 -48
- package/src/renderers/webgl/WebGLPrograms.js +210 -130
- package/src/renderers/webgl/WebGLRenderStates.js +2 -2
- package/src/renderers/webgl/WebGLShadowMap.js +40 -27
- package/src/renderers/webgl/WebGLState.js +23 -9
- package/src/renderers/webgl/WebGLTextures.js +39 -19
- package/src/renderers/webgl/WebGLUniformsGroups.js +74 -33
- package/src/renderers/webgl/WebGLUtils.js +41 -29
- package/src/renderers/webxr/WebXRController.js +3 -0
- package/src/renderers/webxr/WebXRManager.js +89 -141
- package/src/scenes/Scene.js +4 -6
- package/src/textures/CompressedTexture.js +2 -2
- package/src/textures/CubeTexture.js +2 -2
- package/src/textures/DataTexture.js +2 -2
- package/src/textures/DepthTexture.js +22 -0
- package/src/textures/FramebufferTexture.js +1 -3
- package/src/textures/Source.js +4 -0
- package/src/textures/Texture.js +43 -13
- package/src/utils.js +13 -1
- package/examples/fonts/open-sans/open-sans-v15-cyrillic-ext_greek_greek-ext_cyrillic_latin_latin-ext_vietnamese-regular.woff +0 -0
- package/examples/fonts/open-sans/open-sans-v15-cyrillic-ext_greek_greek-ext_cyrillic_latin_latin-ext_vietnamese-regular.woff2 +0 -0
- package/examples/fonts/open-sans/open-sans.css +0 -9
- package/examples/fonts/tabler-icons/fonts/tabler-icons.eot +0 -0
- package/examples/fonts/tabler-icons/fonts/tabler-icons.svg +0 -3966
- package/examples/fonts/tabler-icons/fonts/tabler-icons.ttf +0 -0
- package/examples/fonts/tabler-icons/fonts/tabler-icons.woff +0 -0
- package/examples/fonts/tabler-icons/fonts/tabler-icons.woff2 +0 -0
- package/examples/fonts/tabler-icons/tabler-icons.min.css +0 -4
- package/examples/js/animation/AnimationClipCreator.js +0 -89
- package/examples/js/animation/CCDIKSolver.js +0 -416
- package/examples/js/animation/MMDAnimationHelper.js +0 -1046
- package/examples/js/animation/MMDPhysics.js +0 -1174
- package/examples/js/cameras/CinematicCamera.js +0 -168
- package/examples/js/controls/ArcballControls.js +0 -2770
- package/examples/js/controls/DragControls.js +0 -205
- package/examples/js/controls/FirstPersonControls.js +0 -312
- package/examples/js/controls/FlyControls.js +0 -321
- package/examples/js/controls/OrbitControls.js +0 -1065
- package/examples/js/controls/PointerLockControls.js +0 -144
- package/examples/js/controls/TrackballControls.js +0 -729
- package/examples/js/controls/TransformControls.js +0 -1301
- package/examples/js/csm/CSM.js +0 -347
- package/examples/js/csm/CSMFrustum.js +0 -127
- package/examples/js/csm/CSMHelper.js +0 -165
- package/examples/js/csm/CSMShader.js +0 -253
- package/examples/js/curves/CurveExtras.js +0 -348
- package/examples/js/curves/NURBSCurve.js +0 -63
- package/examples/js/curves/NURBSSurface.js +0 -48
- package/examples/js/curves/NURBSUtils.js +0 -439
- package/examples/js/effects/AnaglyphEffect.js +0 -86
- package/examples/js/effects/AsciiEffect.js +0 -260
- package/examples/js/effects/OutlineEffect.js +0 -450
- package/examples/js/effects/ParallaxBarrierEffect.js +0 -62
- package/examples/js/effects/PeppersGhostEffect.js +0 -139
- package/examples/js/effects/StereoEffect.js +0 -46
- package/examples/js/environments/DebugEnvironment.js +0 -53
- package/examples/js/environments/RoomEnvironment.js +0 -124
- package/examples/js/exporters/ColladaExporter.js +0 -487
- package/examples/js/exporters/DRACOExporter.js +0 -212
- package/examples/js/exporters/EXRExporter.js +0 -455
- package/examples/js/exporters/GLTFExporter.js +0 -2425
- package/examples/js/exporters/MMDExporter.js +0 -187
- package/examples/js/exporters/OBJExporter.js +0 -260
- package/examples/js/exporters/PLYExporter.js +0 -427
- package/examples/js/exporters/STLExporter.js +0 -188
- package/examples/js/exporters/USDZExporter.js +0 -608
- package/examples/js/geometries/BoxLineGeometry.js +0 -59
- package/examples/js/geometries/ConvexGeometry.js +0 -53
- package/examples/js/geometries/DecalGeometry.js +0 -324
- package/examples/js/geometries/LightningStrike.js +0 -861
- package/examples/js/geometries/ParametricGeometries.js +0 -216
- package/examples/js/geometries/ParametricGeometry.js +0 -121
- package/examples/js/geometries/RoundedBoxGeometry.js +0 -142
- package/examples/js/geometries/TeapotGeometry.js +0 -335
- package/examples/js/geometries/TextGeometry.js +0 -53
- package/examples/js/helpers/LightProbeHelper.js +0 -48
- package/examples/js/helpers/OctreeHelper.js +0 -76
- package/examples/js/helpers/PositionalAudioHelper.js +0 -91
- package/examples/js/helpers/RectAreaLightHelper.js +0 -73
- package/examples/js/helpers/VertexNormalsHelper.js +0 -74
- package/examples/js/helpers/VertexTangentsHelper.js +0 -68
- package/examples/js/helpers/ViewHelper.js +0 -281
- package/examples/js/interactive/HTMLMesh.js +0 -497
- package/examples/js/interactive/InteractiveGroup.js +0 -95
- package/examples/js/interactive/SelectionBox.js +0 -195
- package/examples/js/interactive/SelectionHelper.js +0 -83
- package/examples/js/libs/chevrotain.min.js +0 -3
- package/examples/js/libs/draco/draco_decoder.js +0 -52
- package/examples/js/libs/draco/draco_decoder.wasm +0 -0
- package/examples/js/libs/draco/draco_wasm_wrapper.js +0 -104
- package/examples/js/libs/draco/gltf/draco_decoder.js +0 -48
- package/examples/js/libs/draco/gltf/draco_decoder.wasm +0 -0
- package/examples/js/libs/draco/gltf/draco_wasm_wrapper.js +0 -104
- package/examples/js/libs/fflate.min.js +0 -7
- package/examples/js/libs/ktx-parse.umd.js +0 -1
- package/examples/js/libs/meshopt_decoder.js +0 -188
- package/examples/js/libs/opentype.min.js +0 -1
- package/examples/js/libs/stats.min.js +0 -5
- package/examples/js/lights/LightProbeGenerator.js +0 -221
- package/examples/js/lights/RectAreaLightUniformsLib.js +0 -60
- package/examples/js/lines/Line2.js +0 -19
- package/examples/js/lines/LineGeometry.js +0 -69
- package/examples/js/lines/LineMaterial.js +0 -635
- package/examples/js/lines/LineSegments2.js +0 -311
- package/examples/js/lines/LineSegmentsGeometry.js +0 -198
- package/examples/js/lines/Wireframe.js +0 -47
- package/examples/js/lines/WireframeGeometry2.js +0 -20
- package/examples/js/loaders/3DMLoader.js +0 -1273
- package/examples/js/loaders/3MFLoader.js +0 -1306
- package/examples/js/loaders/AMFLoader.js +0 -504
- package/examples/js/loaders/BVHLoader.js +0 -395
- package/examples/js/loaders/BasisTextureLoader.js +0 -706
- package/examples/js/loaders/ColladaLoader.js +0 -3663
- package/examples/js/loaders/DDSLoader.js +0 -244
- package/examples/js/loaders/DRACOLoader.js +0 -511
- package/examples/js/loaders/EXRLoader.js +0 -2039
- package/examples/js/loaders/FBXLoader.js +0 -3680
- package/examples/js/loaders/FontLoader.js +0 -160
- package/examples/js/loaders/GCodeLoader.js +0 -255
- package/examples/js/loaders/GLTFLoader.js +0 -4108
- package/examples/js/loaders/HDRCubeTextureLoader.js +0 -87
- package/examples/js/loaders/KMZLoader.js +0 -121
- package/examples/js/loaders/KTXLoader.js +0 -159
- package/examples/js/loaders/LDrawLoader.js +0 -2263
- package/examples/js/loaders/LUT3dlLoader.js +0 -135
- package/examples/js/loaders/LUTCubeLoader.js +0 -132
- package/examples/js/loaders/LWOLoader.js +0 -901
- package/examples/js/loaders/LogLuvLoader.js +0 -715
- package/examples/js/loaders/LottieLoader.js +0 -62
- package/examples/js/loaders/MD2Loader.js +0 -248
- package/examples/js/loaders/MDDLoader.js +0 -91
- package/examples/js/loaders/MMDLoader.js +0 -1915
- package/examples/js/loaders/MTLLoader.js +0 -472
- package/examples/js/loaders/MaterialXLoader.js +0 -392
- package/examples/js/loaders/NRRDLoader.js +0 -609
- package/examples/js/loaders/OBJLoader.js +0 -789
- package/examples/js/loaders/PCDLoader.js +0 -413
- package/examples/js/loaders/PDBLoader.js +0 -317
- package/examples/js/loaders/PLYLoader.js +0 -532
- package/examples/js/loaders/PRWMLoader.js +0 -249
- package/examples/js/loaders/PVRLoader.js +0 -218
- package/examples/js/loaders/RGBELoader.js +0 -442
- package/examples/js/loaders/RGBMLoader.js +0 -1354
- package/examples/js/loaders/STLLoader.js +0 -364
- package/examples/js/loaders/SVGLoader.js +0 -2783
- package/examples/js/loaders/TDSLoader.js +0 -992
- package/examples/js/loaders/TGALoader.js +0 -484
- package/examples/js/loaders/TIFFLoader.js +0 -30
- package/examples/js/loaders/TTFLoader.js +0 -203
- package/examples/js/loaders/TiltLoader.js +0 -459
- package/examples/js/loaders/VOXLoader.js +0 -240
- package/examples/js/loaders/VRMLLoader.js +0 -3140
- package/examples/js/loaders/VTKLoader.js +0 -1078
- package/examples/js/loaders/XYZLoader.js +0 -89
- package/examples/js/loaders/lwo/IFFParser.js +0 -1067
- package/examples/js/loaders/lwo/LWO2Parser.js +0 -397
- package/examples/js/loaders/lwo/LWO3Parser.js +0 -360
- package/examples/js/materials/MeshGouraudMaterial.js +0 -387
- package/examples/js/math/Capsule.js +0 -103
- package/examples/js/math/ColorConverter.js +0 -33
- package/examples/js/math/ConvexHull.js +0 -1154
- package/examples/js/math/ImprovedNoise.js +0 -66
- package/examples/js/math/Lut.js +0 -164
- package/examples/js/math/MeshSurfaceSampler.js +0 -171
- package/examples/js/math/OBB.js +0 -382
- package/examples/js/math/Octree.js +0 -410
- package/examples/js/math/SimplexNoise.js +0 -445
- package/examples/js/misc/ConvexObjectBreaker.js +0 -474
- package/examples/js/misc/GPUComputationRenderer.js +0 -393
- package/examples/js/misc/Gyroscope.js +0 -56
- package/examples/js/misc/MD2Character.js +0 -235
- package/examples/js/misc/MD2CharacterComplex.js +0 -513
- package/examples/js/misc/MorphAnimMesh.js +0 -63
- package/examples/js/misc/MorphBlendMesh.js +0 -265
- package/examples/js/misc/ProgressiveLightMap.js +0 -335
- package/examples/js/misc/RollerCoaster.js +0 -430
- package/examples/js/misc/TubePainter.js +0 -167
- package/examples/js/misc/Volume.js +0 -437
- package/examples/js/misc/VolumeSlice.js +0 -214
- package/examples/js/modifiers/CurveModifier.js +0 -309
- package/examples/js/modifiers/EdgeSplitModifier.js +0 -228
- package/examples/js/modifiers/SimplifyModifier.js +0 -465
- package/examples/js/modifiers/TessellateModifier.js +0 -276
- package/examples/js/objects/GroundProjectedEnv.js +0 -181
- package/examples/js/objects/Lensflare.js +0 -356
- package/examples/js/objects/LightningStorm.js +0 -206
- package/examples/js/objects/MarchingCubes.js +0 -759
- package/examples/js/objects/Reflector.js +0 -216
- package/examples/js/objects/ReflectorForSSRPass.js +0 -315
- package/examples/js/objects/Refractor.js +0 -283
- package/examples/js/objects/ShadowMesh.js +0 -59
- package/examples/js/objects/Sky.js +0 -218
- package/examples/js/objects/Water.js +0 -292
- package/examples/js/objects/Water2.js +0 -307
- package/examples/js/physics/AmmoPhysics.js +0 -259
- package/examples/js/physics/OimoPhysics.js +0 -217
- package/examples/js/postprocessing/AdaptiveToneMappingPass.js +0 -335
- package/examples/js/postprocessing/AfterimagePass.js +0 -77
- package/examples/js/postprocessing/BloomPass.js +0 -135
- package/examples/js/postprocessing/BokehPass.js +0 -120
- package/examples/js/postprocessing/ClearPass.js +0 -39
- package/examples/js/postprocessing/CubeTexturePass.js +0 -60
- package/examples/js/postprocessing/DotScreenPass.js +0 -51
- package/examples/js/postprocessing/EffectComposer.js +0 -272
- package/examples/js/postprocessing/FilmPass.js +0 -52
- package/examples/js/postprocessing/GlitchPass.js +0 -104
- package/examples/js/postprocessing/HalftonePass.js +0 -75
- package/examples/js/postprocessing/LUTPass.js +0 -171
- package/examples/js/postprocessing/MaskPass.js +0 -95
- package/examples/js/postprocessing/OutlinePass.js +0 -598
- package/examples/js/postprocessing/Pass.js +0 -72
- package/examples/js/postprocessing/RenderPass.js +0 -70
- package/examples/js/postprocessing/SAOPass.js +0 -374
- package/examples/js/postprocessing/SMAAPass.js +0 -170
- package/examples/js/postprocessing/SSAARenderPass.js +0 -156
- package/examples/js/postprocessing/SSAOPass.js +0 -365
- package/examples/js/postprocessing/SSRPass.js +0 -567
- package/examples/js/postprocessing/SavePass.js +0 -59
- package/examples/js/postprocessing/ShaderPass.js +0 -64
- package/examples/js/postprocessing/TAARenderPass.js +0 -130
- package/examples/js/postprocessing/TexturePass.js +0 -49
- package/examples/js/postprocessing/UnrealBloomPass.js +0 -375
- package/examples/js/renderers/CSS2DRenderer.js +0 -178
- package/examples/js/renderers/CSS3DRenderer.js +0 -237
- package/examples/js/renderers/Projector.js +0 -818
- package/examples/js/renderers/SVGRenderer.js +0 -491
- package/examples/js/shaders/ACESFilmicToneMappingShader.js +0 -89
- package/examples/js/shaders/AfterimageShader.js +0 -60
- package/examples/js/shaders/BasicShader.js +0 -27
- package/examples/js/shaders/BleachBypassShader.js +0 -62
- package/examples/js/shaders/BlendShader.js +0 -54
- package/examples/js/shaders/BokehShader.js +0 -156
- package/examples/js/shaders/BokehShader2.js +0 -419
- package/examples/js/shaders/BrightnessContrastShader.js +0 -58
- package/examples/js/shaders/ColorCorrectionShader.js +0 -52
- package/examples/js/shaders/ColorifyShader.js +0 -47
- package/examples/js/shaders/ConvolutionShader.js +0 -92
- package/examples/js/shaders/CopyShader.js +0 -45
- package/examples/js/shaders/DOFMipMapShader.js +0 -60
- package/examples/js/shaders/DepthLimitedBlurShader.js +0 -173
- package/examples/js/shaders/DigitalGlitch.js +0 -127
- package/examples/js/shaders/DotScreenShader.js +0 -72
- package/examples/js/shaders/FXAAShader.js +0 -284
- package/examples/js/shaders/FilmShader.js +0 -110
- package/examples/js/shaders/FocusShader.js +0 -95
- package/examples/js/shaders/FreiChenShader.js +0 -93
- package/examples/js/shaders/GammaCorrectionShader.js +0 -41
- package/examples/js/shaders/GodRaysShader.js +0 -284
- package/examples/js/shaders/HalftoneShader.js +0 -336
- package/examples/js/shaders/HorizontalBlurShader.js +0 -59
- package/examples/js/shaders/HorizontalTiltShiftShader.js +0 -65
- package/examples/js/shaders/HueSaturationShader.js +0 -69
- package/examples/js/shaders/KaleidoShader.js +0 -60
- package/examples/js/shaders/LuminosityHighPassShader.js +0 -67
- package/examples/js/shaders/LuminosityShader.js +0 -46
- package/examples/js/shaders/MMDToonShader.js +0 -96
- package/examples/js/shaders/MirrorShader.js +0 -56
- package/examples/js/shaders/NormalMapShader.js +0 -55
- package/examples/js/shaders/RGBShiftShader.js +0 -56
- package/examples/js/shaders/SAOShader.js +0 -209
- package/examples/js/shaders/SMAAShader.js +0 -454
- package/examples/js/shaders/SSAOShader.js +0 -295
- package/examples/js/shaders/SSRShader.js +0 -381
- package/examples/js/shaders/SepiaShader.js +0 -52
- package/examples/js/shaders/SobelOperatorShader.js +0 -88
- package/examples/js/shaders/SubsurfaceScatteringShader.js +0 -49
- package/examples/js/shaders/TechnicolorShader.js +0 -43
- package/examples/js/shaders/ToneMapShader.js +0 -84
- package/examples/js/shaders/ToonShader.js +0 -335
- package/examples/js/shaders/TriangleBlurShader.js +0 -70
- package/examples/js/shaders/UnpackDepthRGBAShader.js +0 -47
- package/examples/js/shaders/VelocityShader.js +0 -126
- package/examples/js/shaders/VerticalBlurShader.js +0 -59
- package/examples/js/shaders/VerticalTiltShiftShader.js +0 -65
- package/examples/js/shaders/VignetteShader.js +0 -53
- package/examples/js/shaders/VolumeShader.js +0 -296
- package/examples/js/shaders/WaterRefractionShader.js +0 -84
- package/examples/js/textures/FlakesTexture.js +0 -40
- package/examples/js/utils/BufferGeometryUtils.js +0 -1160
- package/examples/js/utils/CameraUtils.js +0 -71
- package/examples/js/utils/GPUStatsPanel.js +0 -125
- package/examples/js/utils/GeometryCompressionUtils.js +0 -549
- package/examples/js/utils/GeometryUtils.js +0 -168
- package/examples/js/utils/LDrawUtils.js +0 -179
- package/examples/js/utils/PackedPhongMaterial.js +0 -109
- package/examples/js/utils/SceneUtils.js +0 -214
- package/examples/js/utils/ShadowMapViewer.js +0 -183
- package/examples/js/utils/SkeletonUtils.js +0 -493
- package/examples/js/utils/UVsDebug.js +0 -143
- package/examples/js/utils/WorkerPool.js +0 -105
- package/examples/jsm/exporters/ColladaExporter.js +0 -713
- package/examples/jsm/geometries/LightningStrike.js +0 -1017
- package/examples/jsm/libs/OimoPhysics/OimoPhysics.js +0 -37071
- package/examples/jsm/libs/OimoPhysics/index.js +0 -43
- package/examples/jsm/libs/flow.module.js +0 -4552
- package/examples/jsm/libs/tween.module.min.js +0 -3
- package/examples/jsm/loaders/BasisTextureLoader.js +0 -790
- package/examples/jsm/loaders/IFCLoader.js +0 -2431
- package/examples/jsm/loaders/PRWMLoader.js +0 -299
- package/examples/jsm/loaders/ifc/web-ifc-api.js +0 -47504
- package/examples/jsm/loaders/ifc/web-ifc.wasm +0 -0
- package/examples/jsm/node-editor/NodeEditor.js +0 -857
- package/examples/jsm/node-editor/accessors/MatcapUVEditor.js +0 -14
- package/examples/jsm/node-editor/accessors/NormalEditor.js +0 -30
- package/examples/jsm/node-editor/accessors/PositionEditor.js +0 -30
- package/examples/jsm/node-editor/accessors/UVEditor.js +0 -25
- package/examples/jsm/node-editor/core/BaseNode.js +0 -96
- package/examples/jsm/node-editor/core/DataFile.js +0 -59
- package/examples/jsm/node-editor/core/FileEditor.js +0 -20
- package/examples/jsm/node-editor/core/FileURLEditor.js +0 -29
- package/examples/jsm/node-editor/display/BlendEditor.js +0 -44
- package/examples/jsm/node-editor/display/NormalMapEditor.js +0 -49
- package/examples/jsm/node-editor/examples/animate-uv.json +0 -1
- package/examples/jsm/node-editor/examples/fake-top-light.json +0 -1
- package/examples/jsm/node-editor/examples/matcap.json +0 -1
- package/examples/jsm/node-editor/examples/oscillator-color.json +0 -1
- package/examples/jsm/node-editor/examples/rim.json +0 -1
- package/examples/jsm/node-editor/inputs/ColorEditor.js +0 -96
- package/examples/jsm/node-editor/inputs/FloatEditor.js +0 -23
- package/examples/jsm/node-editor/inputs/SliderEditor.js +0 -67
- package/examples/jsm/node-editor/inputs/TextureEditor.js +0 -155
- package/examples/jsm/node-editor/inputs/Vector2Editor.js +0 -28
- package/examples/jsm/node-editor/inputs/Vector3Editor.js +0 -30
- package/examples/jsm/node-editor/inputs/Vector4Editor.js +0 -37
- package/examples/jsm/node-editor/materials/BasicMaterialEditor.js +0 -84
- package/examples/jsm/node-editor/materials/PointsMaterialEditor.js +0 -102
- package/examples/jsm/node-editor/materials/StandardMaterialEditor.js +0 -118
- package/examples/jsm/node-editor/math/AngleEditor.js +0 -40
- package/examples/jsm/node-editor/math/DotEditor.js +0 -35
- package/examples/jsm/node-editor/math/InvertEditor.js +0 -39
- package/examples/jsm/node-editor/math/LimiterEditor.js +0 -62
- package/examples/jsm/node-editor/math/NormalizeEditor.js +0 -28
- package/examples/jsm/node-editor/math/OperatorEditor.js +0 -63
- package/examples/jsm/node-editor/math/PowerEditor.js +0 -44
- package/examples/jsm/node-editor/math/TrigonometryEditor.js +0 -45
- package/examples/jsm/node-editor/procedural/CheckerEditor.js +0 -27
- package/examples/jsm/node-editor/scene/MeshEditor.js +0 -102
- package/examples/jsm/node-editor/scene/Object3DEditor.js +0 -160
- package/examples/jsm/node-editor/scene/PointsEditor.js +0 -99
- package/examples/jsm/node-editor/utils/JoinEditor.js +0 -58
- package/examples/jsm/node-editor/utils/OscillatorEditor.js +0 -43
- package/examples/jsm/node-editor/utils/PreviewEditor.js +0 -170
- package/examples/jsm/node-editor/utils/SplitEditor.js +0 -39
- package/examples/jsm/node-editor/utils/TimerEditor.js +0 -58
- package/examples/jsm/nodes/core/CodeNode.js +0 -50
- package/examples/jsm/nodes/core/ExpressionNode.js +0 -32
- package/examples/jsm/nodes/functions/light/getDistanceAttenuation.js +0 -22
- package/examples/jsm/nodes/lighting/PunctualLightNode.js +0 -68
- package/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js +0 -301
- package/examples/jsm/nodes/shadernode/ShaderNodeElements.js +0 -149
- package/examples/jsm/objects/GroundProjectedEnv.js +0 -186
- package/examples/jsm/objects/LightningStorm.js +0 -245
- package/examples/jsm/physics/OimoPhysics.js +0 -231
- package/examples/jsm/postprocessing/AdaptiveToneMappingPass.js +0 -369
- package/examples/jsm/renderers/webgpu/WebGPUAttributes.js +0 -187
- package/examples/jsm/renderers/webgpu/WebGPUBackground.js +0 -173
- package/examples/jsm/renderers/webgpu/WebGPUBinding.js +0 -22
- package/examples/jsm/renderers/webgpu/WebGPUBindings.js +0 -255
- package/examples/jsm/renderers/webgpu/WebGPUBuffer.js +0 -43
- package/examples/jsm/renderers/webgpu/WebGPUComputePipelines.js +0 -78
- package/examples/jsm/renderers/webgpu/WebGPUGeometries.js +0 -82
- package/examples/jsm/renderers/webgpu/WebGPUObjects.js +0 -36
- package/examples/jsm/renderers/webgpu/WebGPUProgrammableStage.js +0 -22
- package/examples/jsm/renderers/webgpu/WebGPUProperties.js +0 -38
- package/examples/jsm/renderers/webgpu/WebGPURenderPipelines.js +0 -296
- package/examples/jsm/renderers/webgpu/WebGPURenderStates.js +0 -66
- package/examples/jsm/renderers/webgpu/WebGPUSampledTexture.js +0 -73
- package/examples/jsm/renderers/webgpu/WebGPUSampler.js +0 -29
- package/examples/jsm/renderers/webgpu/WebGPUStorageBuffer.js +0 -20
- package/examples/jsm/renderers/webgpu/WebGPUTextureRenderer.js +0 -40
- package/examples/jsm/renderers/webgpu/WebGPUTextures.js +0 -794
- package/examples/jsm/renderers/webgpu/WebGPUUniformBuffer.js +0 -18
- package/examples/jsm/renderers/webgpu/WebGPUUtils.js +0 -81
- package/examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js +0 -83
- package/examples/jsm/shaders/ToneMapShader.js +0 -73
- package/src/renderers/shaders/ShaderChunk/uv2_pars_fragment.glsl.js +0 -7
- package/src/renderers/shaders/ShaderChunk/uv2_pars_vertex.glsl.js +0 -10
- package/src/renderers/shaders/ShaderChunk/uv2_vertex.glsl.js +0 -7
- /package/examples/{js → jsm}/libs/ammo.wasm.js +0 -0
- /package/examples/{js → jsm}/libs/ammo.wasm.wasm +0 -0
- /package/examples/{js → jsm}/libs/basis/basis_transcoder.js +0 -0
- /package/examples/{js → jsm}/libs/basis/basis_transcoder.wasm +0 -0
- /package/examples/{js → jsm}/libs/draco/README.md +0 -0
- /package/examples/{js → jsm}/libs/draco/draco_encoder.js +0 -0
- /package/examples/{js → jsm}/libs/draco/gltf/draco_encoder.js +0 -0
|
@@ -230,2986 +230,2993 @@ class ArcballControls extends EventDispatcher {
|
|
|
230
230
|
|
|
231
231
|
this.initializeMouseActions();
|
|
232
232
|
|
|
233
|
-
this.
|
|
234
|
-
this.
|
|
235
|
-
this.
|
|
236
|
-
this.
|
|
233
|
+
this._onContextMenu = onContextMenu.bind( this );
|
|
234
|
+
this._onWheel = onWheel.bind( this );
|
|
235
|
+
this._onPointerUp = onPointerUp.bind( this );
|
|
236
|
+
this._onPointerMove = onPointerMove.bind( this );
|
|
237
|
+
this._onPointerDown = onPointerDown.bind( this );
|
|
238
|
+
this._onPointerCancel = onPointerCancel.bind( this );
|
|
239
|
+
this._onWindowResize = onWindowResize.bind( this );
|
|
237
240
|
|
|
238
|
-
|
|
241
|
+
this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
|
|
242
|
+
this.domElement.addEventListener( 'wheel', this._onWheel );
|
|
243
|
+
this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
|
|
244
|
+
this.domElement.addEventListener( 'pointercancel', this._onPointerCancel );
|
|
239
245
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
//listeners
|
|
246
|
+
window.addEventListener( 'resize', this._onWindowResize );
|
|
243
247
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
|
|
247
|
-
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
248
|
+
}
|
|
248
249
|
|
|
249
|
-
|
|
250
|
-
const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
|
|
251
|
-
const points = curve.getPoints( this._curvePts );
|
|
252
|
-
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
250
|
+
onSinglePanStart( event, operation ) {
|
|
253
251
|
|
|
252
|
+
if ( this.enabled ) {
|
|
254
253
|
|
|
255
|
-
|
|
254
|
+
this.dispatchEvent( _startEvent );
|
|
256
255
|
|
|
257
|
-
this.
|
|
256
|
+
this.setCenter( event.clientX, event.clientY );
|
|
258
257
|
|
|
259
|
-
|
|
258
|
+
switch ( operation ) {
|
|
260
259
|
|
|
261
|
-
|
|
260
|
+
case 'PAN':
|
|
262
261
|
|
|
263
|
-
|
|
262
|
+
if ( ! this.enablePan ) {
|
|
264
263
|
|
|
265
|
-
|
|
264
|
+
return;
|
|
266
265
|
|
|
267
|
-
|
|
266
|
+
}
|
|
268
267
|
|
|
269
|
-
|
|
268
|
+
if ( this._animationId != - 1 ) {
|
|
270
269
|
|
|
271
|
-
|
|
270
|
+
cancelAnimationFrame( this._animationId );
|
|
271
|
+
this._animationId = - 1;
|
|
272
|
+
this._timeStart = - 1;
|
|
272
273
|
|
|
273
|
-
|
|
274
|
+
this.activateGizmos( false );
|
|
275
|
+
this.dispatchEvent( _changeEvent );
|
|
274
276
|
|
|
275
|
-
|
|
277
|
+
}
|
|
276
278
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
279
|
+
this.updateTbState( STATE.PAN, true );
|
|
280
|
+
this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
|
|
281
|
+
if ( this.enableGrid ) {
|
|
280
282
|
|
|
281
|
-
|
|
283
|
+
this.drawGrid();
|
|
284
|
+
this.dispatchEvent( _changeEvent );
|
|
282
285
|
|
|
283
|
-
|
|
286
|
+
}
|
|
284
287
|
|
|
285
|
-
|
|
288
|
+
break;
|
|
286
289
|
|
|
287
|
-
|
|
290
|
+
case 'ROTATE':
|
|
288
291
|
|
|
289
|
-
|
|
290
|
-
this._touchCurrent.splice( 0, this._touchCurrent.length );
|
|
291
|
-
this._input = INPUT.NONE;
|
|
292
|
+
if ( ! this.enableRotate ) {
|
|
292
293
|
|
|
293
|
-
|
|
294
|
+
return;
|
|
294
295
|
|
|
295
|
-
|
|
296
|
+
}
|
|
296
297
|
|
|
297
|
-
|
|
298
|
+
if ( this._animationId != - 1 ) {
|
|
298
299
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
cancelAnimationFrame( this._animationId );
|
|
301
|
+
this._animationId = - 1;
|
|
302
|
+
this._timeStart = - 1;
|
|
302
303
|
|
|
303
|
-
|
|
304
|
+
}
|
|
304
305
|
|
|
305
|
-
|
|
306
|
+
this.updateTbState( STATE.ROTATE, true );
|
|
307
|
+
this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
|
|
308
|
+
this.activateGizmos( true );
|
|
309
|
+
if ( this.enableAnimations ) {
|
|
306
310
|
|
|
307
|
-
|
|
311
|
+
this._timePrev = this._timeCurrent = performance.now();
|
|
312
|
+
this._angleCurrent = this._anglePrev = 0;
|
|
313
|
+
this._cursorPosPrev.copy( this._startCursorPosition );
|
|
314
|
+
this._cursorPosCurr.copy( this._cursorPosPrev );
|
|
315
|
+
this._wCurr = 0;
|
|
316
|
+
this._wPrev = this._wCurr;
|
|
308
317
|
|
|
309
|
-
|
|
318
|
+
}
|
|
310
319
|
|
|
311
|
-
|
|
312
|
-
|
|
320
|
+
this.dispatchEvent( _changeEvent );
|
|
321
|
+
break;
|
|
313
322
|
|
|
314
|
-
|
|
323
|
+
case 'FOV':
|
|
315
324
|
|
|
316
|
-
|
|
325
|
+
if ( ! this.camera.isPerspectiveCamera || ! this.enableZoom ) {
|
|
317
326
|
|
|
318
|
-
|
|
319
|
-
this._input = INPUT.ONE_FINGER;
|
|
320
|
-
this.onSinglePanStart( event, 'ROTATE' );
|
|
327
|
+
return;
|
|
321
328
|
|
|
322
|
-
|
|
323
|
-
window.addEventListener( 'pointerup', this.onPointerUp );
|
|
329
|
+
}
|
|
324
330
|
|
|
325
|
-
|
|
331
|
+
if ( this._animationId != - 1 ) {
|
|
326
332
|
|
|
327
|
-
|
|
328
|
-
|
|
333
|
+
cancelAnimationFrame( this._animationId );
|
|
334
|
+
this._animationId = - 1;
|
|
335
|
+
this._timeStart = - 1;
|
|
329
336
|
|
|
330
|
-
|
|
331
|
-
|
|
337
|
+
this.activateGizmos( false );
|
|
338
|
+
this.dispatchEvent( _changeEvent );
|
|
332
339
|
|
|
333
|
-
|
|
334
|
-
this.onPinchStart();
|
|
335
|
-
this.onDoublePanStart();
|
|
340
|
+
}
|
|
336
341
|
|
|
342
|
+
this.updateTbState( STATE.FOV, true );
|
|
343
|
+
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
344
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
337
345
|
break;
|
|
338
346
|
|
|
339
|
-
case
|
|
347
|
+
case 'ZOOM':
|
|
340
348
|
|
|
341
|
-
|
|
342
|
-
this._input = INPUT.MULT_FINGER;
|
|
343
|
-
this.onTriplePanStart( event );
|
|
344
|
-
break;
|
|
349
|
+
if ( ! this.enableZoom ) {
|
|
345
350
|
|
|
346
|
-
|
|
351
|
+
return;
|
|
347
352
|
|
|
348
|
-
|
|
353
|
+
}
|
|
349
354
|
|
|
350
|
-
|
|
355
|
+
if ( this._animationId != - 1 ) {
|
|
351
356
|
|
|
352
|
-
|
|
357
|
+
cancelAnimationFrame( this._animationId );
|
|
358
|
+
this._animationId = - 1;
|
|
359
|
+
this._timeStart = - 1;
|
|
353
360
|
|
|
354
|
-
|
|
361
|
+
this.activateGizmos( false );
|
|
362
|
+
this.dispatchEvent( _changeEvent );
|
|
355
363
|
|
|
356
|
-
|
|
364
|
+
}
|
|
357
365
|
|
|
358
|
-
|
|
366
|
+
this.updateTbState( STATE.SCALE, true );
|
|
367
|
+
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
368
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
369
|
+
break;
|
|
359
370
|
|
|
360
371
|
}
|
|
361
372
|
|
|
362
|
-
|
|
363
|
-
if ( this._mouseOp != null ) {
|
|
373
|
+
}
|
|
364
374
|
|
|
365
|
-
|
|
366
|
-
window.addEventListener( 'pointerup', this.onPointerUp );
|
|
375
|
+
}
|
|
367
376
|
|
|
368
|
-
|
|
369
|
-
this._input = INPUT.CURSOR;
|
|
370
|
-
this._button = event.button;
|
|
371
|
-
this.onSinglePanStart( event, this._mouseOp );
|
|
377
|
+
onSinglePanMove( event, opState ) {
|
|
372
378
|
|
|
373
|
-
|
|
379
|
+
if ( this.enabled ) {
|
|
374
380
|
|
|
375
|
-
|
|
381
|
+
const restart = opState != this._state;
|
|
382
|
+
this.setCenter( event.clientX, event.clientY );
|
|
376
383
|
|
|
377
|
-
|
|
384
|
+
switch ( opState ) {
|
|
378
385
|
|
|
379
|
-
|
|
386
|
+
case STATE.PAN:
|
|
380
387
|
|
|
381
|
-
|
|
388
|
+
if ( this.enablePan ) {
|
|
382
389
|
|
|
383
|
-
|
|
390
|
+
if ( restart ) {
|
|
384
391
|
|
|
385
|
-
|
|
392
|
+
//switch to pan operation
|
|
386
393
|
|
|
387
|
-
|
|
388
|
-
|
|
394
|
+
this.dispatchEvent( _endEvent );
|
|
395
|
+
this.dispatchEvent( _startEvent );
|
|
389
396
|
|
|
390
|
-
|
|
391
|
-
|
|
397
|
+
this.updateTbState( opState, true );
|
|
398
|
+
this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
|
|
399
|
+
if ( this.enableGrid ) {
|
|
400
|
+
|
|
401
|
+
this.drawGrid();
|
|
392
402
|
|
|
393
|
-
|
|
403
|
+
}
|
|
394
404
|
|
|
395
|
-
|
|
405
|
+
this.activateGizmos( false );
|
|
396
406
|
|
|
397
|
-
|
|
407
|
+
} else {
|
|
398
408
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
409
|
+
//continue with pan operation
|
|
410
|
+
this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
|
|
411
|
+
this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition ) );
|
|
402
412
|
|
|
403
|
-
|
|
404
|
-
break;
|
|
413
|
+
}
|
|
405
414
|
|
|
406
415
|
}
|
|
407
416
|
|
|
408
417
|
break;
|
|
409
418
|
|
|
410
|
-
case
|
|
419
|
+
case STATE.ROTATE:
|
|
411
420
|
|
|
412
|
-
|
|
413
|
-
this.updateTouchEvent( event );
|
|
421
|
+
if ( this.enableRotate ) {
|
|
414
422
|
|
|
415
|
-
|
|
416
|
-
this.onPinchMove();
|
|
417
|
-
this.onDoublePanMove();
|
|
423
|
+
if ( restart ) {
|
|
418
424
|
|
|
419
|
-
|
|
425
|
+
//switch to rotate operation
|
|
420
426
|
|
|
421
|
-
|
|
427
|
+
this.dispatchEvent( _endEvent );
|
|
428
|
+
this.dispatchEvent( _startEvent );
|
|
422
429
|
|
|
423
|
-
|
|
424
|
-
|
|
430
|
+
this.updateTbState( opState, true );
|
|
431
|
+
this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
|
|
425
432
|
|
|
426
|
-
|
|
427
|
-
break;
|
|
433
|
+
if ( this.enableGrid ) {
|
|
428
434
|
|
|
429
|
-
|
|
435
|
+
this.disposeGrid();
|
|
430
436
|
|
|
431
|
-
|
|
437
|
+
}
|
|
432
438
|
|
|
433
|
-
|
|
439
|
+
this.activateGizmos( true );
|
|
434
440
|
|
|
435
|
-
|
|
441
|
+
} else {
|
|
436
442
|
|
|
437
|
-
|
|
443
|
+
//continue with rotate operation
|
|
444
|
+
this._currentCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
|
|
438
445
|
|
|
439
|
-
|
|
446
|
+
const distance = this._startCursorPosition.distanceTo( this._currentCursorPosition );
|
|
447
|
+
const angle = this._startCursorPosition.angleTo( this._currentCursorPosition );
|
|
448
|
+
const amount = Math.max( distance / this._tbRadius, angle ); //effective rotation angle
|
|
440
449
|
|
|
441
|
-
|
|
450
|
+
this.applyTransformMatrix( this.rotate( this.calculateRotationAxis( this._startCursorPosition, this._currentCursorPosition ), amount ) );
|
|
442
451
|
|
|
443
|
-
|
|
452
|
+
if ( this.enableAnimations ) {
|
|
444
453
|
|
|
445
|
-
|
|
454
|
+
this._timePrev = this._timeCurrent;
|
|
455
|
+
this._timeCurrent = performance.now();
|
|
456
|
+
this._anglePrev = this._angleCurrent;
|
|
457
|
+
this._angleCurrent = amount;
|
|
458
|
+
this._cursorPosPrev.copy( this._cursorPosCurr );
|
|
459
|
+
this._cursorPosCurr.copy( this._currentCursorPosition );
|
|
460
|
+
this._wPrev = this._wCurr;
|
|
461
|
+
this._wCurr = this.calculateAngularSpeed( this._anglePrev, this._angleCurrent, this._timePrev, this._timeCurrent );
|
|
446
462
|
|
|
447
|
-
|
|
463
|
+
}
|
|
448
464
|
|
|
449
|
-
|
|
465
|
+
}
|
|
450
466
|
|
|
451
|
-
|
|
467
|
+
}
|
|
452
468
|
|
|
453
|
-
|
|
469
|
+
break;
|
|
454
470
|
|
|
455
|
-
|
|
456
|
-
if ( this._downValid ) {
|
|
471
|
+
case STATE.SCALE:
|
|
457
472
|
|
|
458
|
-
|
|
459
|
-
if ( movement > this._movementThreshold ) {
|
|
473
|
+
if ( this.enableZoom ) {
|
|
460
474
|
|
|
461
|
-
|
|
475
|
+
if ( restart ) {
|
|
462
476
|
|
|
463
|
-
|
|
477
|
+
//switch to zoom operation
|
|
464
478
|
|
|
465
|
-
|
|
479
|
+
this.dispatchEvent( _endEvent );
|
|
480
|
+
this.dispatchEvent( _startEvent );
|
|
466
481
|
|
|
467
|
-
|
|
482
|
+
this.updateTbState( opState, true );
|
|
483
|
+
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
484
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
468
485
|
|
|
469
|
-
|
|
486
|
+
if ( this.enableGrid ) {
|
|
470
487
|
|
|
471
|
-
|
|
488
|
+
this.disposeGrid();
|
|
472
489
|
|
|
473
|
-
|
|
490
|
+
}
|
|
474
491
|
|
|
475
|
-
|
|
492
|
+
this.activateGizmos( false );
|
|
476
493
|
|
|
477
|
-
|
|
494
|
+
} else {
|
|
478
495
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
496
|
+
//continue with zoom operation
|
|
497
|
+
const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
|
|
498
|
+
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
482
499
|
|
|
483
|
-
|
|
500
|
+
const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
|
|
484
501
|
|
|
485
|
-
|
|
502
|
+
let size = 1;
|
|
486
503
|
|
|
487
|
-
|
|
504
|
+
if ( movement < 0 ) {
|
|
488
505
|
|
|
489
|
-
|
|
490
|
-
case INPUT.ONE_FINGER_SWITCHED:
|
|
506
|
+
size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
|
|
491
507
|
|
|
492
|
-
|
|
493
|
-
window.removeEventListener( 'pointermove', this.onPointerMove );
|
|
494
|
-
window.removeEventListener( 'pointerup', this.onPointerUp );
|
|
508
|
+
} else if ( movement > 0 ) {
|
|
495
509
|
|
|
496
|
-
|
|
497
|
-
this.onSinglePanEnd();
|
|
510
|
+
size = Math.pow( this.scaleFactor, movement * screenNotches );
|
|
498
511
|
|
|
499
|
-
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
this._v3_1.setFromMatrixPosition( this._gizmoMatrixState );
|
|
500
515
|
|
|
501
|
-
|
|
516
|
+
this.applyTransformMatrix( this.scale( size, this._v3_1 ) );
|
|
502
517
|
|
|
503
|
-
|
|
504
|
-
this.onDoublePanEnd( event );
|
|
505
|
-
this.onPinchEnd( event );
|
|
506
|
-
this.onRotateEnd( event );
|
|
518
|
+
}
|
|
507
519
|
|
|
508
|
-
|
|
509
|
-
this._input = INPUT.ONE_FINGER_SWITCHED;
|
|
520
|
+
}
|
|
510
521
|
|
|
511
522
|
break;
|
|
512
523
|
|
|
513
|
-
case
|
|
524
|
+
case STATE.FOV:
|
|
514
525
|
|
|
515
|
-
if ( this.
|
|
526
|
+
if ( this.enableZoom && this.camera.isPerspectiveCamera ) {
|
|
516
527
|
|
|
517
|
-
|
|
518
|
-
window.removeEventListener( 'pointerup', this.onPointerUp );
|
|
528
|
+
if ( restart ) {
|
|
519
529
|
|
|
520
|
-
|
|
521
|
-
this._input = INPUT.NONE;
|
|
522
|
-
this.onTriplePanEnd();
|
|
530
|
+
//switch to fov operation
|
|
523
531
|
|
|
524
|
-
|
|
532
|
+
this.dispatchEvent( _endEvent );
|
|
533
|
+
this.dispatchEvent( _startEvent );
|
|
525
534
|
|
|
526
|
-
|
|
535
|
+
this.updateTbState( opState, true );
|
|
536
|
+
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
537
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
527
538
|
|
|
528
|
-
|
|
539
|
+
if ( this.enableGrid ) {
|
|
529
540
|
|
|
530
|
-
|
|
541
|
+
this.disposeGrid();
|
|
531
542
|
|
|
532
|
-
|
|
533
|
-
window.removeEventListener( 'pointerup', this.onPointerUp );
|
|
543
|
+
}
|
|
534
544
|
|
|
535
|
-
|
|
536
|
-
this.onSinglePanEnd();
|
|
537
|
-
this._button = - 1;
|
|
545
|
+
this.activateGizmos( false );
|
|
538
546
|
|
|
539
|
-
|
|
547
|
+
} else {
|
|
540
548
|
|
|
541
|
-
|
|
549
|
+
//continue with fov operation
|
|
550
|
+
const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
|
|
551
|
+
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
542
552
|
|
|
543
|
-
|
|
553
|
+
const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
|
|
544
554
|
|
|
545
|
-
|
|
555
|
+
let size = 1;
|
|
546
556
|
|
|
547
|
-
|
|
557
|
+
if ( movement < 0 ) {
|
|
548
558
|
|
|
549
|
-
|
|
559
|
+
size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
|
|
550
560
|
|
|
551
|
-
|
|
552
|
-
this._nclicks = 1;
|
|
553
|
-
this._clickStart = performance.now();
|
|
561
|
+
} else if ( movement > 0 ) {
|
|
554
562
|
|
|
555
|
-
|
|
563
|
+
size = Math.pow( this.scaleFactor, movement * screenNotches );
|
|
556
564
|
|
|
557
|
-
|
|
558
|
-
const movement = this.calculatePointersDistance( this._downEvents[ 1 ], this._downEvents[ 0 ] ) * this._devPxRatio;
|
|
565
|
+
}
|
|
559
566
|
|
|
560
|
-
|
|
567
|
+
this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
|
|
568
|
+
const x = this._v3_1.distanceTo( this._gizmos.position );
|
|
569
|
+
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
561
570
|
|
|
562
|
-
//
|
|
563
|
-
|
|
564
|
-
this._nclicks = 0;
|
|
565
|
-
this._downEvents.splice( 0, this._downEvents.length );
|
|
566
|
-
this.onDoubleTap( event );
|
|
571
|
+
//check min and max distance
|
|
572
|
+
xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
|
|
567
573
|
|
|
568
|
-
|
|
574
|
+
const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
|
|
569
575
|
|
|
570
|
-
//new
|
|
571
|
-
|
|
572
|
-
this._downEvents.shift();
|
|
573
|
-
this._clickStart = performance.now();
|
|
576
|
+
//calculate new fov
|
|
577
|
+
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
574
578
|
|
|
575
|
-
|
|
579
|
+
//check min and max fov
|
|
580
|
+
newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
|
|
576
581
|
|
|
577
|
-
|
|
582
|
+
const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
|
|
583
|
+
size = x / newDistance;
|
|
584
|
+
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
578
585
|
|
|
579
|
-
|
|
586
|
+
this.setFov( newFov );
|
|
587
|
+
this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
|
|
580
588
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
589
|
+
//adjusting distance
|
|
590
|
+
_offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
|
|
591
|
+
this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
584
592
|
|
|
585
|
-
|
|
593
|
+
}
|
|
586
594
|
|
|
587
|
-
|
|
595
|
+
}
|
|
588
596
|
|
|
589
|
-
|
|
590
|
-
this._downEvents.splice( 0, this._downEvents.length );
|
|
597
|
+
break;
|
|
591
598
|
|
|
592
599
|
}
|
|
593
600
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
};
|
|
601
|
+
this.dispatchEvent( _changeEvent );
|
|
597
602
|
|
|
598
|
-
|
|
603
|
+
}
|
|
599
604
|
|
|
600
|
-
|
|
605
|
+
}
|
|
601
606
|
|
|
602
|
-
|
|
607
|
+
onSinglePanEnd() {
|
|
603
608
|
|
|
604
|
-
|
|
609
|
+
if ( this._state == STATE.ROTATE ) {
|
|
605
610
|
|
|
606
|
-
modifier = 'CTRL';
|
|
607
611
|
|
|
608
|
-
|
|
612
|
+
if ( ! this.enableRotate ) {
|
|
609
613
|
|
|
610
|
-
|
|
614
|
+
return;
|
|
611
615
|
|
|
612
616
|
}
|
|
613
617
|
|
|
614
|
-
|
|
618
|
+
if ( this.enableAnimations ) {
|
|
615
619
|
|
|
616
|
-
|
|
620
|
+
//perform rotation animation
|
|
621
|
+
const deltaTime = ( performance.now() - this._timeCurrent );
|
|
622
|
+
if ( deltaTime < 120 ) {
|
|
617
623
|
|
|
618
|
-
|
|
619
|
-
this.dispatchEvent( _startEvent );
|
|
624
|
+
const w = Math.abs( ( this._wPrev + this._wCurr ) / 2 );
|
|
620
625
|
|
|
621
|
-
|
|
622
|
-
|
|
626
|
+
const self = this;
|
|
627
|
+
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
623
628
|
|
|
624
|
-
|
|
629
|
+
self.updateTbState( STATE.ANIMATION_ROTATE, true );
|
|
630
|
+
const rotationAxis = self.calculateRotationAxis( self._cursorPosPrev, self._cursorPosCurr );
|
|
625
631
|
|
|
626
|
-
|
|
632
|
+
self.onRotationAnim( t, rotationAxis, Math.min( w, self.wMax ) );
|
|
627
633
|
|
|
628
|
-
|
|
634
|
+
} );
|
|
629
635
|
|
|
630
|
-
} else
|
|
636
|
+
} else {
|
|
631
637
|
|
|
632
|
-
|
|
638
|
+
//cursor has been standing still for over 120 ms since last movement
|
|
639
|
+
this.updateTbState( STATE.IDLE, false );
|
|
640
|
+
this.activateGizmos( false );
|
|
641
|
+
this.dispatchEvent( _changeEvent );
|
|
633
642
|
|
|
634
643
|
}
|
|
635
644
|
|
|
636
|
-
|
|
645
|
+
} else {
|
|
637
646
|
|
|
638
|
-
|
|
647
|
+
this.updateTbState( STATE.IDLE, false );
|
|
648
|
+
this.activateGizmos( false );
|
|
649
|
+
this.dispatchEvent( _changeEvent );
|
|
639
650
|
|
|
640
|
-
|
|
651
|
+
}
|
|
641
652
|
|
|
642
|
-
|
|
653
|
+
} else if ( this._state == STATE.PAN || this._state == STATE.IDLE ) {
|
|
643
654
|
|
|
644
|
-
|
|
655
|
+
this.updateTbState( STATE.IDLE, false );
|
|
645
656
|
|
|
646
|
-
|
|
657
|
+
if ( this.enableGrid ) {
|
|
647
658
|
|
|
648
|
-
|
|
659
|
+
this.disposeGrid();
|
|
649
660
|
|
|
650
|
-
|
|
661
|
+
}
|
|
651
662
|
|
|
652
|
-
|
|
663
|
+
this.activateGizmos( false );
|
|
664
|
+
this.dispatchEvent( _changeEvent );
|
|
653
665
|
|
|
654
|
-
let scalePoint;
|
|
655
666
|
|
|
656
|
-
|
|
667
|
+
}
|
|
657
668
|
|
|
658
|
-
|
|
669
|
+
this.dispatchEvent( _endEvent );
|
|
659
670
|
|
|
660
|
-
|
|
671
|
+
}
|
|
661
672
|
|
|
662
|
-
|
|
673
|
+
onDoubleTap( event ) {
|
|
663
674
|
|
|
664
|
-
|
|
675
|
+
if ( this.enabled && this.enablePan && this.scene != null ) {
|
|
665
676
|
|
|
666
|
-
|
|
677
|
+
this.dispatchEvent( _startEvent );
|
|
667
678
|
|
|
668
|
-
|
|
679
|
+
this.setCenter( event.clientX, event.clientY );
|
|
680
|
+
const hitP = this.unprojectOnObj( this.getCursorNDC( _center.x, _center.y, this.domElement ), this.camera );
|
|
669
681
|
|
|
670
|
-
|
|
682
|
+
if ( hitP != null && this.enableAnimations ) {
|
|
671
683
|
|
|
672
|
-
|
|
684
|
+
const self = this;
|
|
685
|
+
if ( this._animationId != - 1 ) {
|
|
673
686
|
|
|
674
|
-
|
|
687
|
+
window.cancelAnimationFrame( this._animationId );
|
|
675
688
|
|
|
676
|
-
|
|
677
|
-
this.drawGrid();
|
|
689
|
+
}
|
|
678
690
|
|
|
679
|
-
|
|
691
|
+
this._timeStart = - 1;
|
|
692
|
+
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
680
693
|
|
|
681
|
-
|
|
694
|
+
self.updateTbState( STATE.ANIMATION_FOCUS, true );
|
|
695
|
+
self.onFocusAnim( t, hitP, self._cameraMatrixState, self._gizmoMatrixState );
|
|
682
696
|
|
|
683
|
-
|
|
684
|
-
this.dispatchEvent( _endEvent );
|
|
697
|
+
} );
|
|
685
698
|
|
|
686
|
-
|
|
699
|
+
} else if ( hitP != null && ! this.enableAnimations ) {
|
|
687
700
|
|
|
688
|
-
|
|
701
|
+
this.updateTbState( STATE.FOCUS, true );
|
|
702
|
+
this.focus( hitP, this.scaleFactor );
|
|
703
|
+
this.updateTbState( STATE.IDLE, false );
|
|
704
|
+
this.dispatchEvent( _changeEvent );
|
|
689
705
|
|
|
690
|
-
|
|
706
|
+
}
|
|
691
707
|
|
|
692
|
-
|
|
708
|
+
}
|
|
693
709
|
|
|
710
|
+
this.dispatchEvent( _endEvent );
|
|
694
711
|
|
|
695
|
-
|
|
712
|
+
}
|
|
696
713
|
|
|
697
|
-
|
|
698
|
-
// |\
|
|
699
|
-
// | \
|
|
700
|
-
// | \
|
|
701
|
-
// x | \
|
|
702
|
-
// | \
|
|
703
|
-
// | \
|
|
704
|
-
// | _ _ _\
|
|
705
|
-
// y
|
|
714
|
+
onDoublePanStart() {
|
|
706
715
|
|
|
707
|
-
|
|
708
|
-
if ( event.deltaX != 0 ) {
|
|
716
|
+
if ( this.enabled && this.enablePan ) {
|
|
709
717
|
|
|
710
|
-
|
|
718
|
+
this.dispatchEvent( _startEvent );
|
|
711
719
|
|
|
712
|
-
|
|
720
|
+
this.updateTbState( STATE.PAN, true );
|
|
713
721
|
|
|
714
|
-
|
|
722
|
+
this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
|
|
723
|
+
this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement, true ) );
|
|
724
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
715
725
|
|
|
716
|
-
|
|
726
|
+
this.activateGizmos( false );
|
|
717
727
|
|
|
718
|
-
|
|
728
|
+
}
|
|
719
729
|
|
|
720
|
-
|
|
730
|
+
}
|
|
721
731
|
|
|
722
|
-
|
|
732
|
+
onDoublePanMove() {
|
|
723
733
|
|
|
724
|
-
|
|
734
|
+
if ( this.enabled && this.enablePan ) {
|
|
725
735
|
|
|
726
|
-
|
|
727
|
-
const x = this._v3_1.distanceTo( this._gizmos.position );
|
|
728
|
-
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
736
|
+
this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
|
|
729
737
|
|
|
730
|
-
|
|
731
|
-
xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
|
|
738
|
+
if ( this._state != STATE.PAN ) {
|
|
732
739
|
|
|
733
|
-
|
|
740
|
+
this.updateTbState( STATE.PAN, true );
|
|
741
|
+
this._startCursorPosition.copy( this._currentCursorPosition );
|
|
734
742
|
|
|
735
|
-
|
|
736
|
-
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
743
|
+
}
|
|
737
744
|
|
|
738
|
-
|
|
739
|
-
|
|
745
|
+
this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement, true ) );
|
|
746
|
+
this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition, true ) );
|
|
747
|
+
this.dispatchEvent( _changeEvent );
|
|
740
748
|
|
|
741
|
-
|
|
749
|
+
}
|
|
742
750
|
|
|
743
|
-
|
|
751
|
+
}
|
|
744
752
|
|
|
745
|
-
|
|
753
|
+
onDoublePanEnd() {
|
|
746
754
|
|
|
747
|
-
|
|
755
|
+
this.updateTbState( STATE.IDLE, false );
|
|
756
|
+
this.dispatchEvent( _endEvent );
|
|
748
757
|
|
|
749
|
-
|
|
750
|
-
size = x / newDistance;
|
|
758
|
+
}
|
|
751
759
|
|
|
752
|
-
|
|
753
|
-
this.applyTransformMatrix( this.scale( size, this._gizmos.position, false ) );
|
|
760
|
+
onRotateStart() {
|
|
754
761
|
|
|
755
|
-
|
|
762
|
+
if ( this.enabled && this.enableRotate ) {
|
|
756
763
|
|
|
757
|
-
|
|
764
|
+
this.dispatchEvent( _startEvent );
|
|
758
765
|
|
|
759
|
-
|
|
760
|
-
this.drawGrid();
|
|
766
|
+
this.updateTbState( STATE.ZROTATE, true );
|
|
761
767
|
|
|
762
|
-
|
|
768
|
+
//this._startFingerRotation = event.rotation;
|
|
763
769
|
|
|
764
|
-
|
|
770
|
+
this._startFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
|
|
771
|
+
this._currentFingerRotation = this._startFingerRotation;
|
|
765
772
|
|
|
766
|
-
|
|
767
|
-
this.dispatchEvent( _endEvent );
|
|
773
|
+
this.camera.getWorldDirection( this._rotationAxis ); //rotation axis
|
|
768
774
|
|
|
769
|
-
|
|
775
|
+
if ( ! this.enablePan && ! this.enableZoom ) {
|
|
770
776
|
|
|
771
|
-
|
|
777
|
+
this.activateGizmos( true );
|
|
772
778
|
|
|
773
779
|
}
|
|
774
780
|
|
|
775
781
|
}
|
|
776
782
|
|
|
777
|
-
}
|
|
783
|
+
}
|
|
778
784
|
|
|
779
|
-
|
|
785
|
+
onRotateMove() {
|
|
780
786
|
|
|
781
|
-
if ( this.enabled ) {
|
|
787
|
+
if ( this.enabled && this.enableRotate ) {
|
|
782
788
|
|
|
783
|
-
this.
|
|
789
|
+
this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
|
|
790
|
+
let rotationPoint;
|
|
784
791
|
|
|
785
|
-
|
|
792
|
+
if ( this._state != STATE.ZROTATE ) {
|
|
786
793
|
|
|
787
|
-
|
|
794
|
+
this.updateTbState( STATE.ZROTATE, true );
|
|
795
|
+
this._startFingerRotation = this._currentFingerRotation;
|
|
788
796
|
|
|
789
|
-
|
|
797
|
+
}
|
|
790
798
|
|
|
791
|
-
|
|
799
|
+
//this._currentFingerRotation = event.rotation;
|
|
800
|
+
this._currentFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
|
|
792
801
|
|
|
793
|
-
|
|
802
|
+
if ( ! this.enablePan ) {
|
|
794
803
|
|
|
795
|
-
|
|
804
|
+
rotationPoint = new Vector3().setFromMatrixPosition( this._gizmoMatrixState );
|
|
796
805
|
|
|
797
|
-
|
|
806
|
+
} else {
|
|
798
807
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
this._timeStart = - 1;
|
|
808
|
+
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
809
|
+
rotationPoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ).applyQuaternion( this.camera.quaternion ).multiplyScalar( 1 / this.camera.zoom ).add( this._v3_2 );
|
|
802
810
|
|
|
803
|
-
|
|
804
|
-
this.dispatchEvent( _changeEvent );
|
|
811
|
+
}
|
|
805
812
|
|
|
806
|
-
|
|
813
|
+
const amount = MathUtils.DEG2RAD * ( this._startFingerRotation - this._currentFingerRotation );
|
|
807
814
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
if ( this.enableGrid ) {
|
|
815
|
+
this.applyTransformMatrix( this.zRotate( rotationPoint, amount ) );
|
|
816
|
+
this.dispatchEvent( _changeEvent );
|
|
811
817
|
|
|
812
|
-
|
|
813
|
-
this.dispatchEvent( _changeEvent );
|
|
818
|
+
}
|
|
814
819
|
|
|
815
|
-
|
|
820
|
+
}
|
|
816
821
|
|
|
817
|
-
|
|
822
|
+
onRotateEnd() {
|
|
818
823
|
|
|
819
|
-
|
|
824
|
+
this.updateTbState( STATE.IDLE, false );
|
|
825
|
+
this.activateGizmos( false );
|
|
826
|
+
this.dispatchEvent( _endEvent );
|
|
820
827
|
|
|
821
|
-
|
|
828
|
+
}
|
|
822
829
|
|
|
823
|
-
|
|
830
|
+
onPinchStart() {
|
|
824
831
|
|
|
825
|
-
|
|
832
|
+
if ( this.enabled && this.enableZoom ) {
|
|
826
833
|
|
|
827
|
-
|
|
834
|
+
this.dispatchEvent( _startEvent );
|
|
835
|
+
this.updateTbState( STATE.SCALE, true );
|
|
828
836
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
this._timeStart = - 1;
|
|
837
|
+
this._startFingerDistance = this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] );
|
|
838
|
+
this._currentFingerDistance = this._startFingerDistance;
|
|
832
839
|
|
|
833
|
-
|
|
840
|
+
this.activateGizmos( false );
|
|
834
841
|
|
|
835
|
-
|
|
836
|
-
this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
|
|
837
|
-
this.activateGizmos( true );
|
|
838
|
-
if ( this.enableAnimations ) {
|
|
842
|
+
}
|
|
839
843
|
|
|
840
|
-
|
|
841
|
-
this._angleCurrent = this._anglePrev = 0;
|
|
842
|
-
this._cursorPosPrev.copy( this._startCursorPosition );
|
|
843
|
-
this._cursorPosCurr.copy( this._cursorPosPrev );
|
|
844
|
-
this._wCurr = 0;
|
|
845
|
-
this._wPrev = this._wCurr;
|
|
844
|
+
}
|
|
846
845
|
|
|
847
|
-
|
|
846
|
+
onPinchMove() {
|
|
848
847
|
|
|
849
|
-
|
|
850
|
-
break;
|
|
848
|
+
if ( this.enabled && this.enableZoom ) {
|
|
851
849
|
|
|
852
|
-
|
|
850
|
+
this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
|
|
851
|
+
const minDistance = 12; //minimum distance between fingers (in css pixels)
|
|
853
852
|
|
|
854
|
-
|
|
853
|
+
if ( this._state != STATE.SCALE ) {
|
|
855
854
|
|
|
856
|
-
|
|
855
|
+
this._startFingerDistance = this._currentFingerDistance;
|
|
856
|
+
this.updateTbState( STATE.SCALE, true );
|
|
857
857
|
|
|
858
|
-
|
|
858
|
+
}
|
|
859
859
|
|
|
860
|
-
|
|
860
|
+
this._currentFingerDistance = Math.max( this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] ), minDistance * this._devPxRatio );
|
|
861
|
+
const amount = this._currentFingerDistance / this._startFingerDistance;
|
|
861
862
|
|
|
862
|
-
|
|
863
|
-
this._animationId = - 1;
|
|
864
|
-
this._timeStart = - 1;
|
|
863
|
+
let scalePoint;
|
|
865
864
|
|
|
866
|
-
|
|
867
|
-
this.dispatchEvent( _changeEvent );
|
|
865
|
+
if ( ! this.enablePan ) {
|
|
868
866
|
|
|
869
|
-
|
|
867
|
+
scalePoint = this._gizmos.position;
|
|
870
868
|
|
|
871
|
-
|
|
872
|
-
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
873
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
874
|
-
break;
|
|
869
|
+
} else {
|
|
875
870
|
|
|
876
|
-
|
|
871
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
877
872
|
|
|
878
|
-
|
|
873
|
+
scalePoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement )
|
|
874
|
+
.applyQuaternion( this.camera.quaternion )
|
|
875
|
+
.multiplyScalar( 1 / this.camera.zoom )
|
|
876
|
+
.add( this._gizmos.position );
|
|
879
877
|
|
|
880
|
-
|
|
878
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
881
879
|
|
|
882
|
-
|
|
880
|
+
scalePoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement )
|
|
881
|
+
.applyQuaternion( this.camera.quaternion )
|
|
882
|
+
.add( this._gizmos.position );
|
|
883
883
|
|
|
884
|
-
|
|
884
|
+
}
|
|
885
885
|
|
|
886
|
-
|
|
887
|
-
this._animationId = - 1;
|
|
888
|
-
this._timeStart = - 1;
|
|
886
|
+
}
|
|
889
887
|
|
|
890
|
-
|
|
891
|
-
|
|
888
|
+
this.applyTransformMatrix( this.scale( amount, scalePoint ) );
|
|
889
|
+
this.dispatchEvent( _changeEvent );
|
|
892
890
|
|
|
893
|
-
|
|
891
|
+
}
|
|
894
892
|
|
|
895
|
-
|
|
896
|
-
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
897
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
898
|
-
break;
|
|
893
|
+
}
|
|
899
894
|
|
|
900
|
-
|
|
895
|
+
onPinchEnd() {
|
|
901
896
|
|
|
902
|
-
|
|
897
|
+
this.updateTbState( STATE.IDLE, false );
|
|
898
|
+
this.dispatchEvent( _endEvent );
|
|
903
899
|
|
|
904
|
-
}
|
|
900
|
+
}
|
|
905
901
|
|
|
906
|
-
|
|
902
|
+
onTriplePanStart() {
|
|
907
903
|
|
|
908
|
-
if ( this.enabled ) {
|
|
904
|
+
if ( this.enabled && this.enableZoom ) {
|
|
909
905
|
|
|
910
|
-
|
|
911
|
-
this.setCenter( event.clientX, event.clientY );
|
|
906
|
+
this.dispatchEvent( _startEvent );
|
|
912
907
|
|
|
913
|
-
|
|
908
|
+
this.updateTbState( STATE.SCALE, true );
|
|
914
909
|
|
|
915
|
-
|
|
910
|
+
//const center = event.center;
|
|
911
|
+
let clientX = 0;
|
|
912
|
+
let clientY = 0;
|
|
913
|
+
const nFingers = this._touchCurrent.length;
|
|
916
914
|
|
|
917
|
-
|
|
915
|
+
for ( let i = 0; i < nFingers; i ++ ) {
|
|
918
916
|
|
|
919
|
-
|
|
917
|
+
clientX += this._touchCurrent[ i ].clientX;
|
|
918
|
+
clientY += this._touchCurrent[ i ].clientY;
|
|
920
919
|
|
|
921
|
-
|
|
920
|
+
}
|
|
922
921
|
|
|
923
|
-
|
|
924
|
-
this.dispatchEvent( _startEvent );
|
|
922
|
+
this.setCenter( clientX / nFingers, clientY / nFingers );
|
|
925
923
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if ( this.enableGrid ) {
|
|
924
|
+
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
925
|
+
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
929
926
|
|
|
930
|
-
|
|
927
|
+
}
|
|
931
928
|
|
|
932
|
-
|
|
929
|
+
}
|
|
933
930
|
|
|
934
|
-
|
|
931
|
+
onTriplePanMove() {
|
|
935
932
|
|
|
936
|
-
|
|
933
|
+
if ( this.enabled && this.enableZoom ) {
|
|
937
934
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
935
|
+
// fov / 2
|
|
936
|
+
// |\
|
|
937
|
+
// | \
|
|
938
|
+
// | \
|
|
939
|
+
// x | \
|
|
940
|
+
// | \
|
|
941
|
+
// | \
|
|
942
|
+
// | _ _ _\
|
|
943
|
+
// y
|
|
941
944
|
|
|
942
|
-
|
|
945
|
+
//const center = event.center;
|
|
946
|
+
let clientX = 0;
|
|
947
|
+
let clientY = 0;
|
|
948
|
+
const nFingers = this._touchCurrent.length;
|
|
943
949
|
|
|
944
|
-
|
|
950
|
+
for ( let i = 0; i < nFingers; i ++ ) {
|
|
945
951
|
|
|
946
|
-
|
|
952
|
+
clientX += this._touchCurrent[ i ].clientX;
|
|
953
|
+
clientY += this._touchCurrent[ i ].clientY;
|
|
947
954
|
|
|
948
|
-
|
|
955
|
+
}
|
|
949
956
|
|
|
950
|
-
|
|
957
|
+
this.setCenter( clientX / nFingers, clientY / nFingers );
|
|
951
958
|
|
|
952
|
-
|
|
959
|
+
const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
|
|
960
|
+
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
953
961
|
|
|
954
|
-
|
|
962
|
+
const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
|
|
955
963
|
|
|
956
|
-
|
|
957
|
-
this.dispatchEvent( _startEvent );
|
|
964
|
+
let size = 1;
|
|
958
965
|
|
|
959
|
-
|
|
960
|
-
this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
|
|
966
|
+
if ( movement < 0 ) {
|
|
961
967
|
|
|
962
|
-
|
|
968
|
+
size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
|
|
963
969
|
|
|
964
|
-
|
|
970
|
+
} else if ( movement > 0 ) {
|
|
965
971
|
|
|
966
|
-
|
|
972
|
+
size = Math.pow( this.scaleFactor, movement * screenNotches );
|
|
967
973
|
|
|
968
|
-
|
|
974
|
+
}
|
|
969
975
|
|
|
970
|
-
|
|
976
|
+
this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
|
|
977
|
+
const x = this._v3_1.distanceTo( this._gizmos.position );
|
|
978
|
+
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
971
979
|
|
|
972
|
-
|
|
973
|
-
|
|
980
|
+
//check min and max distance
|
|
981
|
+
xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
|
|
974
982
|
|
|
975
|
-
|
|
976
|
-
const angle = this._startCursorPosition.angleTo( this._currentCursorPosition );
|
|
977
|
-
const amount = Math.max( distance / this._tbRadius, angle ); //effective rotation angle
|
|
983
|
+
const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
|
|
978
984
|
|
|
979
|
-
|
|
985
|
+
//calculate new fov
|
|
986
|
+
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
980
987
|
|
|
981
|
-
|
|
988
|
+
//check min and max fov
|
|
989
|
+
newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
|
|
982
990
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
this._angleCurrent = amount;
|
|
987
|
-
this._cursorPosPrev.copy( this._cursorPosCurr );
|
|
988
|
-
this._cursorPosCurr.copy( this._currentCursorPosition );
|
|
989
|
-
this._wPrev = this._wCurr;
|
|
990
|
-
this._wCurr = this.calculateAngularSpeed( this._anglePrev, this._angleCurrent, this._timePrev, this._timeCurrent );
|
|
991
|
+
const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
|
|
992
|
+
size = x / newDistance;
|
|
993
|
+
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
991
994
|
|
|
992
|
-
|
|
995
|
+
this.setFov( newFov );
|
|
996
|
+
this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
|
|
993
997
|
|
|
994
|
-
|
|
998
|
+
//adjusting distance
|
|
999
|
+
_offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
|
|
1000
|
+
this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
995
1001
|
|
|
996
|
-
|
|
1002
|
+
this.dispatchEvent( _changeEvent );
|
|
997
1003
|
|
|
998
|
-
|
|
1004
|
+
}
|
|
999
1005
|
|
|
1000
|
-
|
|
1006
|
+
}
|
|
1001
1007
|
|
|
1002
|
-
|
|
1008
|
+
onTriplePanEnd() {
|
|
1003
1009
|
|
|
1004
|
-
|
|
1010
|
+
this.updateTbState( STATE.IDLE, false );
|
|
1011
|
+
this.dispatchEvent( _endEvent );
|
|
1012
|
+
//this.dispatchEvent( _changeEvent );
|
|
1005
1013
|
|
|
1006
|
-
|
|
1014
|
+
}
|
|
1007
1015
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1016
|
+
/**
|
|
1017
|
+
* Set _center's x/y coordinates
|
|
1018
|
+
* @param {Number} clientX
|
|
1019
|
+
* @param {Number} clientY
|
|
1020
|
+
*/
|
|
1021
|
+
setCenter( clientX, clientY ) {
|
|
1010
1022
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
1023
|
+
_center.x = clientX;
|
|
1024
|
+
_center.y = clientY;
|
|
1014
1025
|
|
|
1015
|
-
|
|
1026
|
+
}
|
|
1016
1027
|
|
|
1017
|
-
|
|
1028
|
+
/**
|
|
1029
|
+
* Set default mouse actions
|
|
1030
|
+
*/
|
|
1031
|
+
initializeMouseActions() {
|
|
1018
1032
|
|
|
1019
|
-
|
|
1033
|
+
this.setMouseAction( 'PAN', 0, 'CTRL' );
|
|
1034
|
+
this.setMouseAction( 'PAN', 2 );
|
|
1020
1035
|
|
|
1021
|
-
|
|
1036
|
+
this.setMouseAction( 'ROTATE', 0 );
|
|
1022
1037
|
|
|
1023
|
-
|
|
1038
|
+
this.setMouseAction( 'ZOOM', 'WHEEL' );
|
|
1039
|
+
this.setMouseAction( 'ZOOM', 1 );
|
|
1024
1040
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
1041
|
+
this.setMouseAction( 'FOV', 'WHEEL', 'SHIFT' );
|
|
1042
|
+
this.setMouseAction( 'FOV', 1, 'SHIFT' );
|
|
1028
1043
|
|
|
1029
|
-
const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
|
|
1030
1044
|
|
|
1031
|
-
|
|
1045
|
+
}
|
|
1032
1046
|
|
|
1033
|
-
|
|
1047
|
+
/**
|
|
1048
|
+
* Compare two mouse actions
|
|
1049
|
+
* @param {Object} action1
|
|
1050
|
+
* @param {Object} action2
|
|
1051
|
+
* @returns {Boolean} True if action1 and action 2 are the same mouse action, false otherwise
|
|
1052
|
+
*/
|
|
1053
|
+
compareMouseAction( action1, action2 ) {
|
|
1034
1054
|
|
|
1035
|
-
|
|
1055
|
+
if ( action1.operation == action2.operation ) {
|
|
1036
1056
|
|
|
1037
|
-
|
|
1057
|
+
if ( action1.mouse == action2.mouse && action1.key == action2.key ) {
|
|
1038
1058
|
|
|
1039
|
-
|
|
1059
|
+
return true;
|
|
1040
1060
|
|
|
1041
|
-
|
|
1061
|
+
} else {
|
|
1042
1062
|
|
|
1043
|
-
|
|
1063
|
+
return false;
|
|
1044
1064
|
|
|
1045
|
-
|
|
1065
|
+
}
|
|
1046
1066
|
|
|
1047
|
-
|
|
1067
|
+
} else {
|
|
1048
1068
|
|
|
1049
|
-
|
|
1069
|
+
return false;
|
|
1050
1070
|
|
|
1051
|
-
|
|
1071
|
+
}
|
|
1052
1072
|
|
|
1053
|
-
|
|
1073
|
+
}
|
|
1054
1074
|
|
|
1055
|
-
|
|
1075
|
+
/**
|
|
1076
|
+
* Set a new mouse action by specifying the operation to be performed and a mouse/key combination. In case of conflict, replaces the existing one
|
|
1077
|
+
* @param {String} operation The operation to be performed ('PAN', 'ROTATE', 'ZOOM', 'FOV)
|
|
1078
|
+
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
|
|
1079
|
+
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1080
|
+
* @returns {Boolean} True if the mouse action has been successfully added, false otherwise
|
|
1081
|
+
*/
|
|
1082
|
+
setMouseAction( operation, mouse, key = null ) {
|
|
1056
1083
|
|
|
1057
|
-
|
|
1084
|
+
const operationInput = [ 'PAN', 'ROTATE', 'ZOOM', 'FOV' ];
|
|
1085
|
+
const mouseInput = [ 0, 1, 2, 'WHEEL' ];
|
|
1086
|
+
const keyInput = [ 'CTRL', 'SHIFT', null ];
|
|
1087
|
+
let state;
|
|
1058
1088
|
|
|
1059
|
-
|
|
1089
|
+
if ( ! operationInput.includes( operation ) || ! mouseInput.includes( mouse ) || ! keyInput.includes( key ) ) {
|
|
1060
1090
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1091
|
+
//invalid parameters
|
|
1092
|
+
return false;
|
|
1063
1093
|
|
|
1064
|
-
|
|
1065
|
-
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
1066
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
1094
|
+
}
|
|
1067
1095
|
|
|
1068
|
-
|
|
1096
|
+
if ( mouse == 'WHEEL' ) {
|
|
1069
1097
|
|
|
1070
|
-
|
|
1098
|
+
if ( operation != 'ZOOM' && operation != 'FOV' ) {
|
|
1071
1099
|
|
|
1072
|
-
|
|
1100
|
+
//cannot associate 2D operation to 1D input
|
|
1101
|
+
return false;
|
|
1073
1102
|
|
|
1074
|
-
|
|
1103
|
+
}
|
|
1075
1104
|
|
|
1076
|
-
|
|
1105
|
+
}
|
|
1077
1106
|
|
|
1078
|
-
|
|
1079
|
-
const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
|
|
1080
|
-
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
1107
|
+
switch ( operation ) {
|
|
1081
1108
|
|
|
1082
|
-
|
|
1109
|
+
case 'PAN':
|
|
1083
1110
|
|
|
1084
|
-
|
|
1111
|
+
state = STATE.PAN;
|
|
1112
|
+
break;
|
|
1085
1113
|
|
|
1086
|
-
|
|
1114
|
+
case 'ROTATE':
|
|
1087
1115
|
|
|
1088
|
-
|
|
1116
|
+
state = STATE.ROTATE;
|
|
1117
|
+
break;
|
|
1089
1118
|
|
|
1090
|
-
|
|
1119
|
+
case 'ZOOM':
|
|
1091
1120
|
|
|
1092
|
-
|
|
1121
|
+
state = STATE.SCALE;
|
|
1122
|
+
break;
|
|
1093
1123
|
|
|
1094
|
-
|
|
1124
|
+
case 'FOV':
|
|
1095
1125
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
1099
|
-
|
|
1100
|
-
//check min and max distance
|
|
1101
|
-
xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
|
|
1102
|
-
|
|
1103
|
-
const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
|
|
1104
|
-
|
|
1105
|
-
//calculate new fov
|
|
1106
|
-
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
1126
|
+
state = STATE.FOV;
|
|
1127
|
+
break;
|
|
1107
1128
|
|
|
1108
|
-
|
|
1109
|
-
newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
|
|
1129
|
+
}
|
|
1110
1130
|
|
|
1111
|
-
|
|
1112
|
-
size = x / newDistance;
|
|
1113
|
-
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
1131
|
+
const action = {
|
|
1114
1132
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1133
|
+
operation: operation,
|
|
1134
|
+
mouse: mouse,
|
|
1135
|
+
key: key,
|
|
1136
|
+
state: state
|
|
1117
1137
|
|
|
1118
|
-
|
|
1119
|
-
_offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
|
|
1120
|
-
this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
1138
|
+
};
|
|
1121
1139
|
|
|
1122
|
-
|
|
1140
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1123
1141
|
|
|
1124
|
-
|
|
1142
|
+
if ( this.mouseActions[ i ].mouse == action.mouse && this.mouseActions[ i ].key == action.key ) {
|
|
1125
1143
|
|
|
1126
|
-
|
|
1144
|
+
this.mouseActions.splice( i, 1, action );
|
|
1145
|
+
return true;
|
|
1127
1146
|
|
|
1128
1147
|
}
|
|
1129
1148
|
|
|
1130
|
-
this.dispatchEvent( _changeEvent );
|
|
1131
|
-
|
|
1132
1149
|
}
|
|
1133
1150
|
|
|
1134
|
-
|
|
1151
|
+
this.mouseActions.push( action );
|
|
1152
|
+
return true;
|
|
1135
1153
|
|
|
1136
|
-
|
|
1154
|
+
}
|
|
1137
1155
|
|
|
1138
|
-
|
|
1156
|
+
/**
|
|
1157
|
+
* Remove a mouse action by specifying its mouse/key combination
|
|
1158
|
+
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
|
|
1159
|
+
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1160
|
+
* @returns {Boolean} True if the operation has been succesfully removed, false otherwise
|
|
1161
|
+
*/
|
|
1162
|
+
unsetMouseAction( mouse, key = null ) {
|
|
1139
1163
|
|
|
1164
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1140
1165
|
|
|
1141
|
-
if (
|
|
1166
|
+
if ( this.mouseActions[ i ].mouse == mouse && this.mouseActions[ i ].key == key ) {
|
|
1142
1167
|
|
|
1143
|
-
|
|
1168
|
+
this.mouseActions.splice( i, 1 );
|
|
1169
|
+
return true;
|
|
1144
1170
|
|
|
1145
1171
|
}
|
|
1146
1172
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
//perform rotation animation
|
|
1150
|
-
const deltaTime = ( performance.now() - this._timeCurrent );
|
|
1151
|
-
if ( deltaTime < 120 ) {
|
|
1152
|
-
|
|
1153
|
-
const w = Math.abs( ( this._wPrev + this._wCurr ) / 2 );
|
|
1154
|
-
|
|
1155
|
-
const self = this;
|
|
1156
|
-
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
1157
|
-
|
|
1158
|
-
self.updateTbState( STATE.ANIMATION_ROTATE, true );
|
|
1159
|
-
const rotationAxis = self.calculateRotationAxis( self._cursorPosPrev, self._cursorPosCurr );
|
|
1173
|
+
}
|
|
1160
1174
|
|
|
1161
|
-
|
|
1175
|
+
return false;
|
|
1162
1176
|
|
|
1163
|
-
|
|
1177
|
+
}
|
|
1164
1178
|
|
|
1165
|
-
|
|
1179
|
+
/**
|
|
1180
|
+
* Return the operation associated to a mouse/keyboard combination
|
|
1181
|
+
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
|
|
1182
|
+
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1183
|
+
* @returns The operation if it has been found, null otherwise
|
|
1184
|
+
*/
|
|
1185
|
+
getOpFromAction( mouse, key ) {
|
|
1166
1186
|
|
|
1167
|
-
|
|
1168
|
-
this.updateTbState( STATE.IDLE, false );
|
|
1169
|
-
this.activateGizmos( false );
|
|
1170
|
-
this.dispatchEvent( _changeEvent );
|
|
1187
|
+
let action;
|
|
1171
1188
|
|
|
1172
|
-
|
|
1189
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1173
1190
|
|
|
1174
|
-
|
|
1191
|
+
action = this.mouseActions[ i ];
|
|
1192
|
+
if ( action.mouse == mouse && action.key == key ) {
|
|
1175
1193
|
|
|
1176
|
-
|
|
1177
|
-
this.activateGizmos( false );
|
|
1178
|
-
this.dispatchEvent( _changeEvent );
|
|
1194
|
+
return action.operation;
|
|
1179
1195
|
|
|
1180
1196
|
}
|
|
1181
1197
|
|
|
1182
|
-
}
|
|
1198
|
+
}
|
|
1183
1199
|
|
|
1184
|
-
|
|
1200
|
+
if ( key != null ) {
|
|
1185
1201
|
|
|
1186
|
-
|
|
1202
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1187
1203
|
|
|
1188
|
-
this.
|
|
1204
|
+
action = this.mouseActions[ i ];
|
|
1205
|
+
if ( action.mouse == mouse && action.key == null ) {
|
|
1189
1206
|
|
|
1190
|
-
|
|
1207
|
+
return action.operation;
|
|
1191
1208
|
|
|
1192
|
-
|
|
1193
|
-
this.dispatchEvent( _changeEvent );
|
|
1209
|
+
}
|
|
1194
1210
|
|
|
1211
|
+
}
|
|
1195
1212
|
|
|
1196
1213
|
}
|
|
1197
1214
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
};
|
|
1215
|
+
return null;
|
|
1201
1216
|
|
|
1202
|
-
|
|
1217
|
+
}
|
|
1203
1218
|
|
|
1204
|
-
|
|
1219
|
+
/**
|
|
1220
|
+
* Get the operation associated to mouse and key combination and returns the corresponding FSA state
|
|
1221
|
+
* @param {Number} mouse Mouse button
|
|
1222
|
+
* @param {String} key Keyboard modifier
|
|
1223
|
+
* @returns The FSA state obtained from the operation associated to mouse/keyboard combination
|
|
1224
|
+
*/
|
|
1225
|
+
getOpStateFromAction( mouse, key ) {
|
|
1205
1226
|
|
|
1206
|
-
|
|
1227
|
+
let action;
|
|
1207
1228
|
|
|
1208
|
-
|
|
1209
|
-
const hitP = this.unprojectOnObj( this.getCursorNDC( _center.x, _center.y, this.domElement ), this.camera );
|
|
1229
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1210
1230
|
|
|
1211
|
-
|
|
1231
|
+
action = this.mouseActions[ i ];
|
|
1232
|
+
if ( action.mouse == mouse && action.key == key ) {
|
|
1212
1233
|
|
|
1213
|
-
|
|
1214
|
-
if ( this._animationId != - 1 ) {
|
|
1234
|
+
return action.state;
|
|
1215
1235
|
|
|
1216
|
-
|
|
1236
|
+
}
|
|
1217
1237
|
|
|
1218
|
-
|
|
1238
|
+
}
|
|
1219
1239
|
|
|
1220
|
-
|
|
1221
|
-
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
1240
|
+
if ( key != null ) {
|
|
1222
1241
|
|
|
1223
|
-
|
|
1224
|
-
self.onFocusAnim( t, hitP, self._cameraMatrixState, self._gizmoMatrixState );
|
|
1242
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
1225
1243
|
|
|
1226
|
-
|
|
1244
|
+
action = this.mouseActions[ i ];
|
|
1245
|
+
if ( action.mouse == mouse && action.key == null ) {
|
|
1227
1246
|
|
|
1228
|
-
|
|
1247
|
+
return action.state;
|
|
1229
1248
|
|
|
1230
|
-
|
|
1231
|
-
this.focus( hitP, this.scaleFactor );
|
|
1232
|
-
this.updateTbState( STATE.IDLE, false );
|
|
1233
|
-
this.dispatchEvent( _changeEvent );
|
|
1249
|
+
}
|
|
1234
1250
|
|
|
1235
1251
|
}
|
|
1236
1252
|
|
|
1237
1253
|
}
|
|
1238
1254
|
|
|
1239
|
-
|
|
1255
|
+
return null;
|
|
1240
1256
|
|
|
1241
|
-
}
|
|
1257
|
+
}
|
|
1242
1258
|
|
|
1243
|
-
|
|
1259
|
+
/**
|
|
1260
|
+
* Calculate the angle between two pointers
|
|
1261
|
+
* @param {PointerEvent} p1
|
|
1262
|
+
* @param {PointerEvent} p2
|
|
1263
|
+
* @returns {Number} The angle between two pointers in degrees
|
|
1264
|
+
*/
|
|
1265
|
+
getAngle( p1, p2 ) {
|
|
1244
1266
|
|
|
1245
|
-
|
|
1267
|
+
return Math.atan2( p2.clientY - p1.clientY, p2.clientX - p1.clientX ) * 180 / Math.PI;
|
|
1246
1268
|
|
|
1247
|
-
|
|
1269
|
+
}
|
|
1248
1270
|
|
|
1249
|
-
|
|
1271
|
+
/**
|
|
1272
|
+
* Update a PointerEvent inside current pointerevents array
|
|
1273
|
+
* @param {PointerEvent} event
|
|
1274
|
+
*/
|
|
1275
|
+
updateTouchEvent( event ) {
|
|
1250
1276
|
|
|
1251
|
-
|
|
1252
|
-
this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement, true ) );
|
|
1253
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
1277
|
+
for ( let i = 0; i < this._touchCurrent.length; i ++ ) {
|
|
1254
1278
|
|
|
1255
|
-
this.
|
|
1279
|
+
if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
|
|
1280
|
+
|
|
1281
|
+
this._touchCurrent.splice( i, 1, event );
|
|
1282
|
+
break;
|
|
1283
|
+
|
|
1284
|
+
}
|
|
1256
1285
|
|
|
1257
1286
|
}
|
|
1258
1287
|
|
|
1259
|
-
}
|
|
1288
|
+
}
|
|
1260
1289
|
|
|
1261
|
-
|
|
1290
|
+
/**
|
|
1291
|
+
* Apply a transformation matrix, to the camera and gizmos
|
|
1292
|
+
* @param {Object} transformation Object containing matrices to apply to camera and gizmos
|
|
1293
|
+
*/
|
|
1294
|
+
applyTransformMatrix( transformation ) {
|
|
1262
1295
|
|
|
1263
|
-
if (
|
|
1296
|
+
if ( transformation.camera != null ) {
|
|
1264
1297
|
|
|
1265
|
-
this.
|
|
1298
|
+
this._m4_1.copy( this._cameraMatrixState ).premultiply( transformation.camera );
|
|
1299
|
+
this._m4_1.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
1300
|
+
this.camera.updateMatrix();
|
|
1266
1301
|
|
|
1267
|
-
|
|
1302
|
+
//update camera up vector
|
|
1303
|
+
if ( this._state == STATE.ROTATE || this._state == STATE.ZROTATE || this._state == STATE.ANIMATION_ROTATE ) {
|
|
1268
1304
|
|
|
1269
|
-
this.
|
|
1270
|
-
this._startCursorPosition.copy( this._currentCursorPosition );
|
|
1305
|
+
this.camera.up.copy( this._upState ).applyQuaternion( this.camera.quaternion );
|
|
1271
1306
|
|
|
1272
1307
|
}
|
|
1273
1308
|
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
if ( transformation.gizmos != null ) {
|
|
1312
|
+
|
|
1313
|
+
this._m4_1.copy( this._gizmoMatrixState ).premultiply( transformation.gizmos );
|
|
1314
|
+
this._m4_1.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1315
|
+
this._gizmos.updateMatrix();
|
|
1277
1316
|
|
|
1278
1317
|
}
|
|
1279
1318
|
|
|
1280
|
-
|
|
1319
|
+
if ( this._state == STATE.SCALE || this._state == STATE.FOCUS || this._state == STATE.ANIMATION_FOCUS ) {
|
|
1281
1320
|
|
|
1282
|
-
|
|
1321
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
1283
1322
|
|
|
1284
|
-
|
|
1285
|
-
this.dispatchEvent( _endEvent );
|
|
1323
|
+
if ( this.adjustNearFar ) {
|
|
1286
1324
|
|
|
1287
|
-
|
|
1325
|
+
const cameraDistance = this.camera.position.distanceTo( this._gizmos.position );
|
|
1288
1326
|
|
|
1327
|
+
const bb = new Box3();
|
|
1328
|
+
bb.setFromObject( this._gizmos );
|
|
1329
|
+
const sphere = new Sphere();
|
|
1330
|
+
bb.getBoundingSphere( sphere );
|
|
1289
1331
|
|
|
1290
|
-
|
|
1332
|
+
const adjustedNearPosition = Math.max( this._nearPos0, sphere.radius + sphere.center.length() );
|
|
1333
|
+
const regularNearPosition = cameraDistance - this._initialNear;
|
|
1291
1334
|
|
|
1292
|
-
|
|
1335
|
+
const minNearPos = Math.min( adjustedNearPosition, regularNearPosition );
|
|
1336
|
+
this.camera.near = cameraDistance - minNearPos;
|
|
1293
1337
|
|
|
1294
|
-
this.dispatchEvent( _startEvent );
|
|
1295
1338
|
|
|
1296
|
-
|
|
1339
|
+
const adjustedFarPosition = Math.min( this._farPos0, - sphere.radius + sphere.center.length() );
|
|
1340
|
+
const regularFarPosition = cameraDistance - this._initialFar;
|
|
1297
1341
|
|
|
1298
|
-
|
|
1342
|
+
const minFarPos = Math.min( adjustedFarPosition, regularFarPosition );
|
|
1343
|
+
this.camera.far = cameraDistance - minFarPos;
|
|
1299
1344
|
|
|
1300
|
-
|
|
1301
|
-
this._currentFingerRotation = this._startFingerRotation;
|
|
1345
|
+
this.camera.updateProjectionMatrix();
|
|
1302
1346
|
|
|
1303
|
-
|
|
1347
|
+
} else {
|
|
1304
1348
|
|
|
1305
|
-
|
|
1349
|
+
let update = false;
|
|
1306
1350
|
|
|
1307
|
-
this.
|
|
1351
|
+
if ( this.camera.near != this._initialNear ) {
|
|
1308
1352
|
|
|
1309
|
-
|
|
1353
|
+
this.camera.near = this._initialNear;
|
|
1354
|
+
update = true;
|
|
1310
1355
|
|
|
1311
|
-
|
|
1356
|
+
}
|
|
1312
1357
|
|
|
1313
|
-
|
|
1358
|
+
if ( this.camera.far != this._initialFar ) {
|
|
1314
1359
|
|
|
1315
|
-
|
|
1360
|
+
this.camera.far = this._initialFar;
|
|
1361
|
+
update = true;
|
|
1316
1362
|
|
|
1317
|
-
|
|
1363
|
+
}
|
|
1318
1364
|
|
|
1319
|
-
|
|
1320
|
-
let rotationPoint;
|
|
1365
|
+
if ( update ) {
|
|
1321
1366
|
|
|
1322
|
-
|
|
1367
|
+
this.camera.updateProjectionMatrix();
|
|
1323
1368
|
|
|
1324
|
-
|
|
1325
|
-
this._startFingerRotation = this._currentFingerRotation;
|
|
1369
|
+
}
|
|
1326
1370
|
|
|
1327
1371
|
}
|
|
1328
1372
|
|
|
1329
|
-
|
|
1330
|
-
this._currentFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
|
|
1331
|
-
|
|
1332
|
-
if ( ! this.enablePan ) {
|
|
1333
|
-
|
|
1334
|
-
rotationPoint = new Vector3().setFromMatrixPosition( this._gizmoMatrixState );
|
|
1335
|
-
|
|
1336
|
-
} else {
|
|
1373
|
+
}
|
|
1337
1374
|
|
|
1338
|
-
|
|
1339
|
-
rotationPoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ).applyQuaternion( this.camera.quaternion ).multiplyScalar( 1 / this.camera.zoom ).add( this._v3_2 );
|
|
1375
|
+
}
|
|
1340
1376
|
|
|
1341
|
-
|
|
1377
|
+
/**
|
|
1378
|
+
* Calculate the angular speed
|
|
1379
|
+
* @param {Number} p0 Position at t0
|
|
1380
|
+
* @param {Number} p1 Position at t1
|
|
1381
|
+
* @param {Number} t0 Initial time in milliseconds
|
|
1382
|
+
* @param {Number} t1 Ending time in milliseconds
|
|
1383
|
+
*/
|
|
1384
|
+
calculateAngularSpeed( p0, p1, t0, t1 ) {
|
|
1342
1385
|
|
|
1343
|
-
|
|
1386
|
+
const s = p1 - p0;
|
|
1387
|
+
const t = ( t1 - t0 ) / 1000;
|
|
1388
|
+
if ( t == 0 ) {
|
|
1344
1389
|
|
|
1345
|
-
|
|
1346
|
-
this.dispatchEvent( _changeEvent );
|
|
1390
|
+
return 0;
|
|
1347
1391
|
|
|
1348
1392
|
}
|
|
1349
1393
|
|
|
1350
|
-
|
|
1394
|
+
return s / t;
|
|
1351
1395
|
|
|
1352
|
-
|
|
1396
|
+
}
|
|
1353
1397
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1398
|
+
/**
|
|
1399
|
+
* Calculate the distance between two pointers
|
|
1400
|
+
* @param {PointerEvent} p0 The first pointer
|
|
1401
|
+
* @param {PointerEvent} p1 The second pointer
|
|
1402
|
+
* @returns {number} The distance between the two pointers
|
|
1403
|
+
*/
|
|
1404
|
+
calculatePointersDistance( p0, p1 ) {
|
|
1357
1405
|
|
|
1358
|
-
|
|
1406
|
+
return Math.sqrt( Math.pow( p1.clientX - p0.clientX, 2 ) + Math.pow( p1.clientY - p0.clientY, 2 ) );
|
|
1359
1407
|
|
|
1360
|
-
|
|
1408
|
+
}
|
|
1361
1409
|
|
|
1362
|
-
|
|
1410
|
+
/**
|
|
1411
|
+
* Calculate the rotation axis as the vector perpendicular between two vectors
|
|
1412
|
+
* @param {Vector3} vec1 The first vector
|
|
1413
|
+
* @param {Vector3} vec2 The second vector
|
|
1414
|
+
* @returns {Vector3} The normalized rotation axis
|
|
1415
|
+
*/
|
|
1416
|
+
calculateRotationAxis( vec1, vec2 ) {
|
|
1363
1417
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1418
|
+
this._rotationMatrix.extractRotation( this._cameraMatrixState );
|
|
1419
|
+
this._quat.setFromRotationMatrix( this._rotationMatrix );
|
|
1366
1420
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1421
|
+
this._rotationAxis.crossVectors( vec1, vec2 ).applyQuaternion( this._quat );
|
|
1422
|
+
return this._rotationAxis.normalize().clone();
|
|
1369
1423
|
|
|
1370
|
-
|
|
1424
|
+
}
|
|
1371
1425
|
|
|
1372
|
-
|
|
1426
|
+
/**
|
|
1427
|
+
* Calculate the trackball radius so that gizmo's diamater will be 2/3 of the minimum side of the camera frustum
|
|
1428
|
+
* @param {Camera} camera
|
|
1429
|
+
* @returns {Number} The trackball radius
|
|
1430
|
+
*/
|
|
1431
|
+
calculateTbRadius( camera ) {
|
|
1373
1432
|
|
|
1374
|
-
|
|
1433
|
+
const distance = camera.position.distanceTo( this._gizmos.position );
|
|
1375
1434
|
|
|
1376
|
-
|
|
1435
|
+
if ( camera.type == 'PerspectiveCamera' ) {
|
|
1377
1436
|
|
|
1378
|
-
|
|
1437
|
+
const halfFovV = MathUtils.DEG2RAD * camera.fov * 0.5; //vertical fov/2 in radians
|
|
1438
|
+
const halfFovH = Math.atan( ( camera.aspect ) * Math.tan( halfFovV ) ); //horizontal fov/2 in radians
|
|
1439
|
+
return Math.tan( Math.min( halfFovV, halfFovH ) ) * distance * this.radiusFactor;
|
|
1379
1440
|
|
|
1380
|
-
|
|
1381
|
-
const minDistance = 12; //minimum distance between fingers (in css pixels)
|
|
1441
|
+
} else if ( camera.type == 'OrthographicCamera' ) {
|
|
1382
1442
|
|
|
1383
|
-
|
|
1443
|
+
return Math.min( camera.top, camera.right ) * this.radiusFactor;
|
|
1384
1444
|
|
|
1385
|
-
|
|
1386
|
-
this.updateTbState( STATE.SCALE, true );
|
|
1445
|
+
}
|
|
1387
1446
|
|
|
1388
|
-
|
|
1447
|
+
}
|
|
1389
1448
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1449
|
+
/**
|
|
1450
|
+
* Focus operation consist of positioning the point of interest in front of the camera and a slightly zoom in
|
|
1451
|
+
* @param {Vector3} point The point of interest
|
|
1452
|
+
* @param {Number} size Scale factor
|
|
1453
|
+
* @param {Number} amount Amount of operation to be completed (used for focus animations, default is complete full operation)
|
|
1454
|
+
*/
|
|
1455
|
+
focus( point, size, amount = 1 ) {
|
|
1392
1456
|
|
|
1393
|
-
|
|
1457
|
+
//move center of camera (along with gizmos) towards point of interest
|
|
1458
|
+
_offset.copy( point ).sub( this._gizmos.position ).multiplyScalar( amount );
|
|
1459
|
+
this._translationMatrix.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
1394
1460
|
|
|
1395
|
-
|
|
1461
|
+
_gizmoMatrixStateTemp.copy( this._gizmoMatrixState );
|
|
1462
|
+
this._gizmoMatrixState.premultiply( this._translationMatrix );
|
|
1463
|
+
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1396
1464
|
|
|
1397
|
-
|
|
1465
|
+
_cameraMatrixStateTemp.copy( this._cameraMatrixState );
|
|
1466
|
+
this._cameraMatrixState.premultiply( this._translationMatrix );
|
|
1467
|
+
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
1398
1468
|
|
|
1399
|
-
|
|
1469
|
+
//apply zoom
|
|
1470
|
+
if ( this.enableZoom ) {
|
|
1400
1471
|
|
|
1401
|
-
|
|
1472
|
+
this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
|
|
1402
1473
|
|
|
1403
|
-
|
|
1404
|
-
.applyQuaternion( this.camera.quaternion )
|
|
1405
|
-
.multiplyScalar( 1 / this.camera.zoom )
|
|
1406
|
-
.add( this._gizmos.position );
|
|
1474
|
+
}
|
|
1407
1475
|
|
|
1408
|
-
|
|
1476
|
+
this._gizmoMatrixState.copy( _gizmoMatrixStateTemp );
|
|
1477
|
+
this._cameraMatrixState.copy( _cameraMatrixStateTemp );
|
|
1409
1478
|
|
|
1410
|
-
|
|
1411
|
-
.applyQuaternion( this.camera.quaternion )
|
|
1412
|
-
.add( this._gizmos.position );
|
|
1479
|
+
}
|
|
1413
1480
|
|
|
1414
|
-
|
|
1481
|
+
/**
|
|
1482
|
+
* Draw a grid and add it to the scene
|
|
1483
|
+
*/
|
|
1484
|
+
drawGrid() {
|
|
1415
1485
|
|
|
1416
|
-
|
|
1486
|
+
if ( this.scene != null ) {
|
|
1417
1487
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1488
|
+
const color = 0x888888;
|
|
1489
|
+
const multiplier = 3;
|
|
1490
|
+
let size, divisions, maxLength, tick;
|
|
1420
1491
|
|
|
1421
|
-
|
|
1492
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
1422
1493
|
|
|
1423
|
-
|
|
1494
|
+
const width = this.camera.right - this.camera.left;
|
|
1495
|
+
const height = this.camera.bottom - this.camera.top;
|
|
1424
1496
|
|
|
1425
|
-
|
|
1497
|
+
maxLength = Math.max( width, height );
|
|
1498
|
+
tick = maxLength / 20;
|
|
1426
1499
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1500
|
+
size = maxLength / this.camera.zoom * multiplier;
|
|
1501
|
+
divisions = size / tick * this.camera.zoom;
|
|
1429
1502
|
|
|
1430
|
-
|
|
1503
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
1431
1504
|
|
|
1432
|
-
|
|
1505
|
+
const distance = this.camera.position.distanceTo( this._gizmos.position );
|
|
1506
|
+
const halfFovV = MathUtils.DEG2RAD * this.camera.fov * 0.5;
|
|
1507
|
+
const halfFovH = Math.atan( ( this.camera.aspect ) * Math.tan( halfFovV ) );
|
|
1433
1508
|
|
|
1434
|
-
|
|
1509
|
+
maxLength = Math.tan( Math.max( halfFovV, halfFovH ) ) * distance * 2;
|
|
1510
|
+
tick = maxLength / 20;
|
|
1435
1511
|
|
|
1436
|
-
|
|
1512
|
+
size = maxLength * multiplier;
|
|
1513
|
+
divisions = size / tick;
|
|
1437
1514
|
|
|
1438
|
-
|
|
1515
|
+
}
|
|
1439
1516
|
|
|
1440
|
-
|
|
1441
|
-
let clientX = 0;
|
|
1442
|
-
let clientY = 0;
|
|
1443
|
-
const nFingers = this._touchCurrent.length;
|
|
1517
|
+
if ( this._grid == null ) {
|
|
1444
1518
|
|
|
1445
|
-
|
|
1519
|
+
this._grid = new GridHelper( size, divisions, color, color );
|
|
1520
|
+
this._grid.position.copy( this._gizmos.position );
|
|
1521
|
+
this._gridPosition.copy( this._grid.position );
|
|
1522
|
+
this._grid.quaternion.copy( this.camera.quaternion );
|
|
1523
|
+
this._grid.rotateX( Math.PI * 0.5 );
|
|
1446
1524
|
|
|
1447
|
-
|
|
1448
|
-
clientY += this._touchCurrent[ i ].clientY;
|
|
1525
|
+
this.scene.add( this._grid );
|
|
1449
1526
|
|
|
1450
1527
|
}
|
|
1451
1528
|
|
|
1452
|
-
this.setCenter( clientX / nFingers, clientY / nFingers );
|
|
1453
|
-
|
|
1454
|
-
this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
1455
|
-
this._currentCursorPosition.copy( this._startCursorPosition );
|
|
1456
|
-
|
|
1457
1529
|
}
|
|
1458
1530
|
|
|
1459
|
-
}
|
|
1531
|
+
}
|
|
1460
1532
|
|
|
1461
|
-
|
|
1533
|
+
/**
|
|
1534
|
+
* Remove all listeners, stop animations and clean scene
|
|
1535
|
+
*/
|
|
1536
|
+
dispose() {
|
|
1462
1537
|
|
|
1463
|
-
if ( this.
|
|
1538
|
+
if ( this._animationId != - 1 ) {
|
|
1464
1539
|
|
|
1465
|
-
|
|
1466
|
-
// |\
|
|
1467
|
-
// | \
|
|
1468
|
-
// | \
|
|
1469
|
-
// x | \
|
|
1470
|
-
// | \
|
|
1471
|
-
// | \
|
|
1472
|
-
// | _ _ _\
|
|
1473
|
-
// y
|
|
1540
|
+
window.cancelAnimationFrame( this._animationId );
|
|
1474
1541
|
|
|
1475
|
-
|
|
1476
|
-
let clientX = 0;
|
|
1477
|
-
let clientY = 0;
|
|
1478
|
-
const nFingers = this._touchCurrent.length;
|
|
1542
|
+
}
|
|
1479
1543
|
|
|
1480
|
-
|
|
1544
|
+
this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
|
|
1545
|
+
this.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );
|
|
1546
|
+
this.domElement.removeEventListener( 'wheel', this._onWheel );
|
|
1547
|
+
this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
|
|
1481
1548
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1549
|
+
window.removeEventListener( 'pointermove', this._onPointerMove );
|
|
1550
|
+
window.removeEventListener( 'pointerup', this._onPointerUp );
|
|
1484
1551
|
|
|
1485
|
-
|
|
1552
|
+
window.removeEventListener( 'resize', this._onWindowResize );
|
|
1486
1553
|
|
|
1487
|
-
|
|
1554
|
+
if ( this.scene !== null ) this.scene.remove( this._gizmos );
|
|
1555
|
+
this.disposeGrid();
|
|
1488
1556
|
|
|
1489
|
-
|
|
1490
|
-
this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
|
|
1557
|
+
}
|
|
1491
1558
|
|
|
1492
|
-
|
|
1559
|
+
/**
|
|
1560
|
+
* remove the grid from the scene
|
|
1561
|
+
*/
|
|
1562
|
+
disposeGrid() {
|
|
1493
1563
|
|
|
1494
|
-
|
|
1564
|
+
if ( this._grid != null && this.scene != null ) {
|
|
1495
1565
|
|
|
1496
|
-
|
|
1566
|
+
this.scene.remove( this._grid );
|
|
1567
|
+
this._grid = null;
|
|
1497
1568
|
|
|
1498
|
-
|
|
1569
|
+
}
|
|
1499
1570
|
|
|
1500
|
-
|
|
1571
|
+
}
|
|
1501
1572
|
|
|
1502
|
-
|
|
1573
|
+
/**
|
|
1574
|
+
* Compute the easing out cubic function for ease out effect in animation
|
|
1575
|
+
* @param {Number} t The absolute progress of the animation in the bound of 0 (beginning of the) and 1 (ending of animation)
|
|
1576
|
+
* @returns {Number} Result of easing out cubic at time t
|
|
1577
|
+
*/
|
|
1578
|
+
easeOutCubic( t ) {
|
|
1503
1579
|
|
|
1504
|
-
|
|
1580
|
+
return 1 - Math.pow( 1 - t, 3 );
|
|
1505
1581
|
|
|
1506
|
-
|
|
1507
|
-
const x = this._v3_1.distanceTo( this._gizmos.position );
|
|
1508
|
-
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
1582
|
+
}
|
|
1509
1583
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1584
|
+
/**
|
|
1585
|
+
* Make rotation gizmos more or less visible
|
|
1586
|
+
* @param {Boolean} isActive If true, make gizmos more visible
|
|
1587
|
+
*/
|
|
1588
|
+
activateGizmos( isActive ) {
|
|
1512
1589
|
|
|
1513
|
-
|
|
1590
|
+
const gizmoX = this._gizmos.children[ 0 ];
|
|
1591
|
+
const gizmoY = this._gizmos.children[ 1 ];
|
|
1592
|
+
const gizmoZ = this._gizmos.children[ 2 ];
|
|
1514
1593
|
|
|
1515
|
-
|
|
1516
|
-
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
1594
|
+
if ( isActive ) {
|
|
1517
1595
|
|
|
1518
|
-
|
|
1519
|
-
|
|
1596
|
+
gizmoX.material.setValues( { opacity: 1 } );
|
|
1597
|
+
gizmoY.material.setValues( { opacity: 1 } );
|
|
1598
|
+
gizmoZ.material.setValues( { opacity: 1 } );
|
|
1520
1599
|
|
|
1521
|
-
|
|
1522
|
-
size = x / newDistance;
|
|
1523
|
-
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
1600
|
+
} else {
|
|
1524
1601
|
|
|
1525
|
-
|
|
1526
|
-
|
|
1602
|
+
gizmoX.material.setValues( { opacity: 0.6 } );
|
|
1603
|
+
gizmoY.material.setValues( { opacity: 0.6 } );
|
|
1604
|
+
gizmoZ.material.setValues( { opacity: 0.6 } );
|
|
1527
1605
|
|
|
1528
|
-
|
|
1529
|
-
_offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
|
|
1530
|
-
this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
1606
|
+
}
|
|
1531
1607
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
};
|
|
1608
|
+
}
|
|
1537
1609
|
|
|
1538
|
-
|
|
1610
|
+
/**
|
|
1611
|
+
* Calculate the cursor position in NDC
|
|
1612
|
+
* @param {number} x Cursor horizontal coordinate within the canvas
|
|
1613
|
+
* @param {number} y Cursor vertical coordinate within the canvas
|
|
1614
|
+
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
1615
|
+
* @returns {Vector2} Cursor normalized position inside the canvas
|
|
1616
|
+
*/
|
|
1617
|
+
getCursorNDC( cursorX, cursorY, canvas ) {
|
|
1539
1618
|
|
|
1540
|
-
|
|
1541
|
-
this.
|
|
1542
|
-
|
|
1619
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
1620
|
+
this._v2_1.setX( ( ( cursorX - canvasRect.left ) / canvasRect.width ) * 2 - 1 );
|
|
1621
|
+
this._v2_1.setY( ( ( canvasRect.bottom - cursorY ) / canvasRect.height ) * 2 - 1 );
|
|
1622
|
+
return this._v2_1.clone();
|
|
1543
1623
|
|
|
1544
|
-
}
|
|
1624
|
+
}
|
|
1545
1625
|
|
|
1546
1626
|
/**
|
|
1547
|
-
*
|
|
1548
|
-
* @param {Number}
|
|
1549
|
-
* @param {Number}
|
|
1627
|
+
* Calculate the cursor position inside the canvas x/y coordinates with the origin being in the center of the canvas
|
|
1628
|
+
* @param {Number} x Cursor horizontal coordinate within the canvas
|
|
1629
|
+
* @param {Number} y Cursor vertical coordinate within the canvas
|
|
1630
|
+
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
1631
|
+
* @returns {Vector2} Cursor position inside the canvas
|
|
1550
1632
|
*/
|
|
1551
|
-
|
|
1633
|
+
getCursorPosition( cursorX, cursorY, canvas ) {
|
|
1552
1634
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1635
|
+
this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
|
|
1636
|
+
this._v2_1.x *= ( this.camera.right - this.camera.left ) * 0.5;
|
|
1637
|
+
this._v2_1.y *= ( this.camera.top - this.camera.bottom ) * 0.5;
|
|
1638
|
+
return this._v2_1.clone();
|
|
1555
1639
|
|
|
1556
|
-
}
|
|
1640
|
+
}
|
|
1557
1641
|
|
|
1558
1642
|
/**
|
|
1559
|
-
* Set
|
|
1643
|
+
* Set the camera to be controlled
|
|
1644
|
+
* @param {Camera} camera The virtual camera to be controlled
|
|
1560
1645
|
*/
|
|
1561
|
-
|
|
1646
|
+
setCamera( camera ) {
|
|
1562
1647
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1648
|
+
camera.lookAt( this.target );
|
|
1649
|
+
camera.updateMatrix();
|
|
1565
1650
|
|
|
1566
|
-
|
|
1651
|
+
//setting state
|
|
1652
|
+
if ( camera.type == 'PerspectiveCamera' ) {
|
|
1567
1653
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1654
|
+
this._fov0 = camera.fov;
|
|
1655
|
+
this._fovState = camera.fov;
|
|
1570
1656
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
this._cameraMatrixState0.copy( camera.matrix );
|
|
1660
|
+
this._cameraMatrixState.copy( this._cameraMatrixState0 );
|
|
1661
|
+
this._cameraProjectionState.copy( camera.projectionMatrix );
|
|
1662
|
+
this._zoom0 = camera.zoom;
|
|
1663
|
+
this._zoomState = this._zoom0;
|
|
1664
|
+
|
|
1665
|
+
this._initialNear = camera.near;
|
|
1666
|
+
this._nearPos0 = camera.position.distanceTo( this.target ) - camera.near;
|
|
1667
|
+
this._nearPos = this._initialNear;
|
|
1668
|
+
|
|
1669
|
+
this._initialFar = camera.far;
|
|
1670
|
+
this._farPos0 = camera.position.distanceTo( this.target ) - camera.far;
|
|
1671
|
+
this._farPos = this._initialFar;
|
|
1672
|
+
|
|
1673
|
+
this._up0.copy( camera.up );
|
|
1674
|
+
this._upState.copy( camera.up );
|
|
1573
1675
|
|
|
1676
|
+
this.camera = camera;
|
|
1677
|
+
this.camera.updateProjectionMatrix();
|
|
1678
|
+
|
|
1679
|
+
//making gizmos
|
|
1680
|
+
this._tbRadius = this.calculateTbRadius( camera );
|
|
1681
|
+
this.makeGizmos( this.target, this._tbRadius );
|
|
1574
1682
|
|
|
1575
|
-
}
|
|
1683
|
+
}
|
|
1576
1684
|
|
|
1577
1685
|
/**
|
|
1578
|
-
*
|
|
1579
|
-
* @param {
|
|
1580
|
-
* @param {Object} action2
|
|
1581
|
-
* @returns {Boolean} True if action1 and action 2 are the same mouse action, false otherwise
|
|
1686
|
+
* Set gizmos visibility
|
|
1687
|
+
* @param {Boolean} value Value of gizmos visibility
|
|
1582
1688
|
*/
|
|
1583
|
-
|
|
1689
|
+
setGizmosVisible( value ) {
|
|
1584
1690
|
|
|
1585
|
-
|
|
1691
|
+
this._gizmos.visible = value;
|
|
1692
|
+
this.dispatchEvent( _changeEvent );
|
|
1586
1693
|
|
|
1587
|
-
|
|
1694
|
+
}
|
|
1588
1695
|
|
|
1589
|
-
|
|
1696
|
+
/**
|
|
1697
|
+
* Set gizmos radius factor and redraws gizmos
|
|
1698
|
+
* @param {Float} value Value of radius factor
|
|
1699
|
+
*/
|
|
1700
|
+
setTbRadius( value ) {
|
|
1590
1701
|
|
|
1591
|
-
|
|
1702
|
+
this.radiusFactor = value;
|
|
1703
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
1592
1704
|
|
|
1593
|
-
|
|
1705
|
+
const curve = new EllipseCurve( 0, 0, this._tbRadius, this._tbRadius );
|
|
1706
|
+
const points = curve.getPoints( this._curvePts );
|
|
1707
|
+
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
1594
1708
|
|
|
1595
|
-
}
|
|
1596
1709
|
|
|
1597
|
-
|
|
1710
|
+
for ( const gizmo in this._gizmos.children ) {
|
|
1598
1711
|
|
|
1599
|
-
|
|
1712
|
+
this._gizmos.children[ gizmo ].geometry = curveGeometry;
|
|
1600
1713
|
|
|
1601
1714
|
}
|
|
1602
1715
|
|
|
1603
|
-
|
|
1716
|
+
this.dispatchEvent( _changeEvent );
|
|
1717
|
+
|
|
1718
|
+
}
|
|
1604
1719
|
|
|
1605
1720
|
/**
|
|
1606
|
-
*
|
|
1607
|
-
* @param {
|
|
1608
|
-
* @param {
|
|
1609
|
-
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1610
|
-
* @returns {Boolean} True if the mouse action has been successfully added, false otherwise
|
|
1721
|
+
* Creates the rotation gizmos matching trackball center and radius
|
|
1722
|
+
* @param {Vector3} tbCenter The trackball center
|
|
1723
|
+
* @param {number} tbRadius The trackball radius
|
|
1611
1724
|
*/
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
const operationInput = [ 'PAN', 'ROTATE', 'ZOOM', 'FOV' ];
|
|
1615
|
-
const mouseInput = [ 0, 1, 2, 'WHEEL' ];
|
|
1616
|
-
const keyInput = [ 'CTRL', 'SHIFT', null ];
|
|
1617
|
-
let state;
|
|
1725
|
+
makeGizmos( tbCenter, tbRadius ) {
|
|
1618
1726
|
|
|
1619
|
-
|
|
1727
|
+
const curve = new EllipseCurve( 0, 0, tbRadius, tbRadius );
|
|
1728
|
+
const points = curve.getPoints( this._curvePts );
|
|
1620
1729
|
|
|
1621
|
-
|
|
1622
|
-
|
|
1730
|
+
//geometry
|
|
1731
|
+
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
1623
1732
|
|
|
1624
|
-
|
|
1733
|
+
//material
|
|
1734
|
+
const curveMaterialX = new LineBasicMaterial( { color: 0xff8080, fog: false, transparent: true, opacity: 0.6 } );
|
|
1735
|
+
const curveMaterialY = new LineBasicMaterial( { color: 0x80ff80, fog: false, transparent: true, opacity: 0.6 } );
|
|
1736
|
+
const curveMaterialZ = new LineBasicMaterial( { color: 0x8080ff, fog: false, transparent: true, opacity: 0.6 } );
|
|
1625
1737
|
|
|
1626
|
-
|
|
1738
|
+
//line
|
|
1739
|
+
const gizmoX = new Line( curveGeometry, curveMaterialX );
|
|
1740
|
+
const gizmoY = new Line( curveGeometry, curveMaterialY );
|
|
1741
|
+
const gizmoZ = new Line( curveGeometry, curveMaterialZ );
|
|
1627
1742
|
|
|
1628
|
-
|
|
1743
|
+
const rotation = Math.PI * 0.5;
|
|
1744
|
+
gizmoX.rotation.x = rotation;
|
|
1745
|
+
gizmoY.rotation.y = rotation;
|
|
1629
1746
|
|
|
1630
|
-
//cannot associate 2D operation to 1D input
|
|
1631
|
-
return false;
|
|
1632
1747
|
|
|
1633
|
-
|
|
1748
|
+
//setting state
|
|
1749
|
+
this._gizmoMatrixState0.identity().setPosition( tbCenter );
|
|
1750
|
+
this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
|
|
1634
1751
|
|
|
1635
|
-
|
|
1752
|
+
if ( this.camera.zoom !== 1 ) {
|
|
1636
1753
|
|
|
1637
|
-
|
|
1754
|
+
//adapt gizmos size to camera zoom
|
|
1755
|
+
const size = 1 / this.camera.zoom;
|
|
1756
|
+
this._scaleMatrix.makeScale( size, size, size );
|
|
1757
|
+
this._translationMatrix.makeTranslation( - tbCenter.x, - tbCenter.y, - tbCenter.z );
|
|
1638
1758
|
|
|
1639
|
-
|
|
1759
|
+
this._gizmoMatrixState.premultiply( this._translationMatrix ).premultiply( this._scaleMatrix );
|
|
1760
|
+
this._translationMatrix.makeTranslation( tbCenter.x, tbCenter.y, tbCenter.z );
|
|
1761
|
+
this._gizmoMatrixState.premultiply( this._translationMatrix );
|
|
1640
1762
|
|
|
1641
|
-
|
|
1642
|
-
break;
|
|
1763
|
+
}
|
|
1643
1764
|
|
|
1644
|
-
|
|
1765
|
+
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1645
1766
|
|
|
1646
|
-
|
|
1647
|
-
break;
|
|
1767
|
+
//
|
|
1648
1768
|
|
|
1649
|
-
|
|
1769
|
+
this._gizmos.traverse( function ( object ) {
|
|
1650
1770
|
|
|
1651
|
-
|
|
1652
|
-
break;
|
|
1771
|
+
if ( object.isLine ) {
|
|
1653
1772
|
|
|
1654
|
-
|
|
1773
|
+
object.geometry.dispose();
|
|
1774
|
+
object.material.dispose();
|
|
1655
1775
|
|
|
1656
|
-
|
|
1657
|
-
break;
|
|
1776
|
+
}
|
|
1658
1777
|
|
|
1659
|
-
}
|
|
1778
|
+
} );
|
|
1660
1779
|
|
|
1661
|
-
|
|
1780
|
+
this._gizmos.clear();
|
|
1662
1781
|
|
|
1663
|
-
|
|
1664
|
-
mouse: mouse,
|
|
1665
|
-
key: key,
|
|
1666
|
-
state: state
|
|
1782
|
+
//
|
|
1667
1783
|
|
|
1668
|
-
|
|
1784
|
+
this._gizmos.add( gizmoX );
|
|
1785
|
+
this._gizmos.add( gizmoY );
|
|
1786
|
+
this._gizmos.add( gizmoZ );
|
|
1669
1787
|
|
|
1670
|
-
|
|
1788
|
+
}
|
|
1671
1789
|
|
|
1672
|
-
|
|
1790
|
+
/**
|
|
1791
|
+
* Perform animation for focus operation
|
|
1792
|
+
* @param {Number} time Instant in which this function is called as performance.now()
|
|
1793
|
+
* @param {Vector3} point Point of interest for focus operation
|
|
1794
|
+
* @param {Matrix4} cameraMatrix Camera matrix
|
|
1795
|
+
* @param {Matrix4} gizmoMatrix Gizmos matrix
|
|
1796
|
+
*/
|
|
1797
|
+
onFocusAnim( time, point, cameraMatrix, gizmoMatrix ) {
|
|
1673
1798
|
|
|
1674
|
-
|
|
1675
|
-
return true;
|
|
1799
|
+
if ( this._timeStart == - 1 ) {
|
|
1676
1800
|
|
|
1677
|
-
|
|
1801
|
+
//animation start
|
|
1802
|
+
this._timeStart = time;
|
|
1678
1803
|
|
|
1679
1804
|
}
|
|
1680
1805
|
|
|
1681
|
-
this.
|
|
1682
|
-
return true;
|
|
1806
|
+
if ( this._state == STATE.ANIMATION_FOCUS ) {
|
|
1683
1807
|
|
|
1684
|
-
|
|
1808
|
+
const deltaTime = time - this._timeStart;
|
|
1809
|
+
const animTime = deltaTime / this.focusAnimationTime;
|
|
1685
1810
|
|
|
1686
|
-
|
|
1687
|
-
* Remove a mouse action by specifying its mouse/key combination
|
|
1688
|
-
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
|
|
1689
|
-
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1690
|
-
* @returns {Boolean} True if the operation has been succesfully removed, false otherwise
|
|
1691
|
-
*/
|
|
1692
|
-
unsetMouseAction = ( mouse, key = null ) => {
|
|
1811
|
+
this._gizmoMatrixState.copy( gizmoMatrix );
|
|
1693
1812
|
|
|
1694
|
-
|
|
1813
|
+
if ( animTime >= 1 ) {
|
|
1695
1814
|
|
|
1696
|
-
|
|
1815
|
+
//animation end
|
|
1697
1816
|
|
|
1698
|
-
this.
|
|
1699
|
-
return true;
|
|
1817
|
+
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1700
1818
|
|
|
1701
|
-
|
|
1819
|
+
this.focus( point, this.scaleFactor );
|
|
1702
1820
|
|
|
1703
|
-
|
|
1821
|
+
this._timeStart = - 1;
|
|
1822
|
+
this.updateTbState( STATE.IDLE, false );
|
|
1823
|
+
this.activateGizmos( false );
|
|
1704
1824
|
|
|
1705
|
-
|
|
1825
|
+
this.dispatchEvent( _changeEvent );
|
|
1706
1826
|
|
|
1707
|
-
|
|
1827
|
+
} else {
|
|
1708
1828
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
|
|
1712
|
-
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
|
|
1713
|
-
* @returns The operation if it has been found, null otherwise
|
|
1714
|
-
*/
|
|
1715
|
-
getOpFromAction = ( mouse, key ) => {
|
|
1829
|
+
const amount = this.easeOutCubic( animTime );
|
|
1830
|
+
const size = ( ( 1 - amount ) + ( this.scaleFactor * amount ) );
|
|
1716
1831
|
|
|
1717
|
-
|
|
1832
|
+
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1833
|
+
this.focus( point, size, amount );
|
|
1718
1834
|
|
|
1719
|
-
|
|
1835
|
+
this.dispatchEvent( _changeEvent );
|
|
1836
|
+
const self = this;
|
|
1837
|
+
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
1720
1838
|
|
|
1721
|
-
|
|
1722
|
-
if ( action.mouse == mouse && action.key == key ) {
|
|
1839
|
+
self.onFocusAnim( t, point, cameraMatrix, gizmoMatrix.clone() );
|
|
1723
1840
|
|
|
1724
|
-
|
|
1841
|
+
} );
|
|
1725
1842
|
|
|
1726
1843
|
}
|
|
1727
1844
|
|
|
1728
|
-
}
|
|
1845
|
+
} else {
|
|
1729
1846
|
|
|
1730
|
-
|
|
1847
|
+
//interrupt animation
|
|
1731
1848
|
|
|
1732
|
-
|
|
1849
|
+
this._animationId = - 1;
|
|
1850
|
+
this._timeStart = - 1;
|
|
1733
1851
|
|
|
1734
|
-
|
|
1735
|
-
if ( action.mouse == mouse && action.key == null ) {
|
|
1852
|
+
}
|
|
1736
1853
|
|
|
1737
|
-
|
|
1854
|
+
}
|
|
1738
1855
|
|
|
1739
|
-
|
|
1856
|
+
/**
|
|
1857
|
+
* Perform animation for rotation operation
|
|
1858
|
+
* @param {Number} time Instant in which this function is called as performance.now()
|
|
1859
|
+
* @param {Vector3} rotationAxis Rotation axis
|
|
1860
|
+
* @param {number} w0 Initial angular velocity
|
|
1861
|
+
*/
|
|
1862
|
+
onRotationAnim( time, rotationAxis, w0 ) {
|
|
1740
1863
|
|
|
1741
|
-
|
|
1864
|
+
if ( this._timeStart == - 1 ) {
|
|
1865
|
+
|
|
1866
|
+
//animation start
|
|
1867
|
+
this._anglePrev = 0;
|
|
1868
|
+
this._angleCurrent = 0;
|
|
1869
|
+
this._timeStart = time;
|
|
1742
1870
|
|
|
1743
1871
|
}
|
|
1744
1872
|
|
|
1745
|
-
|
|
1873
|
+
if ( this._state == STATE.ANIMATION_ROTATE ) {
|
|
1746
1874
|
|
|
1747
|
-
|
|
1875
|
+
//w = w0 + alpha * t
|
|
1876
|
+
const deltaTime = ( time - this._timeStart ) / 1000;
|
|
1877
|
+
const w = w0 + ( ( - this.dampingFactor ) * deltaTime );
|
|
1748
1878
|
|
|
1749
|
-
|
|
1750
|
-
* Get the operation associated to mouse and key combination and returns the corresponding FSA state
|
|
1751
|
-
* @param {Number} mouse Mouse button
|
|
1752
|
-
* @param {String} key Keyboard modifier
|
|
1753
|
-
* @returns The FSA state obtained from the operation associated to mouse/keyboard combination
|
|
1754
|
-
*/
|
|
1755
|
-
getOpStateFromAction = ( mouse, key ) => {
|
|
1879
|
+
if ( w > 0 ) {
|
|
1756
1880
|
|
|
1757
|
-
|
|
1881
|
+
//tetha = 0.5 * alpha * t^2 + w0 * t + tetha0
|
|
1882
|
+
this._angleCurrent = 0.5 * ( - this.dampingFactor ) * Math.pow( deltaTime, 2 ) + w0 * deltaTime + 0;
|
|
1883
|
+
this.applyTransformMatrix( this.rotate( rotationAxis, this._angleCurrent ) );
|
|
1884
|
+
this.dispatchEvent( _changeEvent );
|
|
1885
|
+
const self = this;
|
|
1886
|
+
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
1758
1887
|
|
|
1759
|
-
|
|
1888
|
+
self.onRotationAnim( t, rotationAxis, w0 );
|
|
1760
1889
|
|
|
1761
|
-
|
|
1762
|
-
if ( action.mouse == mouse && action.key == key ) {
|
|
1890
|
+
} );
|
|
1763
1891
|
|
|
1764
|
-
|
|
1892
|
+
} else {
|
|
1765
1893
|
|
|
1766
|
-
|
|
1894
|
+
this._animationId = - 1;
|
|
1895
|
+
this._timeStart = - 1;
|
|
1767
1896
|
|
|
1768
|
-
|
|
1897
|
+
this.updateTbState( STATE.IDLE, false );
|
|
1898
|
+
this.activateGizmos( false );
|
|
1769
1899
|
|
|
1770
|
-
|
|
1900
|
+
this.dispatchEvent( _changeEvent );
|
|
1771
1901
|
|
|
1772
|
-
|
|
1902
|
+
}
|
|
1773
1903
|
|
|
1774
|
-
|
|
1775
|
-
if ( action.mouse == mouse && action.key == null ) {
|
|
1904
|
+
} else {
|
|
1776
1905
|
|
|
1777
|
-
|
|
1906
|
+
//interrupt animation
|
|
1778
1907
|
|
|
1779
|
-
|
|
1908
|
+
this._animationId = - 1;
|
|
1909
|
+
this._timeStart = - 1;
|
|
1910
|
+
|
|
1911
|
+
if ( this._state != STATE.ROTATE ) {
|
|
1912
|
+
|
|
1913
|
+
this.activateGizmos( false );
|
|
1914
|
+
this.dispatchEvent( _changeEvent );
|
|
1780
1915
|
|
|
1781
1916
|
}
|
|
1782
1917
|
|
|
1783
1918
|
}
|
|
1784
1919
|
|
|
1785
|
-
|
|
1920
|
+
}
|
|
1786
1921
|
|
|
1787
|
-
};
|
|
1788
1922
|
|
|
1789
1923
|
/**
|
|
1790
|
-
*
|
|
1791
|
-
* @param {
|
|
1792
|
-
* @param {
|
|
1793
|
-
* @
|
|
1924
|
+
* Perform pan operation moving camera between two points
|
|
1925
|
+
* @param {Vector3} p0 Initial point
|
|
1926
|
+
* @param {Vector3} p1 Ending point
|
|
1927
|
+
* @param {Boolean} adjust If movement should be adjusted considering camera distance (Perspective only)
|
|
1794
1928
|
*/
|
|
1795
|
-
|
|
1929
|
+
pan( p0, p1, adjust = false ) {
|
|
1796
1930
|
|
|
1797
|
-
|
|
1931
|
+
const movement = p0.clone().sub( p1 );
|
|
1798
1932
|
|
|
1799
|
-
|
|
1933
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
1800
1934
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
* @param {PointerEvent} event
|
|
1804
|
-
*/
|
|
1805
|
-
updateTouchEvent = ( event ) => {
|
|
1935
|
+
//adjust movement amount
|
|
1936
|
+
movement.multiplyScalar( 1 / this.camera.zoom );
|
|
1806
1937
|
|
|
1807
|
-
|
|
1938
|
+
} else if ( this.camera.isPerspectiveCamera && adjust ) {
|
|
1808
1939
|
|
|
1809
|
-
|
|
1940
|
+
//adjust movement amount
|
|
1941
|
+
this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ); //camera's initial position
|
|
1942
|
+
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ); //gizmo's initial position
|
|
1943
|
+
const distanceFactor = this._v3_1.distanceTo( this._v3_2 ) / this.camera.position.distanceTo( this._gizmos.position );
|
|
1944
|
+
movement.multiplyScalar( 1 / distanceFactor );
|
|
1810
1945
|
|
|
1811
|
-
|
|
1812
|
-
break;
|
|
1946
|
+
}
|
|
1813
1947
|
|
|
1814
|
-
|
|
1948
|
+
this._v3_1.set( movement.x, movement.y, 0 ).applyQuaternion( this.camera.quaternion );
|
|
1815
1949
|
|
|
1816
|
-
|
|
1950
|
+
this._m4_1.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z );
|
|
1817
1951
|
|
|
1818
|
-
|
|
1952
|
+
this.setTransformationMatrices( this._m4_1, this._m4_1 );
|
|
1953
|
+
return _transformation;
|
|
1954
|
+
|
|
1955
|
+
}
|
|
1819
1956
|
|
|
1820
1957
|
/**
|
|
1821
|
-
*
|
|
1822
|
-
* @param {Object} transformation Object containing matrices to apply to camera and gizmos
|
|
1958
|
+
* Reset trackball
|
|
1823
1959
|
*/
|
|
1824
|
-
|
|
1960
|
+
reset() {
|
|
1825
1961
|
|
|
1826
|
-
|
|
1962
|
+
this.camera.zoom = this._zoom0;
|
|
1827
1963
|
|
|
1828
|
-
|
|
1829
|
-
this._m4_1.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
1830
|
-
this.camera.updateMatrix();
|
|
1964
|
+
if ( this.camera.isPerspectiveCamera ) {
|
|
1831
1965
|
|
|
1832
|
-
|
|
1833
|
-
if ( this._state == STATE.ROTATE || this._state == STATE.ZROTATE || this._state == STATE.ANIMATION_ROTATE ) {
|
|
1966
|
+
this.camera.fov = this._fov0;
|
|
1834
1967
|
|
|
1835
|
-
|
|
1968
|
+
}
|
|
1836
1969
|
|
|
1837
|
-
|
|
1970
|
+
this.camera.near = this._nearPos;
|
|
1971
|
+
this.camera.far = this._farPos;
|
|
1972
|
+
this._cameraMatrixState.copy( this._cameraMatrixState0 );
|
|
1973
|
+
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
1974
|
+
this.camera.up.copy( this._up0 );
|
|
1838
1975
|
|
|
1839
|
-
|
|
1976
|
+
this.camera.updateMatrix();
|
|
1977
|
+
this.camera.updateProjectionMatrix();
|
|
1840
1978
|
|
|
1841
|
-
|
|
1979
|
+
this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
|
|
1980
|
+
this._gizmoMatrixState0.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
1981
|
+
this._gizmos.updateMatrix();
|
|
1842
1982
|
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
this._gizmos.updateMatrix();
|
|
1983
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
1984
|
+
this.makeGizmos( this._gizmos.position, this._tbRadius );
|
|
1846
1985
|
|
|
1847
|
-
|
|
1986
|
+
this.camera.lookAt( this._gizmos.position );
|
|
1848
1987
|
|
|
1849
|
-
|
|
1988
|
+
this.updateTbState( STATE.IDLE, false );
|
|
1850
1989
|
|
|
1851
|
-
|
|
1990
|
+
this.dispatchEvent( _changeEvent );
|
|
1852
1991
|
|
|
1853
|
-
|
|
1992
|
+
}
|
|
1854
1993
|
|
|
1855
|
-
|
|
1994
|
+
/**
|
|
1995
|
+
* Rotate the camera around an axis passing by trackball's center
|
|
1996
|
+
* @param {Vector3} axis Rotation axis
|
|
1997
|
+
* @param {number} angle Angle in radians
|
|
1998
|
+
* @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera
|
|
1999
|
+
*/
|
|
2000
|
+
rotate( axis, angle ) {
|
|
1856
2001
|
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
bb.getBoundingSphere( sphere );
|
|
2002
|
+
const point = this._gizmos.position; //rotation center
|
|
2003
|
+
this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
|
|
2004
|
+
this._rotationMatrix.makeRotationAxis( axis, - angle );
|
|
1861
2005
|
|
|
1862
|
-
|
|
1863
|
-
|
|
2006
|
+
//rotate camera
|
|
2007
|
+
this._m4_1.makeTranslation( point.x, point.y, point.z );
|
|
2008
|
+
this._m4_1.multiply( this._rotationMatrix );
|
|
2009
|
+
this._m4_1.multiply( this._translationMatrix );
|
|
1864
2010
|
|
|
1865
|
-
|
|
1866
|
-
this.camera.near = cameraDistance - minNearPos;
|
|
2011
|
+
this.setTransformationMatrices( this._m4_1 );
|
|
1867
2012
|
|
|
2013
|
+
return _transformation;
|
|
1868
2014
|
|
|
1869
|
-
|
|
1870
|
-
const regularFarPosition = cameraDistance - this._initialFar;
|
|
2015
|
+
}
|
|
1871
2016
|
|
|
1872
|
-
|
|
1873
|
-
this.camera.far = cameraDistance - minFarPos;
|
|
2017
|
+
copyState() {
|
|
1874
2018
|
|
|
1875
|
-
|
|
2019
|
+
let state;
|
|
2020
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
1876
2021
|
|
|
1877
|
-
|
|
2022
|
+
state = JSON.stringify( { arcballState: {
|
|
1878
2023
|
|
|
1879
|
-
|
|
2024
|
+
cameraFar: this.camera.far,
|
|
2025
|
+
cameraMatrix: this.camera.matrix,
|
|
2026
|
+
cameraNear: this.camera.near,
|
|
2027
|
+
cameraUp: this.camera.up,
|
|
2028
|
+
cameraZoom: this.camera.zoom,
|
|
2029
|
+
gizmoMatrix: this._gizmos.matrix
|
|
1880
2030
|
|
|
1881
|
-
|
|
2031
|
+
} } );
|
|
1882
2032
|
|
|
1883
|
-
|
|
1884
|
-
update = true;
|
|
2033
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
1885
2034
|
|
|
1886
|
-
|
|
2035
|
+
state = JSON.stringify( { arcballState: {
|
|
2036
|
+
cameraFar: this.camera.far,
|
|
2037
|
+
cameraFov: this.camera.fov,
|
|
2038
|
+
cameraMatrix: this.camera.matrix,
|
|
2039
|
+
cameraNear: this.camera.near,
|
|
2040
|
+
cameraUp: this.camera.up,
|
|
2041
|
+
cameraZoom: this.camera.zoom,
|
|
2042
|
+
gizmoMatrix: this._gizmos.matrix
|
|
1887
2043
|
|
|
1888
|
-
|
|
2044
|
+
} } );
|
|
1889
2045
|
|
|
1890
|
-
|
|
1891
|
-
update = true;
|
|
2046
|
+
}
|
|
1892
2047
|
|
|
1893
|
-
|
|
2048
|
+
navigator.clipboard.writeText( state );
|
|
1894
2049
|
|
|
1895
|
-
|
|
2050
|
+
}
|
|
1896
2051
|
|
|
1897
|
-
|
|
2052
|
+
pasteState() {
|
|
1898
2053
|
|
|
1899
|
-
|
|
2054
|
+
const self = this;
|
|
2055
|
+
navigator.clipboard.readText().then( function resolved( value ) {
|
|
1900
2056
|
|
|
1901
|
-
|
|
2057
|
+
self.setStateFromJSON( value );
|
|
1902
2058
|
|
|
1903
|
-
}
|
|
2059
|
+
} );
|
|
1904
2060
|
|
|
1905
2061
|
}
|
|
1906
2062
|
|
|
1907
2063
|
/**
|
|
1908
|
-
*
|
|
1909
|
-
* @param {Number} p0 Position at t0
|
|
1910
|
-
* @param {Number} p1 Position at t1
|
|
1911
|
-
* @param {Number} t0 Initial time in milliseconds
|
|
1912
|
-
* @param {Number} t1 Ending time in milliseconds
|
|
2064
|
+
* Save the current state of the control. This can later be recover with .reset
|
|
1913
2065
|
*/
|
|
1914
|
-
|
|
2066
|
+
saveState() {
|
|
1915
2067
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
2068
|
+
this._cameraMatrixState0.copy( this.camera.matrix );
|
|
2069
|
+
this._gizmoMatrixState0.copy( this._gizmos.matrix );
|
|
2070
|
+
this._nearPos = this.camera.near;
|
|
2071
|
+
this._farPos = this.camera.far;
|
|
2072
|
+
this._zoom0 = this.camera.zoom;
|
|
2073
|
+
this._up0.copy( this.camera.up );
|
|
1919
2074
|
|
|
1920
|
-
|
|
2075
|
+
if ( this.camera.isPerspectiveCamera ) {
|
|
1921
2076
|
|
|
1922
|
-
|
|
2077
|
+
this._fov0 = this.camera.fov;
|
|
1923
2078
|
|
|
1924
|
-
|
|
2079
|
+
}
|
|
1925
2080
|
|
|
1926
|
-
}
|
|
2081
|
+
}
|
|
1927
2082
|
|
|
1928
2083
|
/**
|
|
1929
|
-
*
|
|
1930
|
-
* @param {
|
|
1931
|
-
* @param {
|
|
1932
|
-
* @
|
|
2084
|
+
* Perform uniform scale operation around a given point
|
|
2085
|
+
* @param {Number} size Scale factor
|
|
2086
|
+
* @param {Vector3} point Point around which scale
|
|
2087
|
+
* @param {Boolean} scaleGizmos If gizmos should be scaled (Perspective only)
|
|
2088
|
+
* @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos
|
|
1933
2089
|
*/
|
|
1934
|
-
|
|
2090
|
+
scale( size, point, scaleGizmos = true ) {
|
|
1935
2091
|
|
|
1936
|
-
|
|
2092
|
+
_scalePointTemp.copy( point );
|
|
2093
|
+
let sizeInverse = 1 / size;
|
|
1937
2094
|
|
|
1938
|
-
|
|
2095
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
1939
2096
|
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
* @param {Vector3} vec2 The second vector
|
|
1944
|
-
* @returns {Vector3} The normalized rotation axis
|
|
1945
|
-
*/
|
|
1946
|
-
calculateRotationAxis = ( vec1, vec2 ) => {
|
|
2097
|
+
//camera zoom
|
|
2098
|
+
this.camera.zoom = this._zoomState;
|
|
2099
|
+
this.camera.zoom *= size;
|
|
1947
2100
|
|
|
1948
|
-
|
|
1949
|
-
|
|
2101
|
+
//check min and max zoom
|
|
2102
|
+
if ( this.camera.zoom > this.maxZoom ) {
|
|
1950
2103
|
|
|
1951
|
-
|
|
1952
|
-
|
|
2104
|
+
this.camera.zoom = this.maxZoom;
|
|
2105
|
+
sizeInverse = this._zoomState / this.maxZoom;
|
|
1953
2106
|
|
|
1954
|
-
|
|
2107
|
+
} else if ( this.camera.zoom < this.minZoom ) {
|
|
1955
2108
|
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
* @param {Camera} camera
|
|
1959
|
-
* @returns {Number} The trackball radius
|
|
1960
|
-
*/
|
|
1961
|
-
calculateTbRadius = ( camera ) => {
|
|
2109
|
+
this.camera.zoom = this.minZoom;
|
|
2110
|
+
sizeInverse = this._zoomState / this.minZoom;
|
|
1962
2111
|
|
|
1963
|
-
|
|
2112
|
+
}
|
|
1964
2113
|
|
|
1965
|
-
|
|
2114
|
+
this.camera.updateProjectionMatrix();
|
|
1966
2115
|
|
|
1967
|
-
|
|
1968
|
-
const halfFovH = Math.atan( ( camera.aspect ) * Math.tan( halfFovV ) ); //horizontal fov/2 in radians
|
|
1969
|
-
return Math.tan( Math.min( halfFovV, halfFovH ) ) * distance * this.radiusFactor;
|
|
2116
|
+
this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ); //gizmos position
|
|
1970
2117
|
|
|
1971
|
-
|
|
2118
|
+
//scale gizmos so they appear in the same spot having the same dimension
|
|
2119
|
+
this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
|
|
2120
|
+
this._translationMatrix.makeTranslation( - this._v3_1.x, - this._v3_1.y, - this._v3_1.z );
|
|
1972
2121
|
|
|
1973
|
-
|
|
2122
|
+
this._m4_2.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z ).multiply( this._scaleMatrix );
|
|
2123
|
+
this._m4_2.multiply( this._translationMatrix );
|
|
1974
2124
|
|
|
1975
|
-
}
|
|
1976
2125
|
|
|
1977
|
-
|
|
2126
|
+
//move camera and gizmos to obtain pinch effect
|
|
2127
|
+
_scalePointTemp.sub( this._v3_1 );
|
|
1978
2128
|
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
* @param {Vector3} point The point of interest
|
|
1982
|
-
* @param {Number} size Scale factor
|
|
1983
|
-
* @param {Number} amount Amount of operation to be completed (used for focus animations, default is complete full operation)
|
|
1984
|
-
*/
|
|
1985
|
-
focus = ( point, size, amount = 1 ) => {
|
|
2129
|
+
const amount = _scalePointTemp.clone().multiplyScalar( sizeInverse );
|
|
2130
|
+
_scalePointTemp.sub( amount );
|
|
1986
2131
|
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
this._translationMatrix.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
2132
|
+
this._m4_1.makeTranslation( _scalePointTemp.x, _scalePointTemp.y, _scalePointTemp.z );
|
|
2133
|
+
this._m4_2.premultiply( this._m4_1 );
|
|
1990
2134
|
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
2135
|
+
this.setTransformationMatrices( this._m4_1, this._m4_2 );
|
|
2136
|
+
return _transformation;
|
|
1994
2137
|
|
|
1995
|
-
|
|
1996
|
-
this._cameraMatrixState.premultiply( this._translationMatrix );
|
|
1997
|
-
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
2138
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
1998
2139
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2140
|
+
this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
|
|
2141
|
+
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
|
|
2001
2142
|
|
|
2002
|
-
|
|
2143
|
+
//move camera
|
|
2144
|
+
let distance = this._v3_1.distanceTo( _scalePointTemp );
|
|
2145
|
+
let amount = distance - ( distance * sizeInverse );
|
|
2003
2146
|
|
|
2004
|
-
|
|
2147
|
+
//check min and max distance
|
|
2148
|
+
const newDistance = distance - amount;
|
|
2149
|
+
if ( newDistance < this.minDistance ) {
|
|
2005
2150
|
|
|
2006
|
-
|
|
2007
|
-
|
|
2151
|
+
sizeInverse = this.minDistance / distance;
|
|
2152
|
+
amount = distance - ( distance * sizeInverse );
|
|
2008
2153
|
|
|
2009
|
-
|
|
2154
|
+
} else if ( newDistance > this.maxDistance ) {
|
|
2010
2155
|
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
*/
|
|
2014
|
-
drawGrid = () => {
|
|
2156
|
+
sizeInverse = this.maxDistance / distance;
|
|
2157
|
+
amount = distance - ( distance * sizeInverse );
|
|
2015
2158
|
|
|
2016
|
-
|
|
2159
|
+
}
|
|
2017
2160
|
|
|
2018
|
-
|
|
2019
|
-
const multiplier = 3;
|
|
2020
|
-
let size, divisions, maxLength, tick;
|
|
2161
|
+
_offset.copy( _scalePointTemp ).sub( this._v3_1 ).normalize().multiplyScalar( amount );
|
|
2021
2162
|
|
|
2022
|
-
|
|
2163
|
+
this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
|
|
2023
2164
|
|
|
2024
|
-
const width = this.camera.right - this.camera.left;
|
|
2025
|
-
const height = this.camera.bottom - this.camera.top;
|
|
2026
2165
|
|
|
2027
|
-
|
|
2028
|
-
tick = maxLength / 20;
|
|
2166
|
+
if ( scaleGizmos ) {
|
|
2029
2167
|
|
|
2030
|
-
|
|
2031
|
-
|
|
2168
|
+
//scale gizmos so they appear in the same spot having the same dimension
|
|
2169
|
+
const pos = this._v3_2;
|
|
2032
2170
|
|
|
2033
|
-
|
|
2171
|
+
distance = pos.distanceTo( _scalePointTemp );
|
|
2172
|
+
amount = distance - ( distance * sizeInverse );
|
|
2173
|
+
_offset.copy( _scalePointTemp ).sub( this._v3_2 ).normalize().multiplyScalar( amount );
|
|
2034
2174
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
const halfFovH = Math.atan( ( this.camera.aspect ) * Math.tan( halfFovV ) );
|
|
2175
|
+
this._translationMatrix.makeTranslation( pos.x, pos.y, pos.z );
|
|
2176
|
+
this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
|
|
2038
2177
|
|
|
2039
|
-
|
|
2040
|
-
|
|
2178
|
+
this._m4_2.makeTranslation( _offset.x, _offset.y, _offset.z ).multiply( this._translationMatrix );
|
|
2179
|
+
this._m4_2.multiply( this._scaleMatrix );
|
|
2041
2180
|
|
|
2042
|
-
|
|
2043
|
-
divisions = size / tick;
|
|
2181
|
+
this._translationMatrix.makeTranslation( - pos.x, - pos.y, - pos.z );
|
|
2044
2182
|
|
|
2045
|
-
|
|
2183
|
+
this._m4_2.multiply( this._translationMatrix );
|
|
2184
|
+
this.setTransformationMatrices( this._m4_1, this._m4_2 );
|
|
2046
2185
|
|
|
2047
|
-
if ( this._grid == null ) {
|
|
2048
2186
|
|
|
2049
|
-
|
|
2050
|
-
this._grid.position.copy( this._gizmos.position );
|
|
2051
|
-
this._gridPosition.copy( this._grid.position );
|
|
2052
|
-
this._grid.quaternion.copy( this.camera.quaternion );
|
|
2053
|
-
this._grid.rotateX( Math.PI * 0.5 );
|
|
2187
|
+
} else {
|
|
2054
2188
|
|
|
2055
|
-
this.
|
|
2189
|
+
this.setTransformationMatrices( this._m4_1 );
|
|
2056
2190
|
|
|
2057
2191
|
}
|
|
2058
2192
|
|
|
2193
|
+
return _transformation;
|
|
2194
|
+
|
|
2059
2195
|
}
|
|
2060
2196
|
|
|
2061
|
-
}
|
|
2197
|
+
}
|
|
2062
2198
|
|
|
2063
2199
|
/**
|
|
2064
|
-
*
|
|
2200
|
+
* Set camera fov
|
|
2201
|
+
* @param {Number} value fov to be setted
|
|
2065
2202
|
*/
|
|
2066
|
-
|
|
2203
|
+
setFov( value ) {
|
|
2067
2204
|
|
|
2068
|
-
if ( this.
|
|
2205
|
+
if ( this.camera.isPerspectiveCamera ) {
|
|
2069
2206
|
|
|
2070
|
-
|
|
2207
|
+
this.camera.fov = MathUtils.clamp( value, this.minFov, this.maxFov );
|
|
2208
|
+
this.camera.updateProjectionMatrix();
|
|
2071
2209
|
|
|
2072
2210
|
}
|
|
2073
2211
|
|
|
2074
|
-
|
|
2075
|
-
this.domElement.removeEventListener( 'pointercancel', this.onPointerCancel );
|
|
2076
|
-
this.domElement.removeEventListener( 'wheel', this.onWheel );
|
|
2077
|
-
this.domElement.removeEventListener( 'contextmenu', this.onContextMenu );
|
|
2212
|
+
}
|
|
2078
2213
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2214
|
+
/**
|
|
2215
|
+
* Set values in transformation object
|
|
2216
|
+
* @param {Matrix4} camera Transformation to be applied to the camera
|
|
2217
|
+
* @param {Matrix4} gizmos Transformation to be applied to gizmos
|
|
2218
|
+
*/
|
|
2219
|
+
setTransformationMatrices( camera = null, gizmos = null ) {
|
|
2081
2220
|
|
|
2082
|
-
|
|
2221
|
+
if ( camera != null ) {
|
|
2083
2222
|
|
|
2084
|
-
|
|
2085
|
-
this.disposeGrid();
|
|
2223
|
+
if ( _transformation.camera != null ) {
|
|
2086
2224
|
|
|
2087
|
-
|
|
2225
|
+
_transformation.camera.copy( camera );
|
|
2088
2226
|
|
|
2089
|
-
|
|
2090
|
-
* remove the grid from the scene
|
|
2091
|
-
*/
|
|
2092
|
-
disposeGrid = () => {
|
|
2227
|
+
} else {
|
|
2093
2228
|
|
|
2094
|
-
|
|
2229
|
+
_transformation.camera = camera.clone();
|
|
2095
2230
|
|
|
2096
|
-
|
|
2097
|
-
this._grid = null;
|
|
2231
|
+
}
|
|
2098
2232
|
|
|
2099
|
-
}
|
|
2233
|
+
} else {
|
|
2100
2234
|
|
|
2101
|
-
|
|
2235
|
+
_transformation.camera = null;
|
|
2102
2236
|
|
|
2103
|
-
|
|
2104
|
-
* Compute the easing out cubic function for ease out effect in animation
|
|
2105
|
-
* @param {Number} t The absolute progress of the animation in the bound of 0 (beginning of the) and 1 (ending of animation)
|
|
2106
|
-
* @returns {Number} Result of easing out cubic at time t
|
|
2107
|
-
*/
|
|
2108
|
-
easeOutCubic = ( t ) => {
|
|
2237
|
+
}
|
|
2109
2238
|
|
|
2110
|
-
|
|
2239
|
+
if ( gizmos != null ) {
|
|
2111
2240
|
|
|
2112
|
-
|
|
2241
|
+
if ( _transformation.gizmos != null ) {
|
|
2113
2242
|
|
|
2114
|
-
|
|
2115
|
-
* Make rotation gizmos more or less visible
|
|
2116
|
-
* @param {Boolean} isActive If true, make gizmos more visible
|
|
2117
|
-
*/
|
|
2118
|
-
activateGizmos = ( isActive ) => {
|
|
2243
|
+
_transformation.gizmos.copy( gizmos );
|
|
2119
2244
|
|
|
2120
|
-
|
|
2121
|
-
const gizmoY = this._gizmos.children[ 1 ];
|
|
2122
|
-
const gizmoZ = this._gizmos.children[ 2 ];
|
|
2245
|
+
} else {
|
|
2123
2246
|
|
|
2124
|
-
|
|
2247
|
+
_transformation.gizmos = gizmos.clone();
|
|
2125
2248
|
|
|
2126
|
-
|
|
2127
|
-
gizmoY.material.setValues( { opacity: 1 } );
|
|
2128
|
-
gizmoZ.material.setValues( { opacity: 1 } );
|
|
2249
|
+
}
|
|
2129
2250
|
|
|
2130
2251
|
} else {
|
|
2131
2252
|
|
|
2132
|
-
|
|
2133
|
-
gizmoY.material.setValues( { opacity: 0.6 } );
|
|
2134
|
-
gizmoZ.material.setValues( { opacity: 0.6 } );
|
|
2253
|
+
_transformation.gizmos = null;
|
|
2135
2254
|
|
|
2136
2255
|
}
|
|
2137
2256
|
|
|
2138
|
-
}
|
|
2257
|
+
}
|
|
2139
2258
|
|
|
2140
2259
|
/**
|
|
2141
|
-
*
|
|
2142
|
-
* @param {
|
|
2143
|
-
* @param {
|
|
2144
|
-
* @
|
|
2145
|
-
* @returns {Vector2} Cursor normalized position inside the canvas
|
|
2260
|
+
* Rotate camera around its direction axis passing by a given point by a given angle
|
|
2261
|
+
* @param {Vector3} point The point where the rotation axis is passing trough
|
|
2262
|
+
* @param {Number} angle Angle in radians
|
|
2263
|
+
* @returns The computed transormation matix
|
|
2146
2264
|
*/
|
|
2147
|
-
|
|
2265
|
+
zRotate( point, angle ) {
|
|
2148
2266
|
|
|
2149
|
-
|
|
2150
|
-
this.
|
|
2151
|
-
this._v2_1.setY( ( ( canvasRect.bottom - cursorY ) / canvasRect.height ) * 2 - 1 );
|
|
2152
|
-
return this._v2_1.clone();
|
|
2267
|
+
this._rotationMatrix.makeRotationAxis( this._rotationAxis, angle );
|
|
2268
|
+
this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
|
|
2153
2269
|
|
|
2154
|
-
|
|
2270
|
+
this._m4_1.makeTranslation( point.x, point.y, point.z );
|
|
2271
|
+
this._m4_1.multiply( this._rotationMatrix );
|
|
2272
|
+
this._m4_1.multiply( this._translationMatrix );
|
|
2155
2273
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
* @param {Number} y Cursor vertical coordinate within the canvas
|
|
2160
|
-
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
2161
|
-
* @returns {Vector2} Cursor position inside the canvas
|
|
2162
|
-
*/
|
|
2163
|
-
getCursorPosition = ( cursorX, cursorY, canvas ) => {
|
|
2274
|
+
this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ).sub( point ); //vector from rotation center to gizmos position
|
|
2275
|
+
this._v3_2.copy( this._v3_1 ).applyAxisAngle( this._rotationAxis, angle ); //apply rotation
|
|
2276
|
+
this._v3_2.sub( this._v3_1 );
|
|
2164
2277
|
|
|
2165
|
-
this.
|
|
2166
|
-
this._v2_1.x *= ( this.camera.right - this.camera.left ) * 0.5;
|
|
2167
|
-
this._v2_1.y *= ( this.camera.top - this.camera.bottom ) * 0.5;
|
|
2168
|
-
return this._v2_1.clone();
|
|
2278
|
+
this._m4_2.makeTranslation( this._v3_2.x, this._v3_2.y, this._v3_2.z );
|
|
2169
2279
|
|
|
2170
|
-
|
|
2280
|
+
this.setTransformationMatrices( this._m4_1, this._m4_2 );
|
|
2281
|
+
return _transformation;
|
|
2171
2282
|
|
|
2172
|
-
|
|
2173
|
-
* Set the camera to be controlled
|
|
2174
|
-
* @param {Camera} camera The virtual camera to be controlled
|
|
2175
|
-
*/
|
|
2176
|
-
setCamera = ( camera ) => {
|
|
2283
|
+
}
|
|
2177
2284
|
|
|
2178
|
-
camera.lookAt( this.target );
|
|
2179
|
-
camera.updateMatrix();
|
|
2180
2285
|
|
|
2181
|
-
|
|
2182
|
-
if ( camera.type == 'PerspectiveCamera' ) {
|
|
2286
|
+
getRaycaster() {
|
|
2183
2287
|
|
|
2184
|
-
|
|
2185
|
-
this._fovState = camera.fov;
|
|
2288
|
+
return _raycaster;
|
|
2186
2289
|
|
|
2187
|
-
|
|
2290
|
+
}
|
|
2188
2291
|
|
|
2189
|
-
this._cameraMatrixState0.copy( camera.matrix );
|
|
2190
|
-
this._cameraMatrixState.copy( this._cameraMatrixState0 );
|
|
2191
|
-
this._cameraProjectionState.copy( camera.projectionMatrix );
|
|
2192
|
-
this._zoom0 = camera.zoom;
|
|
2193
|
-
this._zoomState = this._zoom0;
|
|
2194
2292
|
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2293
|
+
/**
|
|
2294
|
+
* Unproject the cursor on the 3D object surface
|
|
2295
|
+
* @param {Vector2} cursor Cursor coordinates in NDC
|
|
2296
|
+
* @param {Camera} camera Virtual camera
|
|
2297
|
+
* @returns {Vector3} The point of intersection with the model, if exist, null otherwise
|
|
2298
|
+
*/
|
|
2299
|
+
unprojectOnObj( cursor, camera ) {
|
|
2198
2300
|
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2301
|
+
const raycaster = this.getRaycaster();
|
|
2302
|
+
raycaster.near = camera.near;
|
|
2303
|
+
raycaster.far = camera.far;
|
|
2304
|
+
raycaster.setFromCamera( cursor, camera );
|
|
2202
2305
|
|
|
2203
|
-
|
|
2204
|
-
this._upState.copy( camera.up );
|
|
2306
|
+
const intersect = raycaster.intersectObjects( this.scene.children, true );
|
|
2205
2307
|
|
|
2206
|
-
|
|
2207
|
-
this.camera.updateProjectionMatrix();
|
|
2308
|
+
for ( let i = 0; i < intersect.length; i ++ ) {
|
|
2208
2309
|
|
|
2209
|
-
|
|
2210
|
-
this._tbRadius = this.calculateTbRadius( camera );
|
|
2211
|
-
this.makeGizmos( this.target, this._tbRadius );
|
|
2310
|
+
if ( intersect[ i ].object.uuid != this._gizmos.uuid && intersect[ i ].face != null ) {
|
|
2212
2311
|
|
|
2213
|
-
|
|
2312
|
+
return intersect[ i ].point.clone();
|
|
2214
2313
|
|
|
2215
|
-
|
|
2216
|
-
* Set gizmos visibility
|
|
2217
|
-
* @param {Boolean} value Value of gizmos visibility
|
|
2218
|
-
*/
|
|
2219
|
-
setGizmosVisible( value ) {
|
|
2314
|
+
}
|
|
2220
2315
|
|
|
2221
|
-
|
|
2222
|
-
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
return null;
|
|
2223
2319
|
|
|
2224
2320
|
}
|
|
2225
2321
|
|
|
2226
2322
|
/**
|
|
2227
|
-
*
|
|
2228
|
-
* @param {
|
|
2323
|
+
* Unproject the cursor on the trackball surface
|
|
2324
|
+
* @param {Camera} camera The virtual camera
|
|
2325
|
+
* @param {Number} cursorX Cursor horizontal coordinate on screen
|
|
2326
|
+
* @param {Number} cursorY Cursor vertical coordinate on screen
|
|
2327
|
+
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
2328
|
+
* @param {number} tbRadius The trackball radius
|
|
2329
|
+
* @returns {Vector3} The unprojected point on the trackball surface
|
|
2229
2330
|
*/
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
this.radiusFactor = value;
|
|
2233
|
-
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
2234
|
-
|
|
2235
|
-
const curve = new EllipseCurve( 0, 0, this._tbRadius, this._tbRadius );
|
|
2236
|
-
const points = curve.getPoints( this._curvePts );
|
|
2237
|
-
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
2331
|
+
unprojectOnTbSurface( camera, cursorX, cursorY, canvas, tbRadius ) {
|
|
2238
2332
|
|
|
2333
|
+
if ( camera.type == 'OrthographicCamera' ) {
|
|
2239
2334
|
|
|
2240
|
-
|
|
2335
|
+
this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
|
|
2336
|
+
this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
|
|
2241
2337
|
|
|
2242
|
-
this.
|
|
2338
|
+
const x2 = Math.pow( this._v2_1.x, 2 );
|
|
2339
|
+
const y2 = Math.pow( this._v2_1.y, 2 );
|
|
2340
|
+
const r2 = Math.pow( this._tbRadius, 2 );
|
|
2243
2341
|
|
|
2244
|
-
|
|
2342
|
+
if ( x2 + y2 <= r2 * 0.5 ) {
|
|
2245
2343
|
|
|
2246
|
-
|
|
2344
|
+
//intersection with sphere
|
|
2345
|
+
this._v3_1.setZ( Math.sqrt( r2 - ( x2 + y2 ) ) );
|
|
2247
2346
|
|
|
2248
|
-
|
|
2347
|
+
} else {
|
|
2249
2348
|
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
* @param {Vector3} tbCenter The trackball center
|
|
2253
|
-
* @param {number} tbRadius The trackball radius
|
|
2254
|
-
*/
|
|
2255
|
-
makeGizmos = ( tbCenter, tbRadius ) => {
|
|
2349
|
+
//intersection with hyperboloid
|
|
2350
|
+
this._v3_1.setZ( ( r2 * 0.5 ) / ( Math.sqrt( x2 + y2 ) ) );
|
|
2256
2351
|
|
|
2257
|
-
|
|
2258
|
-
const points = curve.getPoints( this._curvePts );
|
|
2352
|
+
}
|
|
2259
2353
|
|
|
2260
|
-
|
|
2261
|
-
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
2354
|
+
return this._v3_1;
|
|
2262
2355
|
|
|
2263
|
-
|
|
2264
|
-
const curveMaterialX = new LineBasicMaterial( { color: 0xff8080, fog: false, transparent: true, opacity: 0.6 } );
|
|
2265
|
-
const curveMaterialY = new LineBasicMaterial( { color: 0x80ff80, fog: false, transparent: true, opacity: 0.6 } );
|
|
2266
|
-
const curveMaterialZ = new LineBasicMaterial( { color: 0x8080ff, fog: false, transparent: true, opacity: 0.6 } );
|
|
2356
|
+
} else if ( camera.type == 'PerspectiveCamera' ) {
|
|
2267
2357
|
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
const gizmoY = new Line( curveGeometry, curveMaterialY );
|
|
2271
|
-
const gizmoZ = new Line( curveGeometry, curveMaterialZ );
|
|
2358
|
+
//unproject cursor on the near plane
|
|
2359
|
+
this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
|
|
2272
2360
|
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
gizmoY.rotation.y = rotation;
|
|
2361
|
+
this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
|
|
2362
|
+
this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
|
|
2276
2363
|
|
|
2364
|
+
const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
|
|
2365
|
+
const cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
|
|
2366
|
+
const radius2 = Math.pow( tbRadius, 2 );
|
|
2277
2367
|
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2368
|
+
// camera
|
|
2369
|
+
// |\
|
|
2370
|
+
// | \
|
|
2371
|
+
// | \
|
|
2372
|
+
// h | \
|
|
2373
|
+
// | \
|
|
2374
|
+
// | \
|
|
2375
|
+
// _ _ | _ _ _\ _ _ near plane
|
|
2376
|
+
// l
|
|
2281
2377
|
|
|
2282
|
-
|
|
2378
|
+
const h = this._v3_1.z;
|
|
2379
|
+
const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
|
|
2283
2380
|
|
|
2284
|
-
|
|
2285
|
-
const size = 1 / this.camera.zoom;
|
|
2286
|
-
this._scaleMatrix.makeScale( size, size, size );
|
|
2287
|
-
this._translationMatrix.makeTranslation( - tbCenter.x, - tbCenter.y, - tbCenter.z );
|
|
2381
|
+
if ( l == 0 ) {
|
|
2288
2382
|
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2383
|
+
//ray aligned with camera
|
|
2384
|
+
rayDir.set( this._v3_1.x, this._v3_1.y, tbRadius );
|
|
2385
|
+
return rayDir;
|
|
2292
2386
|
|
|
2293
|
-
|
|
2387
|
+
}
|
|
2294
2388
|
|
|
2295
|
-
|
|
2389
|
+
const m = h / l;
|
|
2390
|
+
const q = cameraGizmoDistance;
|
|
2296
2391
|
|
|
2297
|
-
|
|
2392
|
+
/*
|
|
2393
|
+
* calculate intersection point between unprojected ray and trackball surface
|
|
2394
|
+
*|y = m * x + q
|
|
2395
|
+
*|x^2 + y^2 = r^2
|
|
2396
|
+
*
|
|
2397
|
+
* (m^2 + 1) * x^2 + (2 * m * q) * x + q^2 - r^2 = 0
|
|
2398
|
+
*/
|
|
2399
|
+
let a = Math.pow( m, 2 ) + 1;
|
|
2400
|
+
let b = 2 * m * q;
|
|
2401
|
+
let c = Math.pow( q, 2 ) - radius2;
|
|
2402
|
+
let delta = Math.pow( b, 2 ) - ( 4 * a * c );
|
|
2298
2403
|
|
|
2299
|
-
|
|
2404
|
+
if ( delta >= 0 ) {
|
|
2300
2405
|
|
|
2301
|
-
|
|
2406
|
+
//intersection with sphere
|
|
2407
|
+
this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
|
|
2408
|
+
this._v2_1.setY( m * this._v2_1.x + q );
|
|
2302
2409
|
|
|
2303
|
-
|
|
2304
|
-
object.material.dispose();
|
|
2410
|
+
const angle = MathUtils.RAD2DEG * this._v2_1.angle();
|
|
2305
2411
|
|
|
2306
|
-
|
|
2412
|
+
if ( angle >= 45 ) {
|
|
2307
2413
|
|
|
2308
|
-
|
|
2414
|
+
//if angle between intersection point and X' axis is >= 45°, return that point
|
|
2415
|
+
//otherwise, calculate intersection point with hyperboloid
|
|
2309
2416
|
|
|
2310
|
-
|
|
2417
|
+
const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
|
|
2418
|
+
rayDir.multiplyScalar( rayLength );
|
|
2419
|
+
rayDir.z += cameraGizmoDistance;
|
|
2420
|
+
return rayDir;
|
|
2311
2421
|
|
|
2312
|
-
|
|
2422
|
+
}
|
|
2313
2423
|
|
|
2314
|
-
|
|
2315
|
-
this._gizmos.add( gizmoY );
|
|
2316
|
-
this._gizmos.add( gizmoZ );
|
|
2424
|
+
}
|
|
2317
2425
|
|
|
2318
|
-
|
|
2426
|
+
//intersection with hyperboloid
|
|
2427
|
+
/*
|
|
2428
|
+
*|y = m * x + q
|
|
2429
|
+
*|y = (1 / x) * (r^2 / 2)
|
|
2430
|
+
*
|
|
2431
|
+
* m * x^2 + q * x - r^2 / 2 = 0
|
|
2432
|
+
*/
|
|
2319
2433
|
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
*/
|
|
2327
|
-
onFocusAnim = ( time, point, cameraMatrix, gizmoMatrix ) => {
|
|
2434
|
+
a = m;
|
|
2435
|
+
b = q;
|
|
2436
|
+
c = - radius2 * 0.5;
|
|
2437
|
+
delta = Math.pow( b, 2 ) - ( 4 * a * c );
|
|
2438
|
+
this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
|
|
2439
|
+
this._v2_1.setY( m * this._v2_1.x + q );
|
|
2328
2440
|
|
|
2329
|
-
|
|
2441
|
+
const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
|
|
2330
2442
|
|
|
2331
|
-
|
|
2332
|
-
|
|
2443
|
+
rayDir.multiplyScalar( rayLength );
|
|
2444
|
+
rayDir.z += cameraGizmoDistance;
|
|
2445
|
+
return rayDir;
|
|
2333
2446
|
|
|
2334
2447
|
}
|
|
2335
2448
|
|
|
2336
|
-
|
|
2449
|
+
}
|
|
2337
2450
|
|
|
2338
|
-
const deltaTime = time - this._timeStart;
|
|
2339
|
-
const animTime = deltaTime / this.focusAnimationTime;
|
|
2340
2451
|
|
|
2341
|
-
|
|
2452
|
+
/**
|
|
2453
|
+
* Unproject the cursor on the plane passing through the center of the trackball orthogonal to the camera
|
|
2454
|
+
* @param {Camera} camera The virtual camera
|
|
2455
|
+
* @param {Number} cursorX Cursor horizontal coordinate on screen
|
|
2456
|
+
* @param {Number} cursorY Cursor vertical coordinate on screen
|
|
2457
|
+
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
2458
|
+
* @param {Boolean} initialDistance If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only)
|
|
2459
|
+
* @returns {Vector3} The unprojected point on the trackball plane
|
|
2460
|
+
*/
|
|
2461
|
+
unprojectOnTbPlane( camera, cursorX, cursorY, canvas, initialDistance = false ) {
|
|
2342
2462
|
|
|
2343
|
-
|
|
2463
|
+
if ( camera.type == 'OrthographicCamera' ) {
|
|
2344
2464
|
|
|
2345
|
-
|
|
2465
|
+
this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
|
|
2466
|
+
this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
|
|
2346
2467
|
|
|
2347
|
-
|
|
2468
|
+
return this._v3_1.clone();
|
|
2348
2469
|
|
|
2349
|
-
|
|
2470
|
+
} else if ( camera.type == 'PerspectiveCamera' ) {
|
|
2350
2471
|
|
|
2351
|
-
|
|
2352
|
-
this.updateTbState( STATE.IDLE, false );
|
|
2353
|
-
this.activateGizmos( false );
|
|
2472
|
+
this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
|
|
2354
2473
|
|
|
2355
|
-
|
|
2474
|
+
//unproject cursor on the near plane
|
|
2475
|
+
this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
|
|
2476
|
+
this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
|
|
2356
2477
|
|
|
2357
|
-
|
|
2478
|
+
const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
|
|
2358
2479
|
|
|
2359
|
-
|
|
2360
|
-
|
|
2480
|
+
// camera
|
|
2481
|
+
// |\
|
|
2482
|
+
// | \
|
|
2483
|
+
// | \
|
|
2484
|
+
// h | \
|
|
2485
|
+
// | \
|
|
2486
|
+
// | \
|
|
2487
|
+
// _ _ | _ _ _\ _ _ near plane
|
|
2488
|
+
// l
|
|
2361
2489
|
|
|
2362
|
-
|
|
2363
|
-
|
|
2490
|
+
const h = this._v3_1.z;
|
|
2491
|
+
const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
|
|
2492
|
+
let cameraGizmoDistance;
|
|
2364
2493
|
|
|
2365
|
-
|
|
2366
|
-
const self = this;
|
|
2367
|
-
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
2494
|
+
if ( initialDistance ) {
|
|
2368
2495
|
|
|
2369
|
-
|
|
2496
|
+
cameraGizmoDistance = this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ).distanceTo( this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ) );
|
|
2370
2497
|
|
|
2371
|
-
|
|
2498
|
+
} else {
|
|
2499
|
+
|
|
2500
|
+
cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
|
|
2372
2501
|
|
|
2373
2502
|
}
|
|
2374
2503
|
|
|
2375
|
-
|
|
2504
|
+
/*
|
|
2505
|
+
* calculate intersection point between unprojected ray and the plane
|
|
2506
|
+
*|y = mx + q
|
|
2507
|
+
*|y = 0
|
|
2508
|
+
*
|
|
2509
|
+
* x = -q/m
|
|
2510
|
+
*/
|
|
2511
|
+
if ( l == 0 ) {
|
|
2376
2512
|
|
|
2377
|
-
|
|
2513
|
+
//ray aligned with camera
|
|
2514
|
+
rayDir.set( 0, 0, 0 );
|
|
2515
|
+
return rayDir;
|
|
2378
2516
|
|
|
2379
|
-
|
|
2380
|
-
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
const m = h / l;
|
|
2520
|
+
const q = cameraGizmoDistance;
|
|
2521
|
+
const x = - q / m;
|
|
2522
|
+
|
|
2523
|
+
const rayLength = Math.sqrt( Math.pow( q, 2 ) + Math.pow( x, 2 ) );
|
|
2524
|
+
rayDir.multiplyScalar( rayLength );
|
|
2525
|
+
rayDir.z = 0;
|
|
2526
|
+
return rayDir;
|
|
2381
2527
|
|
|
2382
2528
|
}
|
|
2383
2529
|
|
|
2384
|
-
}
|
|
2530
|
+
}
|
|
2385
2531
|
|
|
2386
2532
|
/**
|
|
2387
|
-
*
|
|
2388
|
-
* @param {Number} time Instant in which this function is called as performance.now()
|
|
2389
|
-
* @param {Vector3} rotationAxis Rotation axis
|
|
2390
|
-
* @param {number} w0 Initial angular velocity
|
|
2533
|
+
* Update camera and gizmos state
|
|
2391
2534
|
*/
|
|
2392
|
-
|
|
2535
|
+
updateMatrixState() {
|
|
2393
2536
|
|
|
2394
|
-
|
|
2537
|
+
//update camera and gizmos state
|
|
2538
|
+
this._cameraMatrixState.copy( this.camera.matrix );
|
|
2539
|
+
this._gizmoMatrixState.copy( this._gizmos.matrix );
|
|
2395
2540
|
|
|
2396
|
-
|
|
2397
|
-
this._anglePrev = 0;
|
|
2398
|
-
this._angleCurrent = 0;
|
|
2399
|
-
this._timeStart = time;
|
|
2541
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
2400
2542
|
|
|
2401
|
-
|
|
2543
|
+
this._cameraProjectionState.copy( this.camera.projectionMatrix );
|
|
2544
|
+
this.camera.updateProjectionMatrix();
|
|
2545
|
+
this._zoomState = this.camera.zoom;
|
|
2402
2546
|
|
|
2403
|
-
if ( this.
|
|
2547
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
2404
2548
|
|
|
2405
|
-
|
|
2406
|
-
const deltaTime = ( time - this._timeStart ) / 1000;
|
|
2407
|
-
const w = w0 + ( ( - this.dampingFactor ) * deltaTime );
|
|
2549
|
+
this._fovState = this.camera.fov;
|
|
2408
2550
|
|
|
2409
|
-
|
|
2551
|
+
}
|
|
2410
2552
|
|
|
2411
|
-
|
|
2412
|
-
this._angleCurrent = 0.5 * ( - this.dampingFactor ) * Math.pow( deltaTime, 2 ) + w0 * deltaTime + 0;
|
|
2413
|
-
this.applyTransformMatrix( this.rotate( rotationAxis, this._angleCurrent ) );
|
|
2414
|
-
this.dispatchEvent( _changeEvent );
|
|
2415
|
-
const self = this;
|
|
2416
|
-
this._animationId = window.requestAnimationFrame( function ( t ) {
|
|
2553
|
+
}
|
|
2417
2554
|
|
|
2418
|
-
|
|
2555
|
+
/**
|
|
2556
|
+
* Update the trackball FSA
|
|
2557
|
+
* @param {STATE} newState New state of the FSA
|
|
2558
|
+
* @param {Boolean} updateMatrices If matriices state should be updated
|
|
2559
|
+
*/
|
|
2560
|
+
updateTbState( newState, updateMatrices ) {
|
|
2419
2561
|
|
|
2420
|
-
|
|
2562
|
+
this._state = newState;
|
|
2563
|
+
if ( updateMatrices ) {
|
|
2421
2564
|
|
|
2422
|
-
|
|
2565
|
+
this.updateMatrixState();
|
|
2423
2566
|
|
|
2424
|
-
|
|
2425
|
-
this._timeStart = - 1;
|
|
2567
|
+
}
|
|
2426
2568
|
|
|
2427
|
-
|
|
2428
|
-
this.activateGizmos( false );
|
|
2569
|
+
}
|
|
2429
2570
|
|
|
2430
|
-
|
|
2571
|
+
update() {
|
|
2431
2572
|
|
|
2432
|
-
|
|
2573
|
+
const EPS = 0.000001;
|
|
2433
2574
|
|
|
2434
|
-
|
|
2575
|
+
if ( this.target.equals( this._currentTarget ) === false ) {
|
|
2435
2576
|
|
|
2436
|
-
//
|
|
2577
|
+
this._gizmos.position.copy( this.target ); //for correct radius calculation
|
|
2578
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
2579
|
+
this.makeGizmos( this.target, this._tbRadius );
|
|
2580
|
+
this._currentTarget.copy( this.target );
|
|
2437
2581
|
|
|
2438
|
-
|
|
2439
|
-
this._timeStart = - 1;
|
|
2582
|
+
}
|
|
2440
2583
|
|
|
2441
|
-
|
|
2584
|
+
//check min/max parameters
|
|
2585
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
2442
2586
|
|
|
2443
|
-
|
|
2444
|
-
|
|
2587
|
+
//check zoom
|
|
2588
|
+
if ( this.camera.zoom > this.maxZoom || this.camera.zoom < this.minZoom ) {
|
|
2589
|
+
|
|
2590
|
+
const newZoom = MathUtils.clamp( this.camera.zoom, this.minZoom, this.maxZoom );
|
|
2591
|
+
this.applyTransformMatrix( this.scale( newZoom / this.camera.zoom, this._gizmos.position, true ) );
|
|
2445
2592
|
|
|
2446
2593
|
}
|
|
2447
2594
|
|
|
2448
|
-
}
|
|
2595
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
2449
2596
|
|
|
2450
|
-
|
|
2597
|
+
//check distance
|
|
2598
|
+
const distance = this.camera.position.distanceTo( this._gizmos.position );
|
|
2451
2599
|
|
|
2600
|
+
if ( distance > this.maxDistance + EPS || distance < this.minDistance - EPS ) {
|
|
2452
2601
|
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
* @param {Vector3} p1 Ending point
|
|
2457
|
-
* @param {Boolean} adjust If movement should be adjusted considering camera distance (Perspective only)
|
|
2458
|
-
*/
|
|
2459
|
-
pan = ( p0, p1, adjust = false ) => {
|
|
2602
|
+
const newDistance = MathUtils.clamp( distance, this.minDistance, this.maxDistance );
|
|
2603
|
+
this.applyTransformMatrix( this.scale( newDistance / distance, this._gizmos.position ) );
|
|
2604
|
+
this.updateMatrixState();
|
|
2460
2605
|
|
|
2461
|
-
|
|
2606
|
+
}
|
|
2462
2607
|
|
|
2463
|
-
|
|
2608
|
+
//check fov
|
|
2609
|
+
if ( this.camera.fov < this.minFov || this.camera.fov > this.maxFov ) {
|
|
2464
2610
|
|
|
2465
|
-
|
|
2466
|
-
|
|
2611
|
+
this.camera.fov = MathUtils.clamp( this.camera.fov, this.minFov, this.maxFov );
|
|
2612
|
+
this.camera.updateProjectionMatrix();
|
|
2467
2613
|
|
|
2468
|
-
|
|
2614
|
+
}
|
|
2469
2615
|
|
|
2470
|
-
|
|
2471
|
-
this.
|
|
2472
|
-
this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ); //gizmo's initial position
|
|
2473
|
-
const distanceFactor = this._v3_1.distanceTo( this._v3_2 ) / this.camera.position.distanceTo( this._gizmos.position );
|
|
2474
|
-
movement.multiplyScalar( 1 / distanceFactor );
|
|
2616
|
+
const oldRadius = this._tbRadius;
|
|
2617
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
2475
2618
|
|
|
2476
|
-
|
|
2619
|
+
if ( oldRadius < this._tbRadius - EPS || oldRadius > this._tbRadius + EPS ) {
|
|
2477
2620
|
|
|
2478
|
-
|
|
2621
|
+
const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
|
|
2622
|
+
const newRadius = this._tbRadius / scale;
|
|
2623
|
+
const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
|
|
2624
|
+
const points = curve.getPoints( this._curvePts );
|
|
2625
|
+
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
2479
2626
|
|
|
2480
|
-
|
|
2627
|
+
for ( const gizmo in this._gizmos.children ) {
|
|
2481
2628
|
|
|
2482
|
-
|
|
2483
|
-
return _transformation;
|
|
2629
|
+
this._gizmos.children[ gizmo ].geometry = curveGeometry;
|
|
2484
2630
|
|
|
2485
|
-
|
|
2631
|
+
}
|
|
2486
2632
|
|
|
2487
|
-
|
|
2488
|
-
* Reset trackball
|
|
2489
|
-
*/
|
|
2490
|
-
reset = () => {
|
|
2633
|
+
}
|
|
2491
2634
|
|
|
2492
|
-
|
|
2635
|
+
}
|
|
2493
2636
|
|
|
2494
|
-
|
|
2637
|
+
this.camera.lookAt( this._gizmos.position );
|
|
2495
2638
|
|
|
2496
|
-
|
|
2639
|
+
}
|
|
2497
2640
|
|
|
2498
|
-
|
|
2641
|
+
setStateFromJSON( json ) {
|
|
2499
2642
|
|
|
2500
|
-
|
|
2501
|
-
this.camera.far = this._farPos;
|
|
2502
|
-
this._cameraMatrixState.copy( this._cameraMatrixState0 );
|
|
2503
|
-
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
2504
|
-
this.camera.up.copy( this._up0 );
|
|
2643
|
+
const state = JSON.parse( json );
|
|
2505
2644
|
|
|
2506
|
-
|
|
2507
|
-
this.camera.updateProjectionMatrix();
|
|
2645
|
+
if ( state.arcballState != undefined ) {
|
|
2508
2646
|
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
this._gizmos.updateMatrix();
|
|
2647
|
+
this._cameraMatrixState.fromArray( state.arcballState.cameraMatrix.elements );
|
|
2648
|
+
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
2512
2649
|
|
|
2513
|
-
|
|
2514
|
-
|
|
2650
|
+
this.camera.up.copy( state.arcballState.cameraUp );
|
|
2651
|
+
this.camera.near = state.arcballState.cameraNear;
|
|
2652
|
+
this.camera.far = state.arcballState.cameraFar;
|
|
2515
2653
|
|
|
2516
|
-
|
|
2654
|
+
this.camera.zoom = state.arcballState.cameraZoom;
|
|
2517
2655
|
|
|
2518
|
-
|
|
2656
|
+
if ( this.camera.isPerspectiveCamera ) {
|
|
2519
2657
|
|
|
2520
|
-
|
|
2658
|
+
this.camera.fov = state.arcballState.cameraFov;
|
|
2521
2659
|
|
|
2522
|
-
|
|
2660
|
+
}
|
|
2523
2661
|
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
* @param {Vector3} axis Rotation axis
|
|
2527
|
-
* @param {number} angle Angle in radians
|
|
2528
|
-
* @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera
|
|
2529
|
-
*/
|
|
2530
|
-
rotate = ( axis, angle ) => {
|
|
2662
|
+
this._gizmoMatrixState.fromArray( state.arcballState.gizmoMatrix.elements );
|
|
2663
|
+
this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
|
|
2531
2664
|
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
this._rotationMatrix.makeRotationAxis( axis, - angle );
|
|
2665
|
+
this.camera.updateMatrix();
|
|
2666
|
+
this.camera.updateProjectionMatrix();
|
|
2535
2667
|
|
|
2536
|
-
|
|
2537
|
-
this._m4_1.makeTranslation( point.x, point.y, point.z );
|
|
2538
|
-
this._m4_1.multiply( this._rotationMatrix );
|
|
2539
|
-
this._m4_1.multiply( this._translationMatrix );
|
|
2668
|
+
this._gizmos.updateMatrix();
|
|
2540
2669
|
|
|
2541
|
-
|
|
2670
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
2671
|
+
const gizmoTmp = new Matrix4().copy( this._gizmoMatrixState0 );
|
|
2672
|
+
this.makeGizmos( this._gizmos.position, this._tbRadius );
|
|
2673
|
+
this._gizmoMatrixState0.copy( gizmoTmp );
|
|
2542
2674
|
|
|
2543
|
-
|
|
2675
|
+
this.camera.lookAt( this._gizmos.position );
|
|
2676
|
+
this.updateTbState( STATE.IDLE, false );
|
|
2544
2677
|
|
|
2545
|
-
|
|
2678
|
+
this.dispatchEvent( _changeEvent );
|
|
2546
2679
|
|
|
2547
|
-
|
|
2680
|
+
}
|
|
2548
2681
|
|
|
2549
|
-
|
|
2550
|
-
if ( this.camera.isOrthographicCamera ) {
|
|
2682
|
+
}
|
|
2551
2683
|
|
|
2552
|
-
|
|
2684
|
+
}
|
|
2553
2685
|
|
|
2554
|
-
|
|
2555
|
-
cameraMatrix: this.camera.matrix,
|
|
2556
|
-
cameraNear: this.camera.near,
|
|
2557
|
-
cameraUp: this.camera.up,
|
|
2558
|
-
cameraZoom: this.camera.zoom,
|
|
2559
|
-
gizmoMatrix: this._gizmos.matrix
|
|
2686
|
+
//listeners
|
|
2560
2687
|
|
|
2561
|
-
|
|
2688
|
+
function onWindowResize() {
|
|
2562
2689
|
|
|
2563
|
-
|
|
2690
|
+
const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
|
|
2691
|
+
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
2564
2692
|
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
cameraNear: this.camera.near,
|
|
2570
|
-
cameraUp: this.camera.up,
|
|
2571
|
-
cameraZoom: this.camera.zoom,
|
|
2572
|
-
gizmoMatrix: this._gizmos.matrix
|
|
2693
|
+
const newRadius = this._tbRadius / scale;
|
|
2694
|
+
const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
|
|
2695
|
+
const points = curve.getPoints( this._curvePts );
|
|
2696
|
+
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
2573
2697
|
|
|
2574
|
-
} } );
|
|
2575
2698
|
|
|
2576
|
-
|
|
2699
|
+
for ( const gizmo in this._gizmos.children ) {
|
|
2577
2700
|
|
|
2578
|
-
|
|
2701
|
+
this._gizmos.children[ gizmo ].geometry = curveGeometry;
|
|
2579
2702
|
|
|
2580
|
-
}
|
|
2703
|
+
}
|
|
2581
2704
|
|
|
2582
|
-
|
|
2705
|
+
this.dispatchEvent( _changeEvent );
|
|
2583
2706
|
|
|
2584
|
-
|
|
2585
|
-
navigator.clipboard.readText().then( function resolved( value ) {
|
|
2707
|
+
}
|
|
2586
2708
|
|
|
2587
|
-
|
|
2709
|
+
function onContextMenu( event ) {
|
|
2588
2710
|
|
|
2589
|
-
|
|
2711
|
+
if ( ! this.enabled ) {
|
|
2590
2712
|
|
|
2591
|
-
|
|
2713
|
+
return;
|
|
2592
2714
|
|
|
2593
|
-
|
|
2594
|
-
* Save the current state of the control. This can later be recover with .reset
|
|
2595
|
-
*/
|
|
2596
|
-
saveState = () => {
|
|
2715
|
+
}
|
|
2597
2716
|
|
|
2598
|
-
|
|
2599
|
-
this._gizmoMatrixState0.copy( this._gizmos.matrix );
|
|
2600
|
-
this._nearPos = this.camera.near;
|
|
2601
|
-
this._farPos = this.camera.far;
|
|
2602
|
-
this._zoom0 = this.camera.zoom;
|
|
2603
|
-
this._up0.copy( this.camera.up );
|
|
2717
|
+
for ( let i = 0; i < this.mouseActions.length; i ++ ) {
|
|
2604
2718
|
|
|
2605
|
-
if ( this.
|
|
2719
|
+
if ( this.mouseActions[ i ].mouse == 2 ) {
|
|
2606
2720
|
|
|
2607
|
-
|
|
2721
|
+
//prevent only if button 2 is actually used
|
|
2722
|
+
event.preventDefault();
|
|
2723
|
+
break;
|
|
2608
2724
|
|
|
2609
2725
|
}
|
|
2610
2726
|
|
|
2611
|
-
}
|
|
2727
|
+
}
|
|
2612
2728
|
|
|
2613
|
-
|
|
2614
|
-
* Perform uniform scale operation around a given point
|
|
2615
|
-
* @param {Number} size Scale factor
|
|
2616
|
-
* @param {Vector3} point Point around which scale
|
|
2617
|
-
* @param {Boolean} scaleGizmos If gizmos should be scaled (Perspective only)
|
|
2618
|
-
* @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos
|
|
2619
|
-
*/
|
|
2620
|
-
scale = ( size, point, scaleGizmos = true ) => {
|
|
2729
|
+
}
|
|
2621
2730
|
|
|
2622
|
-
|
|
2623
|
-
let sizeInverse = 1 / size;
|
|
2731
|
+
function onPointerCancel() {
|
|
2624
2732
|
|
|
2625
|
-
|
|
2733
|
+
this._touchStart.splice( 0, this._touchStart.length );
|
|
2734
|
+
this._touchCurrent.splice( 0, this._touchCurrent.length );
|
|
2735
|
+
this._input = INPUT.NONE;
|
|
2626
2736
|
|
|
2627
|
-
|
|
2628
|
-
this.camera.zoom = this._zoomState;
|
|
2629
|
-
this.camera.zoom *= size;
|
|
2737
|
+
}
|
|
2630
2738
|
|
|
2631
|
-
|
|
2632
|
-
if ( this.camera.zoom > this.maxZoom ) {
|
|
2739
|
+
function onPointerDown( event ) {
|
|
2633
2740
|
|
|
2634
|
-
|
|
2635
|
-
sizeInverse = this._zoomState / this.maxZoom;
|
|
2741
|
+
if ( event.button == 0 && event.isPrimary ) {
|
|
2636
2742
|
|
|
2637
|
-
|
|
2743
|
+
this._downValid = true;
|
|
2744
|
+
this._downEvents.push( event );
|
|
2745
|
+
this._downStart = performance.now();
|
|
2638
2746
|
|
|
2639
|
-
|
|
2640
|
-
sizeInverse = this._zoomState / this.minZoom;
|
|
2747
|
+
} else {
|
|
2641
2748
|
|
|
2642
|
-
|
|
2749
|
+
this._downValid = false;
|
|
2643
2750
|
|
|
2644
|
-
|
|
2751
|
+
}
|
|
2645
2752
|
|
|
2646
|
-
|
|
2753
|
+
if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
|
|
2647
2754
|
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
this._translationMatrix.makeTranslation( - this._v3_1.x, - this._v3_1.y, - this._v3_1.z );
|
|
2755
|
+
this._touchStart.push( event );
|
|
2756
|
+
this._touchCurrent.push( event );
|
|
2651
2757
|
|
|
2652
|
-
|
|
2653
|
-
this._m4_2.multiply( this._translationMatrix );
|
|
2758
|
+
switch ( this._input ) {
|
|
2654
2759
|
|
|
2760
|
+
case INPUT.NONE:
|
|
2655
2761
|
|
|
2656
|
-
|
|
2657
|
-
|
|
2762
|
+
//singleStart
|
|
2763
|
+
this._input = INPUT.ONE_FINGER;
|
|
2764
|
+
this.onSinglePanStart( event, 'ROTATE' );
|
|
2658
2765
|
|
|
2659
|
-
|
|
2660
|
-
|
|
2766
|
+
window.addEventListener( 'pointermove', this._onPointerMove );
|
|
2767
|
+
window.addEventListener( 'pointerup', this._onPointerUp );
|
|
2661
2768
|
|
|
2662
|
-
|
|
2663
|
-
this._m4_2.premultiply( this._m4_1 );
|
|
2769
|
+
break;
|
|
2664
2770
|
|
|
2665
|
-
|
|
2666
|
-
|
|
2771
|
+
case INPUT.ONE_FINGER:
|
|
2772
|
+
case INPUT.ONE_FINGER_SWITCHED:
|
|
2667
2773
|
|
|
2668
|
-
|
|
2774
|
+
//doubleStart
|
|
2775
|
+
this._input = INPUT.TWO_FINGER;
|
|
2669
2776
|
|
|
2670
|
-
|
|
2671
|
-
|
|
2777
|
+
this.onRotateStart();
|
|
2778
|
+
this.onPinchStart();
|
|
2779
|
+
this.onDoublePanStart();
|
|
2672
2780
|
|
|
2673
|
-
|
|
2674
|
-
let distance = this._v3_1.distanceTo( _scalePointTemp );
|
|
2675
|
-
let amount = distance - ( distance * sizeInverse );
|
|
2781
|
+
break;
|
|
2676
2782
|
|
|
2677
|
-
|
|
2678
|
-
const newDistance = distance - amount;
|
|
2679
|
-
if ( newDistance < this.minDistance ) {
|
|
2783
|
+
case INPUT.TWO_FINGER:
|
|
2680
2784
|
|
|
2681
|
-
|
|
2682
|
-
|
|
2785
|
+
//multipleStart
|
|
2786
|
+
this._input = INPUT.MULT_FINGER;
|
|
2787
|
+
this.onTriplePanStart( event );
|
|
2788
|
+
break;
|
|
2683
2789
|
|
|
2684
|
-
|
|
2790
|
+
}
|
|
2685
2791
|
|
|
2686
|
-
|
|
2687
|
-
amount = distance - ( distance * sizeInverse );
|
|
2792
|
+
} else if ( event.pointerType != 'touch' && this._input == INPUT.NONE ) {
|
|
2688
2793
|
|
|
2689
|
-
|
|
2794
|
+
let modifier = null;
|
|
2690
2795
|
|
|
2691
|
-
|
|
2796
|
+
if ( event.ctrlKey || event.metaKey ) {
|
|
2692
2797
|
|
|
2693
|
-
|
|
2798
|
+
modifier = 'CTRL';
|
|
2694
2799
|
|
|
2800
|
+
} else if ( event.shiftKey ) {
|
|
2695
2801
|
|
|
2696
|
-
|
|
2802
|
+
modifier = 'SHIFT';
|
|
2697
2803
|
|
|
2698
|
-
|
|
2699
|
-
const pos = this._v3_2;
|
|
2804
|
+
}
|
|
2700
2805
|
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
_offset.copy( _scalePointTemp ).sub( this._v3_2 ).normalize().multiplyScalar( amount );
|
|
2806
|
+
this._mouseOp = this.getOpFromAction( event.button, modifier );
|
|
2807
|
+
if ( this._mouseOp != null ) {
|
|
2704
2808
|
|
|
2705
|
-
|
|
2706
|
-
|
|
2809
|
+
window.addEventListener( 'pointermove', this._onPointerMove );
|
|
2810
|
+
window.addEventListener( 'pointerup', this._onPointerUp );
|
|
2707
2811
|
|
|
2708
|
-
|
|
2709
|
-
|
|
2812
|
+
//singleStart
|
|
2813
|
+
this._input = INPUT.CURSOR;
|
|
2814
|
+
this._button = event.button;
|
|
2815
|
+
this.onSinglePanStart( event, this._mouseOp );
|
|
2710
2816
|
|
|
2711
|
-
|
|
2817
|
+
}
|
|
2712
2818
|
|
|
2713
|
-
|
|
2714
|
-
this.setTransformationMatrices( this._m4_1, this._m4_2 );
|
|
2819
|
+
}
|
|
2715
2820
|
|
|
2821
|
+
}
|
|
2716
2822
|
|
|
2717
|
-
|
|
2823
|
+
function onPointerMove( event ) {
|
|
2718
2824
|
|
|
2719
|
-
|
|
2825
|
+
if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
|
|
2720
2826
|
|
|
2721
|
-
|
|
2827
|
+
switch ( this._input ) {
|
|
2722
2828
|
|
|
2723
|
-
|
|
2829
|
+
case INPUT.ONE_FINGER:
|
|
2724
2830
|
|
|
2725
|
-
|
|
2831
|
+
//singleMove
|
|
2832
|
+
this.updateTouchEvent( event );
|
|
2726
2833
|
|
|
2727
|
-
|
|
2834
|
+
this.onSinglePanMove( event, STATE.ROTATE );
|
|
2835
|
+
break;
|
|
2728
2836
|
|
|
2729
|
-
|
|
2730
|
-
* Set camera fov
|
|
2731
|
-
* @param {Number} value fov to be setted
|
|
2732
|
-
*/
|
|
2733
|
-
setFov = ( value ) => {
|
|
2837
|
+
case INPUT.ONE_FINGER_SWITCHED:
|
|
2734
2838
|
|
|
2735
|
-
|
|
2839
|
+
const movement = this.calculatePointersDistance( this._touchCurrent[ 0 ], event ) * this._devPxRatio;
|
|
2736
2840
|
|
|
2737
|
-
|
|
2738
|
-
this.camera.updateProjectionMatrix();
|
|
2841
|
+
if ( movement >= this._switchSensibility ) {
|
|
2739
2842
|
|
|
2740
|
-
|
|
2843
|
+
//singleMove
|
|
2844
|
+
this._input = INPUT.ONE_FINGER;
|
|
2845
|
+
this.updateTouchEvent( event );
|
|
2741
2846
|
|
|
2742
|
-
|
|
2847
|
+
this.onSinglePanStart( event, 'ROTATE' );
|
|
2848
|
+
break;
|
|
2743
2849
|
|
|
2744
|
-
|
|
2745
|
-
* Set values in transformation object
|
|
2746
|
-
* @param {Matrix4} camera Transformation to be applied to the camera
|
|
2747
|
-
* @param {Matrix4} gizmos Transformation to be applied to gizmos
|
|
2748
|
-
*/
|
|
2749
|
-
setTransformationMatrices( camera = null, gizmos = null ) {
|
|
2850
|
+
}
|
|
2750
2851
|
|
|
2751
|
-
|
|
2852
|
+
break;
|
|
2752
2853
|
|
|
2753
|
-
|
|
2854
|
+
case INPUT.TWO_FINGER:
|
|
2754
2855
|
|
|
2755
|
-
|
|
2856
|
+
//rotate/pan/pinchMove
|
|
2857
|
+
this.updateTouchEvent( event );
|
|
2756
2858
|
|
|
2757
|
-
|
|
2859
|
+
this.onRotateMove();
|
|
2860
|
+
this.onPinchMove();
|
|
2861
|
+
this.onDoublePanMove();
|
|
2758
2862
|
|
|
2759
|
-
|
|
2863
|
+
break;
|
|
2760
2864
|
|
|
2761
|
-
|
|
2865
|
+
case INPUT.MULT_FINGER:
|
|
2762
2866
|
|
|
2763
|
-
|
|
2867
|
+
//multMove
|
|
2868
|
+
this.updateTouchEvent( event );
|
|
2764
2869
|
|
|
2765
|
-
|
|
2870
|
+
this.onTriplePanMove( event );
|
|
2871
|
+
break;
|
|
2766
2872
|
|
|
2767
2873
|
}
|
|
2768
2874
|
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
if ( _transformation.gizmos != null ) {
|
|
2772
|
-
|
|
2773
|
-
_transformation.gizmos.copy( gizmos );
|
|
2875
|
+
} else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
|
|
2774
2876
|
|
|
2775
|
-
|
|
2877
|
+
let modifier = null;
|
|
2776
2878
|
|
|
2777
|
-
|
|
2879
|
+
if ( event.ctrlKey || event.metaKey ) {
|
|
2778
2880
|
|
|
2779
|
-
|
|
2881
|
+
modifier = 'CTRL';
|
|
2780
2882
|
|
|
2781
|
-
} else {
|
|
2883
|
+
} else if ( event.shiftKey ) {
|
|
2782
2884
|
|
|
2783
|
-
|
|
2885
|
+
modifier = 'SHIFT';
|
|
2784
2886
|
|
|
2785
2887
|
}
|
|
2786
2888
|
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
/**
|
|
2790
|
-
* Rotate camera around its direction axis passing by a given point by a given angle
|
|
2791
|
-
* @param {Vector3} point The point where the rotation axis is passing trough
|
|
2792
|
-
* @param {Number} angle Angle in radians
|
|
2793
|
-
* @returns The computed transormation matix
|
|
2794
|
-
*/
|
|
2795
|
-
zRotate = ( point, angle ) => {
|
|
2796
|
-
|
|
2797
|
-
this._rotationMatrix.makeRotationAxis( this._rotationAxis, angle );
|
|
2798
|
-
this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
|
|
2889
|
+
const mouseOpState = this.getOpStateFromAction( this._button, modifier );
|
|
2799
2890
|
|
|
2800
|
-
|
|
2801
|
-
this._m4_1.multiply( this._rotationMatrix );
|
|
2802
|
-
this._m4_1.multiply( this._translationMatrix );
|
|
2891
|
+
if ( mouseOpState != null ) {
|
|
2803
2892
|
|
|
2804
|
-
|
|
2805
|
-
this._v3_2.copy( this._v3_1 ).applyAxisAngle( this._rotationAxis, angle ); //apply rotation
|
|
2806
|
-
this._v3_2.sub( this._v3_1 );
|
|
2893
|
+
this.onSinglePanMove( event, mouseOpState );
|
|
2807
2894
|
|
|
2808
|
-
|
|
2895
|
+
}
|
|
2809
2896
|
|
|
2810
|
-
|
|
2811
|
-
return _transformation;
|
|
2897
|
+
}
|
|
2812
2898
|
|
|
2813
|
-
|
|
2899
|
+
//checkDistance
|
|
2900
|
+
if ( this._downValid ) {
|
|
2814
2901
|
|
|
2902
|
+
const movement = this.calculatePointersDistance( this._downEvents[ this._downEvents.length - 1 ], event ) * this._devPxRatio;
|
|
2903
|
+
if ( movement > this._movementThreshold ) {
|
|
2815
2904
|
|
|
2816
|
-
|
|
2905
|
+
this._downValid = false;
|
|
2817
2906
|
|
|
2818
|
-
|
|
2907
|
+
}
|
|
2819
2908
|
|
|
2820
2909
|
}
|
|
2821
2910
|
|
|
2911
|
+
}
|
|
2822
2912
|
|
|
2823
|
-
|
|
2824
|
-
* Unproject the cursor on the 3D object surface
|
|
2825
|
-
* @param {Vector2} cursor Cursor coordinates in NDC
|
|
2826
|
-
* @param {Camera} camera Virtual camera
|
|
2827
|
-
* @returns {Vector3} The point of intersection with the model, if exist, null otherwise
|
|
2828
|
-
*/
|
|
2829
|
-
unprojectOnObj = ( cursor, camera ) => {
|
|
2913
|
+
function onPointerUp( event ) {
|
|
2830
2914
|
|
|
2831
|
-
|
|
2832
|
-
raycaster.near = camera.near;
|
|
2833
|
-
raycaster.far = camera.far;
|
|
2834
|
-
raycaster.setFromCamera( cursor, camera );
|
|
2915
|
+
if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
|
|
2835
2916
|
|
|
2836
|
-
const
|
|
2917
|
+
const nTouch = this._touchCurrent.length;
|
|
2837
2918
|
|
|
2838
|
-
for ( let i = 0; i <
|
|
2919
|
+
for ( let i = 0; i < nTouch; i ++ ) {
|
|
2839
2920
|
|
|
2840
|
-
if (
|
|
2921
|
+
if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
|
|
2841
2922
|
|
|
2842
|
-
|
|
2923
|
+
this._touchCurrent.splice( i, 1 );
|
|
2924
|
+
this._touchStart.splice( i, 1 );
|
|
2925
|
+
break;
|
|
2843
2926
|
|
|
2844
2927
|
}
|
|
2845
2928
|
|
|
2846
2929
|
}
|
|
2847
2930
|
|
|
2848
|
-
|
|
2931
|
+
switch ( this._input ) {
|
|
2849
2932
|
|
|
2850
|
-
|
|
2933
|
+
case INPUT.ONE_FINGER:
|
|
2934
|
+
case INPUT.ONE_FINGER_SWITCHED:
|
|
2851
2935
|
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
* @param {Number} cursorX Cursor horizontal coordinate on screen
|
|
2856
|
-
* @param {Number} cursorY Cursor vertical coordinate on screen
|
|
2857
|
-
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
2858
|
-
* @param {number} tbRadius The trackball radius
|
|
2859
|
-
* @returns {Vector3} The unprojected point on the trackball surface
|
|
2860
|
-
*/
|
|
2861
|
-
unprojectOnTbSurface = ( camera, cursorX, cursorY, canvas, tbRadius ) => {
|
|
2936
|
+
//singleEnd
|
|
2937
|
+
window.removeEventListener( 'pointermove', this._onPointerMove );
|
|
2938
|
+
window.removeEventListener( 'pointerup', this._onPointerUp );
|
|
2862
2939
|
|
|
2863
|
-
|
|
2940
|
+
this._input = INPUT.NONE;
|
|
2941
|
+
this.onSinglePanEnd();
|
|
2864
2942
|
|
|
2865
|
-
|
|
2866
|
-
this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
|
|
2943
|
+
break;
|
|
2867
2944
|
|
|
2868
|
-
|
|
2869
|
-
const y2 = Math.pow( this._v2_1.y, 2 );
|
|
2870
|
-
const r2 = Math.pow( this._tbRadius, 2 );
|
|
2945
|
+
case INPUT.TWO_FINGER:
|
|
2871
2946
|
|
|
2872
|
-
|
|
2947
|
+
//doubleEnd
|
|
2948
|
+
this.onDoublePanEnd( event );
|
|
2949
|
+
this.onPinchEnd( event );
|
|
2950
|
+
this.onRotateEnd( event );
|
|
2873
2951
|
|
|
2874
|
-
//
|
|
2875
|
-
this.
|
|
2952
|
+
//switching to singleStart
|
|
2953
|
+
this._input = INPUT.ONE_FINGER_SWITCHED;
|
|
2876
2954
|
|
|
2877
|
-
|
|
2955
|
+
break;
|
|
2878
2956
|
|
|
2879
|
-
|
|
2880
|
-
|
|
2957
|
+
case INPUT.MULT_FINGER:
|
|
2958
|
+
|
|
2959
|
+
if ( this._touchCurrent.length == 0 ) {
|
|
2960
|
+
|
|
2961
|
+
window.removeEventListener( 'pointermove', this._onPointerMove );
|
|
2962
|
+
window.removeEventListener( 'pointerup', this._onPointerUp );
|
|
2963
|
+
|
|
2964
|
+
//multCancel
|
|
2965
|
+
this._input = INPUT.NONE;
|
|
2966
|
+
this.onTriplePanEnd();
|
|
2967
|
+
|
|
2968
|
+
}
|
|
2881
2969
|
|
|
2882
|
-
|
|
2970
|
+
break;
|
|
2883
2971
|
|
|
2884
|
-
|
|
2972
|
+
}
|
|
2885
2973
|
|
|
2886
|
-
|
|
2974
|
+
} else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
|
|
2887
2975
|
|
|
2888
|
-
|
|
2889
|
-
|
|
2976
|
+
window.removeEventListener( 'pointermove', this._onPointerMove );
|
|
2977
|
+
window.removeEventListener( 'pointerup', this._onPointerUp );
|
|
2890
2978
|
|
|
2891
|
-
|
|
2892
|
-
|
|
2979
|
+
this._input = INPUT.NONE;
|
|
2980
|
+
this.onSinglePanEnd();
|
|
2981
|
+
this._button = - 1;
|
|
2893
2982
|
|
|
2894
|
-
|
|
2895
|
-
const cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
|
|
2896
|
-
const radius2 = Math.pow( tbRadius, 2 );
|
|
2983
|
+
}
|
|
2897
2984
|
|
|
2898
|
-
|
|
2899
|
-
// |\
|
|
2900
|
-
// | \
|
|
2901
|
-
// | \
|
|
2902
|
-
// h | \
|
|
2903
|
-
// | \
|
|
2904
|
-
// | \
|
|
2905
|
-
// _ _ | _ _ _\ _ _ near plane
|
|
2906
|
-
// l
|
|
2985
|
+
if ( event.isPrimary ) {
|
|
2907
2986
|
|
|
2908
|
-
|
|
2909
|
-
const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
|
|
2987
|
+
if ( this._downValid ) {
|
|
2910
2988
|
|
|
2911
|
-
|
|
2989
|
+
const downTime = event.timeStamp - this._downEvents[ this._downEvents.length - 1 ].timeStamp;
|
|
2912
2990
|
|
|
2913
|
-
|
|
2914
|
-
rayDir.set( this._v3_1.x, this._v3_1.y, tbRadius );
|
|
2915
|
-
return rayDir;
|
|
2991
|
+
if ( downTime <= this._maxDownTime ) {
|
|
2916
2992
|
|
|
2917
|
-
|
|
2993
|
+
if ( this._nclicks == 0 ) {
|
|
2918
2994
|
|
|
2919
|
-
|
|
2920
|
-
|
|
2995
|
+
//first valid click detected
|
|
2996
|
+
this._nclicks = 1;
|
|
2997
|
+
this._clickStart = performance.now();
|
|
2921
2998
|
|
|
2922
|
-
|
|
2923
|
-
* calculate intersection point between unprojected ray and trackball surface
|
|
2924
|
-
*|y = m * x + q
|
|
2925
|
-
*|x^2 + y^2 = r^2
|
|
2926
|
-
*
|
|
2927
|
-
* (m^2 + 1) * x^2 + (2 * m * q) * x + q^2 - r^2 = 0
|
|
2928
|
-
*/
|
|
2929
|
-
let a = Math.pow( m, 2 ) + 1;
|
|
2930
|
-
let b = 2 * m * q;
|
|
2931
|
-
let c = Math.pow( q, 2 ) - radius2;
|
|
2932
|
-
let delta = Math.pow( b, 2 ) - ( 4 * a * c );
|
|
2999
|
+
} else {
|
|
2933
3000
|
|
|
2934
|
-
|
|
3001
|
+
const clickInterval = event.timeStamp - this._clickStart;
|
|
3002
|
+
const movement = this.calculatePointersDistance( this._downEvents[ 1 ], this._downEvents[ 0 ] ) * this._devPxRatio;
|
|
2935
3003
|
|
|
2936
|
-
|
|
2937
|
-
this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
|
|
2938
|
-
this._v2_1.setY( m * this._v2_1.x + q );
|
|
3004
|
+
if ( clickInterval <= this._maxInterval && movement <= this._posThreshold ) {
|
|
2939
3005
|
|
|
2940
|
-
|
|
3006
|
+
//second valid click detected
|
|
3007
|
+
//fire double tap and reset values
|
|
3008
|
+
this._nclicks = 0;
|
|
3009
|
+
this._downEvents.splice( 0, this._downEvents.length );
|
|
3010
|
+
this.onDoubleTap( event );
|
|
2941
3011
|
|
|
2942
|
-
|
|
3012
|
+
} else {
|
|
2943
3013
|
|
|
2944
|
-
|
|
2945
|
-
|
|
3014
|
+
//new 'first click'
|
|
3015
|
+
this._nclicks = 1;
|
|
3016
|
+
this._downEvents.shift();
|
|
3017
|
+
this._clickStart = performance.now();
|
|
2946
3018
|
|
|
2947
|
-
|
|
2948
|
-
rayDir.multiplyScalar( rayLength );
|
|
2949
|
-
rayDir.z += cameraGizmoDistance;
|
|
2950
|
-
return rayDir;
|
|
3019
|
+
}
|
|
2951
3020
|
|
|
2952
3021
|
}
|
|
2953
3022
|
|
|
2954
|
-
}
|
|
3023
|
+
} else {
|
|
2955
3024
|
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
*|y = (1 / x) * (r^2 / 2)
|
|
2960
|
-
*
|
|
2961
|
-
* m * x^2 + q * x - r^2 / 2 = 0
|
|
2962
|
-
*/
|
|
3025
|
+
this._downValid = false;
|
|
3026
|
+
this._nclicks = 0;
|
|
3027
|
+
this._downEvents.splice( 0, this._downEvents.length );
|
|
2963
3028
|
|
|
2964
|
-
|
|
2965
|
-
b = q;
|
|
2966
|
-
c = - radius2 * 0.5;
|
|
2967
|
-
delta = Math.pow( b, 2 ) - ( 4 * a * c );
|
|
2968
|
-
this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
|
|
2969
|
-
this._v2_1.setY( m * this._v2_1.x + q );
|
|
3029
|
+
}
|
|
2970
3030
|
|
|
2971
|
-
|
|
3031
|
+
} else {
|
|
2972
3032
|
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
return rayDir;
|
|
3033
|
+
this._nclicks = 0;
|
|
3034
|
+
this._downEvents.splice( 0, this._downEvents.length );
|
|
2976
3035
|
|
|
2977
3036
|
}
|
|
2978
3037
|
|
|
2979
|
-
}
|
|
3038
|
+
}
|
|
2980
3039
|
|
|
3040
|
+
}
|
|
2981
3041
|
|
|
2982
|
-
|
|
2983
|
-
* Unproject the cursor on the plane passing through the center of the trackball orthogonal to the camera
|
|
2984
|
-
* @param {Camera} camera The virtual camera
|
|
2985
|
-
* @param {Number} cursorX Cursor horizontal coordinate on screen
|
|
2986
|
-
* @param {Number} cursorY Cursor vertical coordinate on screen
|
|
2987
|
-
* @param {HTMLElement} canvas The canvas where the renderer draws its output
|
|
2988
|
-
* @param {Boolean} initialDistance If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only)
|
|
2989
|
-
* @returns {Vector3} The unprojected point on the trackball plane
|
|
2990
|
-
*/
|
|
2991
|
-
unprojectOnTbPlane = ( camera, cursorX, cursorY, canvas, initialDistance = false ) => {
|
|
3042
|
+
function onWheel( event ) {
|
|
2992
3043
|
|
|
2993
|
-
|
|
3044
|
+
if ( this.enabled && this.enableZoom ) {
|
|
2994
3045
|
|
|
2995
|
-
|
|
2996
|
-
this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
|
|
3046
|
+
let modifier = null;
|
|
2997
3047
|
|
|
2998
|
-
|
|
3048
|
+
if ( event.ctrlKey || event.metaKey ) {
|
|
2999
3049
|
|
|
3000
|
-
|
|
3050
|
+
modifier = 'CTRL';
|
|
3001
3051
|
|
|
3002
|
-
|
|
3052
|
+
} else if ( event.shiftKey ) {
|
|
3003
3053
|
|
|
3004
|
-
|
|
3005
|
-
this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
|
|
3006
|
-
this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
|
|
3054
|
+
modifier = 'SHIFT';
|
|
3007
3055
|
|
|
3008
|
-
|
|
3056
|
+
}
|
|
3009
3057
|
|
|
3010
|
-
|
|
3011
|
-
// |\
|
|
3012
|
-
// | \
|
|
3013
|
-
// | \
|
|
3014
|
-
// h | \
|
|
3015
|
-
// | \
|
|
3016
|
-
// | \
|
|
3017
|
-
// _ _ | _ _ _\ _ _ near plane
|
|
3018
|
-
// l
|
|
3058
|
+
const mouseOp = this.getOpFromAction( 'WHEEL', modifier );
|
|
3019
3059
|
|
|
3020
|
-
|
|
3021
|
-
const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
|
|
3022
|
-
let cameraGizmoDistance;
|
|
3060
|
+
if ( mouseOp != null ) {
|
|
3023
3061
|
|
|
3024
|
-
|
|
3062
|
+
event.preventDefault();
|
|
3063
|
+
this.dispatchEvent( _startEvent );
|
|
3025
3064
|
|
|
3026
|
-
|
|
3065
|
+
const notchDeltaY = 125; //distance of one notch of mouse wheel
|
|
3066
|
+
let sgn = event.deltaY / notchDeltaY;
|
|
3027
3067
|
|
|
3028
|
-
|
|
3068
|
+
let size = 1;
|
|
3029
3069
|
|
|
3030
|
-
|
|
3070
|
+
if ( sgn > 0 ) {
|
|
3031
3071
|
|
|
3032
|
-
|
|
3072
|
+
size = 1 / this.scaleFactor;
|
|
3033
3073
|
|
|
3034
|
-
|
|
3035
|
-
* calculate intersection point between unprojected ray and the plane
|
|
3036
|
-
*|y = mx + q
|
|
3037
|
-
*|y = 0
|
|
3038
|
-
*
|
|
3039
|
-
* x = -q/m
|
|
3040
|
-
*/
|
|
3041
|
-
if ( l == 0 ) {
|
|
3074
|
+
} else if ( sgn < 0 ) {
|
|
3042
3075
|
|
|
3043
|
-
|
|
3044
|
-
rayDir.set( 0, 0, 0 );
|
|
3045
|
-
return rayDir;
|
|
3076
|
+
size = this.scaleFactor;
|
|
3046
3077
|
|
|
3047
3078
|
}
|
|
3048
3079
|
|
|
3049
|
-
|
|
3050
|
-
const q = cameraGizmoDistance;
|
|
3051
|
-
const x = - q / m;
|
|
3080
|
+
switch ( mouseOp ) {
|
|
3052
3081
|
|
|
3053
|
-
|
|
3054
|
-
rayDir.multiplyScalar( rayLength );
|
|
3055
|
-
rayDir.z = 0;
|
|
3056
|
-
return rayDir;
|
|
3082
|
+
case 'ZOOM':
|
|
3057
3083
|
|
|
3058
|
-
|
|
3084
|
+
this.updateTbState( STATE.SCALE, true );
|
|
3059
3085
|
|
|
3060
|
-
|
|
3086
|
+
if ( sgn > 0 ) {
|
|
3061
3087
|
|
|
3062
|
-
|
|
3063
|
-
* Update camera and gizmos state
|
|
3064
|
-
*/
|
|
3065
|
-
updateMatrixState = () => {
|
|
3088
|
+
size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
|
|
3066
3089
|
|
|
3067
|
-
|
|
3068
|
-
this._cameraMatrixState.copy( this.camera.matrix );
|
|
3069
|
-
this._gizmoMatrixState.copy( this._gizmos.matrix );
|
|
3090
|
+
} else if ( sgn < 0 ) {
|
|
3070
3091
|
|
|
3071
|
-
|
|
3092
|
+
size = Math.pow( this.scaleFactor, - sgn );
|
|
3072
3093
|
|
|
3073
|
-
|
|
3074
|
-
this.camera.updateProjectionMatrix();
|
|
3075
|
-
this._zoomState = this.camera.zoom;
|
|
3094
|
+
}
|
|
3076
3095
|
|
|
3077
|
-
|
|
3096
|
+
if ( this.cursorZoom && this.enablePan ) {
|
|
3078
3097
|
|
|
3079
|
-
|
|
3098
|
+
let scalePoint;
|
|
3080
3099
|
|
|
3081
|
-
|
|
3100
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
3082
3101
|
|
|
3083
|
-
|
|
3102
|
+
scalePoint = this.unprojectOnTbPlane( this.camera, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.camera.quaternion ).multiplyScalar( 1 / this.camera.zoom ).add( this._gizmos.position );
|
|
3084
3103
|
|
|
3085
|
-
|
|
3086
|
-
* Update the trackball FSA
|
|
3087
|
-
* @param {STATE} newState New state of the FSA
|
|
3088
|
-
* @param {Boolean} updateMatrices If matriices state should be updated
|
|
3089
|
-
*/
|
|
3090
|
-
updateTbState = ( newState, updateMatrices ) => {
|
|
3104
|
+
} else if ( this.camera.isPerspectiveCamera ) {
|
|
3091
3105
|
|
|
3092
|
-
|
|
3093
|
-
if ( updateMatrices ) {
|
|
3106
|
+
scalePoint = this.unprojectOnTbPlane( this.camera, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.camera.quaternion ).add( this._gizmos.position );
|
|
3094
3107
|
|
|
3095
|
-
|
|
3108
|
+
}
|
|
3096
3109
|
|
|
3097
|
-
|
|
3110
|
+
this.applyTransformMatrix( this.scale( size, scalePoint ) );
|
|
3098
3111
|
|
|
3099
|
-
|
|
3112
|
+
} else {
|
|
3100
3113
|
|
|
3101
|
-
|
|
3114
|
+
this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
|
|
3102
3115
|
|
|
3103
|
-
|
|
3116
|
+
}
|
|
3104
3117
|
|
|
3105
|
-
|
|
3118
|
+
if ( this._grid != null ) {
|
|
3106
3119
|
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
this.makeGizmos( this.target, this._tbRadius );
|
|
3110
|
-
this._currentTarget.copy( this.target );
|
|
3120
|
+
this.disposeGrid();
|
|
3121
|
+
this.drawGrid();
|
|
3111
3122
|
|
|
3112
|
-
|
|
3123
|
+
}
|
|
3113
3124
|
|
|
3114
|
-
|
|
3115
|
-
if ( this.camera.isOrthographicCamera ) {
|
|
3125
|
+
this.updateTbState( STATE.IDLE, false );
|
|
3116
3126
|
|
|
3117
|
-
|
|
3118
|
-
|
|
3127
|
+
this.dispatchEvent( _changeEvent );
|
|
3128
|
+
this.dispatchEvent( _endEvent );
|
|
3119
3129
|
|
|
3120
|
-
|
|
3121
|
-
this.applyTransformMatrix( this.scale( newZoom / this.camera.zoom, this._gizmos.position, true ) );
|
|
3130
|
+
break;
|
|
3122
3131
|
|
|
3123
|
-
|
|
3132
|
+
case 'FOV':
|
|
3124
3133
|
|
|
3125
|
-
|
|
3134
|
+
if ( this.camera.isPerspectiveCamera ) {
|
|
3126
3135
|
|
|
3127
|
-
|
|
3128
|
-
const distance = this.camera.position.distanceTo( this._gizmos.position );
|
|
3136
|
+
this.updateTbState( STATE.FOV, true );
|
|
3129
3137
|
|
|
3130
|
-
if ( distance > this.maxDistance + EPS || distance < this.minDistance - EPS ) {
|
|
3131
3138
|
|
|
3132
|
-
|
|
3133
|
-
this.applyTransformMatrix( this.scale( newDistance / distance, this._gizmos.position ) );
|
|
3134
|
-
this.updateMatrixState();
|
|
3139
|
+
//Vertigo effect
|
|
3135
3140
|
|
|
3136
|
-
|
|
3141
|
+
// fov / 2
|
|
3142
|
+
// |\
|
|
3143
|
+
// | \
|
|
3144
|
+
// | \
|
|
3145
|
+
// x | \
|
|
3146
|
+
// | \
|
|
3147
|
+
// | \
|
|
3148
|
+
// | _ _ _\
|
|
3149
|
+
// y
|
|
3137
3150
|
|
|
3138
|
-
|
|
3139
|
-
|
|
3151
|
+
//check for iOs shift shortcut
|
|
3152
|
+
if ( event.deltaX != 0 ) {
|
|
3140
3153
|
|
|
3141
|
-
|
|
3142
|
-
this.camera.updateProjectionMatrix();
|
|
3154
|
+
sgn = event.deltaX / notchDeltaY;
|
|
3143
3155
|
|
|
3144
|
-
|
|
3156
|
+
size = 1;
|
|
3145
3157
|
|
|
3146
|
-
|
|
3147
|
-
this._tbRadius = this.calculateTbRadius( this.camera );
|
|
3158
|
+
if ( sgn > 0 ) {
|
|
3148
3159
|
|
|
3149
|
-
|
|
3160
|
+
size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
|
|
3150
3161
|
|
|
3151
|
-
|
|
3152
|
-
const newRadius = this._tbRadius / scale;
|
|
3153
|
-
const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
|
|
3154
|
-
const points = curve.getPoints( this._curvePts );
|
|
3155
|
-
const curveGeometry = new BufferGeometry().setFromPoints( points );
|
|
3162
|
+
} else if ( sgn < 0 ) {
|
|
3156
3163
|
|
|
3157
|
-
|
|
3164
|
+
size = Math.pow( this.scaleFactor, - sgn );
|
|
3158
3165
|
|
|
3159
|
-
|
|
3166
|
+
}
|
|
3160
3167
|
|
|
3161
|
-
|
|
3168
|
+
}
|
|
3162
3169
|
|
|
3163
|
-
|
|
3170
|
+
this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
|
|
3171
|
+
const x = this._v3_1.distanceTo( this._gizmos.position );
|
|
3172
|
+
let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
|
|
3164
3173
|
|
|
3165
|
-
|
|
3174
|
+
//check min and max distance
|
|
3175
|
+
xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
|
|
3166
3176
|
|
|
3167
|
-
|
|
3177
|
+
const y = x * Math.tan( MathUtils.DEG2RAD * this.camera.fov * 0.5 );
|
|
3168
3178
|
|
|
3169
|
-
|
|
3179
|
+
//calculate new fov
|
|
3180
|
+
let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
|
|
3170
3181
|
|
|
3171
|
-
|
|
3182
|
+
//check min and max fov
|
|
3183
|
+
if ( newFov > this.maxFov ) {
|
|
3172
3184
|
|
|
3173
|
-
|
|
3185
|
+
newFov = this.maxFov;
|
|
3174
3186
|
|
|
3175
|
-
|
|
3187
|
+
} else if ( newFov < this.minFov ) {
|
|
3176
3188
|
|
|
3177
|
-
|
|
3178
|
-
this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
|
|
3189
|
+
newFov = this.minFov;
|
|
3179
3190
|
|
|
3180
|
-
|
|
3181
|
-
this.camera.near = state.arcballState.cameraNear;
|
|
3182
|
-
this.camera.far = state.arcballState.cameraFar;
|
|
3191
|
+
}
|
|
3183
3192
|
|
|
3184
|
-
|
|
3193
|
+
const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
|
|
3194
|
+
size = x / newDistance;
|
|
3185
3195
|
|
|
3186
|
-
|
|
3196
|
+
this.setFov( newFov );
|
|
3197
|
+
this.applyTransformMatrix( this.scale( size, this._gizmos.position, false ) );
|
|
3187
3198
|
|
|
3188
|
-
|
|
3199
|
+
}
|
|
3189
3200
|
|
|
3190
|
-
|
|
3201
|
+
if ( this._grid != null ) {
|
|
3191
3202
|
|
|
3192
|
-
|
|
3193
|
-
|
|
3203
|
+
this.disposeGrid();
|
|
3204
|
+
this.drawGrid();
|
|
3194
3205
|
|
|
3195
|
-
|
|
3196
|
-
this.camera.updateProjectionMatrix();
|
|
3206
|
+
}
|
|
3197
3207
|
|
|
3198
|
-
|
|
3208
|
+
this.updateTbState( STATE.IDLE, false );
|
|
3199
3209
|
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
this.makeGizmos( this._gizmos.position, this._tbRadius );
|
|
3203
|
-
this._gizmoMatrixState0.copy( gizmoTmp );
|
|
3210
|
+
this.dispatchEvent( _changeEvent );
|
|
3211
|
+
this.dispatchEvent( _endEvent );
|
|
3204
3212
|
|
|
3205
|
-
|
|
3206
|
-
this.updateTbState( STATE.IDLE, false );
|
|
3213
|
+
break;
|
|
3207
3214
|
|
|
3208
|
-
|
|
3215
|
+
}
|
|
3209
3216
|
|
|
3210
3217
|
}
|
|
3211
3218
|
|
|
3212
|
-
}
|
|
3219
|
+
}
|
|
3213
3220
|
|
|
3214
3221
|
}
|
|
3215
3222
|
|