|
@@ -14,536 +14,99 @@
|
|
|
*/
|
|
|
|
|
|
import * as THREE from "../../libs/three.js/build/three.module.js";
|
|
|
-import {Buttons} from "../defines.js";
|
|
|
-import {Utils} from "../utils.js";
|
|
|
-import cameraLight from "../utils/cameraLight.js";
|
|
|
-import Common from "../utils/Common.js";
|
|
|
+import {MOUSE} from "../defines.js";
|
|
|
+import {Utils} from "../utils.js";
|
|
|
import {EventDispatcher} from "../EventDispatcher.js";
|
|
|
|
|
|
+
|
|
|
export class FirstPersonControls extends EventDispatcher {
|
|
|
- constructor (viewer, viewport) {
|
|
|
+ constructor (viewer) {
|
|
|
super();
|
|
|
-
|
|
|
+
|
|
|
this.viewer = viewer;
|
|
|
this.renderer = viewer.renderer;
|
|
|
|
|
|
- this.scene = viewer.scene;
|
|
|
-
|
|
|
+ this.scene = null;
|
|
|
+ this.sceneControls = new THREE.Scene();
|
|
|
|
|
|
this.rotationSpeed = 200;
|
|
|
this.moveSpeed = 10;
|
|
|
-
|
|
|
-
|
|
|
- this.setCurrentViewport({hoverViewport:viewport, force:true}) //this.currentViewport = viewport
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- this.keys = {
|
|
|
- FORWARD: ['W'.charCodeAt(0), 38],
|
|
|
- BACKWARD: ['S'.charCodeAt(0), 40],
|
|
|
- LEFT: ['A'.charCodeAt(0), 37],
|
|
|
- RIGHT: ['D'.charCodeAt(0), 39],
|
|
|
- UP: ['Q'.charCodeAt(0)],
|
|
|
- DOWN: ['E'.charCodeAt(0)],
|
|
|
-
|
|
|
- //SHIFT : [16],
|
|
|
- ALT : [18],
|
|
|
-
|
|
|
+ this.lockElevation = false;
|
|
|
|
|
|
- Rotate_LEFT : ['L'.charCodeAt(0)],
|
|
|
- Rotate_RIGHT : ['J'.charCodeAt(0)],
|
|
|
- Rotate_UP : ['K'.charCodeAt(0)],
|
|
|
- Rotate_DOWN : ['I'.charCodeAt(0)],
|
|
|
-
|
|
|
- };
|
|
|
+ this.keys = {
|
|
|
+ FORWARD: ['W'.charCodeAt(0), 38],
|
|
|
+ BACKWARD: ['S'.charCodeAt(0), 40],
|
|
|
+ LEFT: ['A'.charCodeAt(0), 37],
|
|
|
+ RIGHT: ['D'.charCodeAt(0), 39],
|
|
|
+ UP: ['R'.charCodeAt(0), 33],
|
|
|
+ DOWN: ['F'.charCodeAt(0), 34]
|
|
|
+ };
|
|
|
|
|
|
- this.fadeFactor = 20;
|
|
|
+ this.fadeFactor = 50;
|
|
|
this.yawDelta = 0;
|
|
|
this.pitchDelta = 0;
|
|
|
this.translationDelta = new THREE.Vector3(0, 0, 0);
|
|
|
this.translationWorldDelta = new THREE.Vector3(0, 0, 0);
|
|
|
|
|
|
this.tweens = [];
|
|
|
- this.dollyStart = new THREE.Vector2
|
|
|
- this.dollyEnd = new THREE.Vector2
|
|
|
- //this.enableChangePos = true
|
|
|
-
|
|
|
- this.viewer.addEventListener('camera_changed',(e)=>{
|
|
|
- this.setFPCMoveSpeed(e.viewport)
|
|
|
- })
|
|
|
-
|
|
|
|
|
|
let drag = (e) => {
|
|
|
- if(!this.enabled)return
|
|
|
- let viewport = e.dragViewport;
|
|
|
- if(!viewport)return
|
|
|
- let camera = viewport.camera
|
|
|
- let mode
|
|
|
- if(e.isTouch){
|
|
|
- if(e.touches.length == 1){
|
|
|
- mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
|
|
|
- }else if(e.touches.length == 2){
|
|
|
- mode = 'scale'
|
|
|
- }else{
|
|
|
- mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale'
|
|
|
- }
|
|
|
- }else{
|
|
|
- //mode = e.buttons === Buttons.LEFT && (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
|
|
|
- mode = e.buttons === Buttons.LEFT && camera.type != 'OrthographicCamera' ? 'rotate' : 'pan'
|
|
|
- }
|
|
|
- //console.log('mode ', mode )
|
|
|
- let moveSpeed = this.currentViewport.getMoveSpeed();
|
|
|
- if (e.drag.startHandled === undefined) {///???????
|
|
|
+ if (e.drag.object !== null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (e.drag.startHandled === undefined) {
|
|
|
e.drag.startHandled = true;
|
|
|
|
|
|
this.dispatchEvent({type: 'start'});
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- if (mode.includes('rotate')) {//旋转
|
|
|
-
|
|
|
- //来自panoramaControl updateRotation
|
|
|
- if(!this.pointerDragStart){
|
|
|
- return this.pointerDragStart = e.pointer.clone()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- let view = this.scene.view;
|
|
|
- if(Potree.settings.rotAroundPoint && this.intersectStart && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[17]){//定点旋转: 以当前intersect的点为target旋转,不改点在屏幕中的位置
|
|
|
- let distance = camera.position.distanceTo(this.intersectStart.location) //不按下ctrl的话
|
|
|
-
|
|
|
- //按照orbitControl的方式旋转:
|
|
|
- let rotationSpeed = 2.5;
|
|
|
-
|
|
|
- this.yawDelta -= e.drag.pointerDelta.x * rotationSpeed;
|
|
|
- this.pitchDelta += e.drag.pointerDelta.y * rotationSpeed;
|
|
|
-
|
|
|
-
|
|
|
- //先更新一下相机:
|
|
|
- this.update()
|
|
|
- view.applyToCamera(camera)
|
|
|
-
|
|
|
- //然后得到新的相机角度下,原先点在屏幕中的位置所对应的3d点现在的坐标。只需要平移一下新旧坐标差值即可。
|
|
|
- let newPointerDir = viewer.inputHandler.getMouseDirection(this.intersectStart.pointer).direction.clone().multiplyScalar(distance)
|
|
|
- let pivot = new THREE.Vector3().addVectors(camera.position, newPointerDir) //新的3d点
|
|
|
-
|
|
|
- let moveVec = new THREE.Vector3().subVectors(pivot, this.intersectStart.location)
|
|
|
-
|
|
|
- this.translationWorldDelta.copy(moveVec.negate())
|
|
|
- //立即更新下,防止因update和此drag频率不同而打滑。
|
|
|
- this.update()
|
|
|
- view.applyToCamera(camera)
|
|
|
-
|
|
|
-
|
|
|
- }else{
|
|
|
-
|
|
|
-
|
|
|
- let _matrixWorld = camera.matrixWorld
|
|
|
- camera.matrixWorld = new THREE.Matrix4;//unproject 前先把相机置于原点
|
|
|
-
|
|
|
- var e1 = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y,-1).unproject(camera)
|
|
|
- , t = new THREE.Vector3(e.pointer.x,e.pointer.y,-1).unproject(camera)
|
|
|
- , i = Math.sqrt(e1.x * e1.x + e1.z * e1.z)
|
|
|
- , n = Math.sqrt(t.x * t.x + t.z * t.z)
|
|
|
- , o = Math.atan2(e1.y, i)
|
|
|
- , a = Math.atan2(t.y, n);
|
|
|
-
|
|
|
- this.pitchDelta += o - a //上下旋转
|
|
|
- e1.y = 0,
|
|
|
- t.y = 0;
|
|
|
-
|
|
|
- var s = Math.acos(e1.dot(t) / e1.length() / t.length());
|
|
|
-
|
|
|
- if(!isNaN(s)){
|
|
|
- var yawDelta = s //左右旋转
|
|
|
- this.pointerDragStart.x > e.pointer.x && (yawDelta *= -1)
|
|
|
- this.yawDelta += yawDelta
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- //console.log('rotate:', this.pitchDelta, e.pointer.toArray(), this.pointerDragStart.toArray())
|
|
|
-
|
|
|
-
|
|
|
- this.pointerDragStart.copy(e.pointer)
|
|
|
-
|
|
|
- camera.matrixWorld = _matrixWorld ;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (mode.includes('pan')) {//平移
|
|
|
- if(!this.canMovePos(viewport)){
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if(camera.type == "OrthographicCamera"){
|
|
|
-
|
|
|
- //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
|
|
|
- let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )//最近一次移动向量
|
|
|
-
|
|
|
- let pointclouds;
|
|
|
- let Alignment = window.viewer.modules.Alignment
|
|
|
- let MergeEditor = window.viewer.modules.MergeEditor
|
|
|
- let handleState = Alignment.handleState
|
|
|
-
|
|
|
- let a = e.buttons === Buttons.LEFT && viewport.alignment && handleState && viewport.alignment[handleState]
|
|
|
- if(Potree.settings.editType == 'pano'){//右键平移视图、左键操作点云
|
|
|
- let PanoEditor = window.viewer.modules.PanoEditor
|
|
|
-
|
|
|
- if(a && PanoEditor.selectedPano){
|
|
|
- if(!PanoEditor.selectedGroup || !PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
|
|
|
- if(handleState == 'translate' && ( e.drag.intersectStart.pointclouds && Common.getMixedSet(PanoEditor.selectedClouds, e.drag.intersectStart.pointclouds).length || PanoEditor.selectedPano.hovered)//拖拽到点云上 或 circle
|
|
|
- || handleState == 'rotate' )
|
|
|
- {
|
|
|
- pointclouds = PanoEditor.selectedClouds
|
|
|
- }
|
|
|
- }else{
|
|
|
- PanoEditor.dispatchEvent('needToDisConnect')
|
|
|
- console.warn('选中的漫游点连通了整个数据集,不允许移动')
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){
|
|
|
- return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
|
|
|
- }
|
|
|
- }else if(Potree.settings.editType == 'merge'){
|
|
|
- if(e.buttons === Buttons.LEFT && viewport.rotateSide){
|
|
|
- return MergeEditor.rotateSideCamera(-e.drag.pointerDelta.x)
|
|
|
- }
|
|
|
-
|
|
|
- }else{
|
|
|
- /* if(Alignment.selectedClouds && Alignment.selectedClouds.length){
|
|
|
- pointclouds = a && e.drag.intersectStart.pointclouds && Common.getMixedSet(Alignment.selectedClouds, e.drag.intersectStart.pointclouds).length && Alignment.selectedClouds
|
|
|
-
|
|
|
- }else{ */
|
|
|
- pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud]
|
|
|
- //}
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if(pointclouds){
|
|
|
- this.dispatchEvent({
|
|
|
- type : "transformPointcloud",
|
|
|
- intersect: e.intersect.orthoIntersect,
|
|
|
- intersectStart: e.drag.intersectStart.orthoIntersect,
|
|
|
- moveVec,
|
|
|
- pointclouds,
|
|
|
- camera
|
|
|
- })
|
|
|
- }else{
|
|
|
-
|
|
|
- this.translationWorldDelta.add(moveVec.negate())
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }else{
|
|
|
- if(e.drag.intersectStart){//如果拖拽着点云
|
|
|
-
|
|
|
- if(e.drag.z == void 0){//拖拽开始
|
|
|
- let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
|
|
|
- e.drag.z = pointerStartPos2d.z //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变
|
|
|
- e.drag.projectionMatrixInverse = camera.projectionMatrixInverse.clone()
|
|
|
- //防止吸附到最近点上(因为鼠标所在位置并非识别到的点云点的位置,需要得到鼠标所在位置的3d坐标。)
|
|
|
- let pointerStartPos2dReal = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y, e.drag.z);
|
|
|
- e.drag.translateStartPos = pointerStartPos2dReal.clone().unproject(camera);
|
|
|
- /* this.viewer.dispatchEvent({
|
|
|
- type: 'dragPanBegin',
|
|
|
- projectionMatrixInverse : e.drag.projectionMatrixInverse
|
|
|
- }); */
|
|
|
- //console.log('开始拖拽', e.pointer.clone())
|
|
|
- }
|
|
|
- //拖拽的过程中将projectionMatrixInverse替换成开始拖拽时的,因为near、far一直在变,会导致unproject计算出的3d坐标改变很大而闪烁。
|
|
|
- var _projectionMatrixInverse = camera.projectionMatrixInverse;
|
|
|
- camera.projectionMatrixInverse = e.drag.projectionMatrixInverse;
|
|
|
-
|
|
|
-
|
|
|
- let newPos2d = new THREE.Vector3(e.pointer.x,e.pointer.y, e.drag.z );
|
|
|
- let newPos3d = newPos2d.clone().unproject(camera);
|
|
|
- let moveVec = newPos3d.clone().sub( e.drag.translateStartPos /* e.drag.intersectStart.location */ );//移动相机,保持鼠标下的位置永远不变,所以用鼠标下的新位置减去鼠标下的原始位置
|
|
|
-
|
|
|
-
|
|
|
- camera.projectionMatrixInverse = _projectionMatrixInverse
|
|
|
- this.translationWorldDelta.copy(moveVec.negate()) //这里没法用add,原因未知,会跳动
|
|
|
- //console.log('pan 1', this.translationWorldDelta.clone())
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- //四指松开剩三指时会偏移一下,暂不知道哪里的问题,或许跟开头防止点云吸附有关?
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }else{ //如果鼠标没有找到和点云的交点,就假设移动整个模型(也可以去扩大范围寻找最近点云)
|
|
|
-
|
|
|
- /* let center = viewer.scene.pointclouds[0].position;
|
|
|
- let radius = camera.position.distanceTo(center);
|
|
|
- let ratio = radius * Math.tan(THREE.Math.degToRad(camera.fov)/2) / 1000 */
|
|
|
-
|
|
|
-
|
|
|
- /* let speed = this.currentViewport.getMoveSpeed()
|
|
|
- if(FirstPersonControls.boundPlane){
|
|
|
- speed = FirstPersonControls.boundPlane.distanceToPoint(this.currentViewport.position)
|
|
|
- speed = Math.max(1 , speed)
|
|
|
- } */
|
|
|
- let lastIntersect = viewport.lastIntersect ? (viewport.lastIntersect.location || viewport.lastIntersect) : viewer.bound.center //该viewport的最近一次鼠标和点云的交点
|
|
|
- let speed = camera.position.distanceTo(lastIntersect)
|
|
|
- let fov = cameraLight.getHFOVForCamera(camera, true)
|
|
|
- let ratio = speed * Math.tan(fov/2)
|
|
|
- this.translationDelta.x -= e.drag.pointerDelta.x * ratio
|
|
|
- this.translationDelta.z -= e.drag.pointerDelta.y * ratio
|
|
|
- //console.log('pan2', e.drag.pointerDelta)
|
|
|
- }
|
|
|
- }
|
|
|
- this.useAttenuation = false
|
|
|
+
|
|
|
+ let moveSpeed = this.viewer.getMoveSpeed();
|
|
|
+
|
|
|
+ let ndrag = {
|
|
|
+ x: e.drag.lastDrag.x / this.renderer.domElement.clientWidth,
|
|
|
+ y: e.drag.lastDrag.y / this.renderer.domElement.clientHeight
|
|
|
+ };
|
|
|
+
|
|
|
+ if (e.drag.mouse === MOUSE.LEFT) {
|
|
|
+ this.yawDelta += ndrag.x * this.rotationSpeed;
|
|
|
+ this.pitchDelta += ndrag.y * this.rotationSpeed;
|
|
|
+ } else if (e.drag.mouse === MOUSE.RIGHT) {
|
|
|
+ this.translationDelta.x -= ndrag.x * moveSpeed * 100;
|
|
|
+ this.translationDelta.z += ndrag.y * moveSpeed * 100;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- if(mode.includes('scale')){
|
|
|
-
|
|
|
- this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
|
|
|
- //if(!this.dollyStart)return
|
|
|
- var scale = this.dollyEnd.length() / this.dollyStart.length()
|
|
|
-
|
|
|
- //console.log('scale ',scale)
|
|
|
-
|
|
|
- let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
|
|
|
-
|
|
|
- dolly({
|
|
|
- pointer,
|
|
|
- scale, camera
|
|
|
- })
|
|
|
- this.dollyStart.copy(this.dollyEnd);
|
|
|
-
|
|
|
- }
|
|
|
- //最好按ctrl可以变为dollhouse的那种旋转
|
|
|
};
|
|
|
|
|
|
let drop = e => {
|
|
|
- if(!this.enabled)return
|
|
|
this.dispatchEvent({type: 'end'});
|
|
|
-
|
|
|
};
|
|
|
|
|
|
+ let scroll = (e) => {
|
|
|
+ let speed = this.viewer.getMoveSpeed();
|
|
|
|
|
|
- let dolly = (e={})=>{
|
|
|
-
|
|
|
- if(Potree.settings.displayMode == 'showPanos' && this.currentViewport == viewer.mainViewport/* this.currentViewport.unableChangePos */){//全景时
|
|
|
- this.dispatchEvent({type:'dollyStopCauseUnable',delta:e.delta, scale:e.scale})
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- let camera = e.camera
|
|
|
-
|
|
|
-
|
|
|
- if(camera.type == "OrthographicCamera"){
|
|
|
- let ratio
|
|
|
- if(e.delta != void 0){//滚轮缩放
|
|
|
- if(e.delta == 0){//mac
|
|
|
- return
|
|
|
- }else if (e.delta < 0) {
|
|
|
- ratio = 0.9
|
|
|
- } else if (e.delta > 0) {
|
|
|
- ratio = 1.1
|
|
|
- }
|
|
|
- }else{
|
|
|
- ratio = e.scale //触屏缩放
|
|
|
- }
|
|
|
-
|
|
|
- let zoom = camera.zoom * ratio
|
|
|
- let limit = camera.zoomLimit
|
|
|
- if(limit) zoom = THREE.Math.clamp(zoom, limit.min,limit.max )
|
|
|
-
|
|
|
-
|
|
|
- let pointerPos = new THREE.Vector3(e.pointer.x, e.pointer.y,0.5);
|
|
|
- let oldPos = pointerPos.clone().unproject(camera);
|
|
|
-
|
|
|
- if(camera.zoom != zoom){
|
|
|
- camera.zoom = zoom
|
|
|
- camera.updateProjectionMatrix()
|
|
|
- }
|
|
|
- let newPos = pointerPos.clone().unproject(camera);
|
|
|
-
|
|
|
- //定点缩放, 恢复一下鼠标所在位置的位置改变量
|
|
|
- let moveVec = new THREE.Vector3().subVectors(newPos,oldPos)
|
|
|
- this.translationWorldDelta.add(moveVec.negate())
|
|
|
- this.useAttenuation = false
|
|
|
- }else{
|
|
|
- let speed , direction
|
|
|
-
|
|
|
-
|
|
|
- if(e.delta != void 0){//滚轮缩放
|
|
|
- speed = this.currentViewport.getMoveSpeed() * 15
|
|
|
-
|
|
|
- //var direction = this.currentViewport.view.direction.clone();
|
|
|
- direction = this.viewer.inputHandler.getMouseDirection().direction //定点缩放
|
|
|
-
|
|
|
-
|
|
|
- if(e.delta == 0){//mac
|
|
|
- return
|
|
|
- }else if (e.delta < 0) {
|
|
|
- speed *= -1
|
|
|
- }
|
|
|
- }else{
|
|
|
- const constantDis = this.currentViewport.getMoveSpeed() * 200 //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
|
|
|
- speed = (e.scale-1)*constantDis //触屏缩放
|
|
|
- //pointer = new THREE.Vector2().addVectors().multiplyScalar(0.5);//两个指头的中心点
|
|
|
- direction = this.viewer.inputHandler.getMouseDirection(e.pointer).direction //定点缩放
|
|
|
- }
|
|
|
-
|
|
|
- this.useAttenuation = true
|
|
|
- var vec = direction.multiplyScalar(speed )
|
|
|
- this.translationWorldDelta.copy(vec)
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
+ if (e.delta < 0) {
|
|
|
+ speed = speed * 0.9;
|
|
|
+ } else if (e.delta > 0) {
|
|
|
+ speed = speed / 0.9;
|
|
|
+ }
|
|
|
|
|
|
- let scroll = (e) => {
|
|
|
- if(!this.enabled || !e.hoverViewport)return
|
|
|
- this.setCurrentViewport(e)
|
|
|
-
|
|
|
-
|
|
|
- e.camera = e.hoverViewport.camera
|
|
|
- dolly(e)
|
|
|
+ speed = Math.max(speed, 0.1);
|
|
|
+
|
|
|
+ this.viewer.setMoveSpeed(speed);
|
|
|
};
|
|
|
|
|
|
- let dblclick = (e) => {
|
|
|
- if(!this.enabled)return
|
|
|
-
|
|
|
- if(!Potree.settings.dblToFocusPoint)return;//调试时才可双击
|
|
|
-
|
|
|
- if(Potree.settings.displayMode == 'showPointCloud'/* !viewer.images360.isAtPano() */) this.zoomToLocation(e.mouse);
|
|
|
+ let dblclick = (e) => {
|
|
|
+ this.zoomToLocation(e.mouse);
|
|
|
};
|
|
|
|
|
|
- this.viewer.addEventListener('global_drag', drag);
|
|
|
- /* this.viewer.addEventListener('global_touchmove', (e)=>{
|
|
|
- if(!this.enabled)return
|
|
|
- if(e.touches.length>1){//单指的就触发上一句
|
|
|
- //console.log('global_touchmove' )
|
|
|
- drag(e)
|
|
|
- }
|
|
|
- }); */
|
|
|
- this.viewer.addEventListener('global_drop', drop);
|
|
|
- this.viewer.addEventListener('global_mousewheel', scroll);
|
|
|
- this.viewer.addEventListener('global_dblclick', dblclick);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- let prepareScale = (e)=>{//触屏的scale
|
|
|
- this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
|
|
|
- }
|
|
|
- let prepareRotate = (e)=>{
|
|
|
- this.pointerDragStart = e.pointer.clone()
|
|
|
- this.intersectStart = e.intersect && e.intersect.location && {
|
|
|
- location : e.intersect.location,
|
|
|
- pointer : e.intersect.location.clone().project(e.dragViewport.camera) //intersect点在屏幕中的位置
|
|
|
- }
|
|
|
- //console.log('prepareRotate' )
|
|
|
- }
|
|
|
- let preparePan = (e)=>{//触屏的pan点云 还是会偏移
|
|
|
- this.pointerDragStart = e.pointer.clone()
|
|
|
-
|
|
|
- e.drag.z = void 0 //清空
|
|
|
- drag(e) //触屏点击时更新的pointer直接用一次drag
|
|
|
- //console.log('preparePan ' )
|
|
|
- }
|
|
|
-
|
|
|
- this.viewer.addEventListener('global_mousedown'/* 'startDragging' */, (e)=>{
|
|
|
- if(!this.enabled)return
|
|
|
- this.setCurrentViewport(e)
|
|
|
- prepareRotate(e)
|
|
|
- })
|
|
|
-
|
|
|
-
|
|
|
- //注意,每次增减指头都会修改pointer,需要更新下状态
|
|
|
- this.viewer.addEventListener('global_touchstart', (e)=>{
|
|
|
- if(!this.enabled)return
|
|
|
-
|
|
|
- if(e.touches.length==2){//只监听开头两个指头
|
|
|
- prepareScale(e)
|
|
|
- }else if(e.touches.length>=3){
|
|
|
- preparePan(e)
|
|
|
- }
|
|
|
- })
|
|
|
- this.viewer.addEventListener('global_touchend', (e)=>{
|
|
|
- if(!this.enabled)return
|
|
|
- if(e.touches.length==2){//停止平移,开始scale
|
|
|
- prepareScale(e)
|
|
|
- }else if(e.touches.length==1){//停止scale,开始rotate
|
|
|
- prepareRotate(e)
|
|
|
- }else if(e.touches.length>=3){//重新准备下平移(因为抬起的指头可能包含平移使用的数据),否则抬起时漂移
|
|
|
- preparePan(e)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- /* this.viewer.addEventListener('enableChangePos', (e)=>{
|
|
|
- if(!this.enabled)return
|
|
|
- this.enableChangePos = e.canLeavePano
|
|
|
- }) */
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ this.addEventListener('drag', drag);
|
|
|
+ this.addEventListener('drop', drop);
|
|
|
+ this.addEventListener('mousewheel', scroll);
|
|
|
+ this.addEventListener('dblclick', dblclick);
|
|
|
}
|
|
|
- canMovePos(viewport){
|
|
|
- if(viewport == viewer.mainViewport && (Potree.settings.displayMode == 'showPanos'
|
|
|
- || viewer.images360.bumping || viewer.images360.latestToPano))return false
|
|
|
- else return true
|
|
|
- }
|
|
|
- setEnable(enabled){
|
|
|
- this.enabled = enabled;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- setFPCMoveSpeed(viewport){
|
|
|
- if(viewport.camera.type == 'OrthographicCamera'){
|
|
|
- let s = 1 / viewport.camera.zoom
|
|
|
- viewport.setMoveSpeed(s)
|
|
|
-
|
|
|
- }else{
|
|
|
- if(viewport == viewer.mainViewport && FirstPersonControls.boundPlane){
|
|
|
- let s = FirstPersonControls.boundPlane.distanceToPoint(viewer.mainViewport.view.position)
|
|
|
- s = Math.sqrt(s) / 10;
|
|
|
- s = Math.max(FirstPersonControls.standardSpeed , s)
|
|
|
- s *= Potree.config.moveSpeedAdujust;
|
|
|
- viewer.setMoveSpeed(s)
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- setCurrentViewport(o={}){//add
|
|
|
- if(!this.enabled && !o.force )return
|
|
|
- if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
|
|
|
- this.currentViewport = o.hoverViewport
|
|
|
- //this.viewer.setMoveSpeed(this.currentViewport.radius/100);
|
|
|
- this.setFPCMoveSpeed(this.currentViewport)
|
|
|
- }
|
|
|
- if(this.currentViewport.camera.type == 'OrthographicCamera'){
|
|
|
- this.lockElevationOri = true
|
|
|
- this.lockRotation = true
|
|
|
- }else{
|
|
|
- this.lockElevationOri = false
|
|
|
- this.lockRotation = false
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
|
|
|
setScene (scene) {
|
|
|
this.scene = scene;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
stop(){
|
|
@@ -551,20 +114,17 @@ export class FirstPersonControls extends EventDispatcher {
|
|
|
this.pitchDelta = 0;
|
|
|
this.translationDelta.set(0, 0, 0);
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
|
|
|
zoomToLocation(mouse){
|
|
|
- if(!this.enabled)return
|
|
|
let camera = this.scene.getActiveCamera();
|
|
|
|
|
|
- /* let I = Utils.getMousePointCloudIntersection(
|
|
|
+ let I = Utils.getMousePointCloudIntersection(
|
|
|
mouse,
|
|
|
camera,
|
|
|
this.viewer,
|
|
|
- this.scene.pointclouds); */
|
|
|
- var I = this.viewer.inputHandler.intersect
|
|
|
- if (!I) {
|
|
|
+ this.scene.pointclouds);
|
|
|
+
|
|
|
+ if (I === null) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -573,17 +133,9 @@ export class FirstPersonControls extends EventDispatcher {
|
|
|
let minimumJumpDistance = 0.2;
|
|
|
|
|
|
let domElement = this.renderer.domElement;
|
|
|
-
|
|
|
- let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer, camera);
|
|
|
- let {origin, direction} = this.viewer.inputHandler.getMouseDirection()
|
|
|
- let raycaster = new THREE.Raycaster();
|
|
|
- raycaster.ray.set(origin, direction);
|
|
|
-
|
|
|
+ let ray = Utils.mouseToRay(mouse, camera, domElement.clientWidth, domElement.clientHeight);
|
|
|
+
|
|
|
let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
|
|
|
-
|
|
|
- let nodes2 = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, raycaster.ray);
|
|
|
-
|
|
|
-
|
|
|
let lastNode = nodes[nodes.length - 1];
|
|
|
let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
|
|
|
targetRadius = Math.min(this.scene.view.radius, radius);
|
|
@@ -626,11 +178,8 @@ export class FirstPersonControls extends EventDispatcher {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- update (delta=1) {
|
|
|
- if(!this.enabled)return
|
|
|
-
|
|
|
- //console.log('update')
|
|
|
- let view = this.currentViewport.view
|
|
|
+ update (delta) {
|
|
|
+ let view = this.scene.view;
|
|
|
|
|
|
{ // cancel move animations on user input
|
|
|
let changes = [ this.yawDelta,
|
|
@@ -653,142 +202,81 @@ export class FirstPersonControls extends EventDispatcher {
|
|
|
let moveRight = this.keys.RIGHT.some(e => ih.pressedKeys[e]);
|
|
|
let moveUp = this.keys.UP.some(e => ih.pressedKeys[e]);
|
|
|
let moveDown = this.keys.DOWN.some(e => ih.pressedKeys[e]);
|
|
|
-
|
|
|
- let rotateLeft = this.keys.Rotate_LEFT.some(e => ih.pressedKeys[e]);
|
|
|
- let rotateRight = this.keys.Rotate_RIGHT.some(e => ih.pressedKeys[e]);
|
|
|
- let rotateUp = this.keys.Rotate_UP.some(e => ih.pressedKeys[e]);
|
|
|
- let rotateDown = this.keys.Rotate_DOWN.some(e => ih.pressedKeys[e]);
|
|
|
-
|
|
|
-
|
|
|
- this.lockElevation = this.lockElevationOri || this.keys.ALT.some(e => ih.pressedKeys[e]);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(!this.lockRotation){
|
|
|
- if(rotateLeft){
|
|
|
- this.yawDelta -= 0.01
|
|
|
- }else if(rotateRight){
|
|
|
- this.yawDelta += 0.01
|
|
|
- }
|
|
|
- if(rotateUp){
|
|
|
- this.pitchDelta -= 0.01
|
|
|
- }else if(rotateDown){
|
|
|
- this.pitchDelta += 0.01
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(this.canMovePos(this.currentViewport) && !this.lockKey){
|
|
|
- if(this.lockElevation){
|
|
|
- let dir = view.direction;
|
|
|
- dir.z = 0;
|
|
|
- dir.normalize();
|
|
|
-
|
|
|
- if (moveForward && moveBackward) {
|
|
|
- this.translationWorldDelta.set(0, 0, 0);
|
|
|
- } else if (moveForward) {
|
|
|
- this.translationWorldDelta.copy(dir.multiplyScalar(this.currentViewport.getMoveSpeed()));
|
|
|
- } else if (moveBackward) {
|
|
|
- this.translationWorldDelta.copy(dir.multiplyScalar(-this.currentViewport.getMoveSpeed()));
|
|
|
- }
|
|
|
- }else{
|
|
|
- if (moveForward && moveBackward) {
|
|
|
- this.translationDelta.y = 0;
|
|
|
- } else if (moveForward) {
|
|
|
- this.translationDelta.y = this.currentViewport.getMoveSpeed();
|
|
|
- } else if (moveBackward) {
|
|
|
- this.translationDelta.y = -this.currentViewport.getMoveSpeed();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (moveLeft && moveRight) {
|
|
|
- this.translationDelta.x = 0;
|
|
|
- } else if (moveLeft) {
|
|
|
- this.translationDelta.x = -this.currentViewport.getMoveSpeed();
|
|
|
- } else if (moveRight) {
|
|
|
- this.translationDelta.x = this.currentViewport.getMoveSpeed();
|
|
|
- }
|
|
|
-
|
|
|
- if (moveUp && moveDown) {
|
|
|
- this.translationWorldDelta.z = 0;
|
|
|
- } else if (moveUp) {
|
|
|
- this.translationWorldDelta.z = this.currentViewport.getMoveSpeed();
|
|
|
- } else if (moveDown) {
|
|
|
- this.translationWorldDelta.z = -this.currentViewport.getMoveSpeed();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if(moveUp || moveDown || moveForward || moveBackward){
|
|
|
- this.useAttenuation = false
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
+
|
|
|
+ if(this.lockElevation){
|
|
|
+ let dir = view.direction;
|
|
|
+ dir.z = 0;
|
|
|
+ dir.normalize();
|
|
|
+
|
|
|
+ if (moveForward && moveBackward) {
|
|
|
+ this.translationWorldDelta.set(0, 0, 0);
|
|
|
+ } else if (moveForward) {
|
|
|
+ this.translationWorldDelta.copy(dir.multiplyScalar(this.viewer.getMoveSpeed()));
|
|
|
+ } else if (moveBackward) {
|
|
|
+ this.translationWorldDelta.copy(dir.multiplyScalar(-this.viewer.getMoveSpeed()));
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if (moveForward && moveBackward) {
|
|
|
+ this.translationDelta.y = 0;
|
|
|
+ } else if (moveForward) {
|
|
|
+ this.translationDelta.y = this.viewer.getMoveSpeed();
|
|
|
+ } else if (moveBackward) {
|
|
|
+ this.translationDelta.y = -this.viewer.getMoveSpeed();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (moveLeft && moveRight) {
|
|
|
+ this.translationDelta.x = 0;
|
|
|
+ } else if (moveLeft) {
|
|
|
+ this.translationDelta.x = -this.viewer.getMoveSpeed();
|
|
|
+ } else if (moveRight) {
|
|
|
+ this.translationDelta.x = this.viewer.getMoveSpeed();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (moveUp && moveDown) {
|
|
|
+ this.translationWorldDelta.z = 0;
|
|
|
+ } else if (moveUp) {
|
|
|
+ this.translationWorldDelta.z = this.viewer.getMoveSpeed();
|
|
|
+ } else if (moveDown) {
|
|
|
+ this.translationWorldDelta.z = -this.viewer.getMoveSpeed();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
{ // apply rotation
|
|
|
let yaw = view.yaw;
|
|
|
let pitch = view.pitch;
|
|
|
-
|
|
|
-
|
|
|
- yaw += this.yawDelta /* * delta; */
|
|
|
- pitch += this.pitchDelta/* * delta; */
|
|
|
+
|
|
|
+ yaw -= this.yawDelta * delta;
|
|
|
+ pitch -= this.pitchDelta * delta;
|
|
|
|
|
|
view.yaw = yaw;
|
|
|
view.pitch = pitch;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- this.yawDelta = 0
|
|
|
- this.pitchDelta = 0
|
|
|
}
|
|
|
- if(this.translationWorldDelta.length()>0) {
|
|
|
- // console.log('translationDelta')
|
|
|
- }
|
|
|
|
|
|
{ // apply translation
|
|
|
view.translate(
|
|
|
- this.translationDelta.x, /* * delta, */
|
|
|
- this.translationDelta.y, /* * delta, */
|
|
|
- this.translationDelta.z, /* * delta */
|
|
|
+ this.translationDelta.x * delta,
|
|
|
+ this.translationDelta.y * delta,
|
|
|
+ this.translationDelta.z * delta
|
|
|
);
|
|
|
- this.translationDelta.set(0,0,0)
|
|
|
-
|
|
|
|
|
|
- //if(this.translationWorldDelta.length())console.log(translationWorldDelta)
|
|
|
-
|
|
|
view.translateWorld(
|
|
|
- this.translationWorldDelta.x /* * delta */,
|
|
|
- this.translationWorldDelta.y /* * delta */,
|
|
|
- this.translationWorldDelta.z /* * delta */
|
|
|
+ this.translationWorldDelta.x * delta,
|
|
|
+ this.translationWorldDelta.y * delta,
|
|
|
+ this.translationWorldDelta.z * delta
|
|
|
);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- //this.translationWorldDelta.set(0,0,0)
|
|
|
}
|
|
|
|
|
|
{ // set view target according to speed
|
|
|
- //view.radius = 1 * this.currentViewport.getMoveSpeed();
|
|
|
-
|
|
|
- /* if(viewer.bound) view.radius = view.position.distanceTo(viewer.bound.center)
|
|
|
- let speed = view.radius/100;
|
|
|
- this.viewer.setMoveSpeed(speed); */
|
|
|
- //this.setMoveSpeed()
|
|
|
-
|
|
|
-
|
|
|
+ view.radius = 3 * this.viewer.getMoveSpeed();
|
|
|
}
|
|
|
-
|
|
|
|
|
|
- if(this.useAttenuation){ //只有滚轮缩放时开启
|
|
|
+ { // decelerate over time
|
|
|
let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
|
|
|
-
|
|
|
- /*this.yawDelta *= attenuation;
|
|
|
- this.pitchDelta *= attenuation;
|
|
|
- this.translationDelta.multiplyScalar(attenuation);*/
|
|
|
+ this.yawDelta *= attenuation;
|
|
|
+ this.pitchDelta *= attenuation;
|
|
|
+ this.translationDelta.multiplyScalar(attenuation);
|
|
|
this.translationWorldDelta.multiplyScalar(attenuation);
|
|
|
- }else{
|
|
|
-
|
|
|
- this.translationWorldDelta.set(0,0,0)
|
|
|
-
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
};
|