2013-05-13 50 views
9

我正在使用OrbitControls.js來允許鼠標交互。我在場景中添加了一個按鈕,允許將攝像機「重置」到它處於任何鼠標交互之前的狀態。使用OrbitControls.js重置攝像頭

我試圖挽救camera.position和camera.rotation任何交往前:

 
    camera_initial_position = camera.position; 
    camera_initial_rotation = camera.rotation; 

和之後的「重置」按鈕被按下,初始位置和旋轉設置:

 
    camera.position = camera_initial_position; 
    camera.rotation = camera_initial_rotation; 

如果不使用平底鍋,它可以很好地工作。如果用戶使用鼠標右鍵平移,則上面的代碼不能「重置」攝像頭。

什麼是正確的方法來將攝像機「重置」到之前的狀態?

three.js所修訂爲R58,這是OrbitControls.js:

 

/** 
* @author qiao/https://github.com/qiao 
* @author mrdoob/http://mrdoob.com 
* @author alteredq/http://alteredqualia.com/ 
* @author WestLangley/http://github.com/WestLangley 
*/ 

THREE.OrbitControls = function (object, domElement) { 

    this.object = object; 
    this.domElement = (domElement !== undefined) ? domElement : document; 

    // API 

    this.enabled = true; 

    this.center = new THREE.Vector3(); 

    this.userZoom = true; 
    this.userZoomSpeed = 1.0; 

    this.userRotate = true; 
    this.userRotateSpeed = 1.0; 

    this.userPan = true; 
    this.userPanSpeed = 2.0; 

    this.autoRotate = false; 
    this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 

    this.minPolarAngle = 0; // radians 
    this.maxPolarAngle = Math.PI; // radians 

    this.minDistance = 0; 
    this.maxDistance = Infinity; 

    this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 

    // internals 

    var scope = this; 

    var EPS = 0.000001; 
    var PIXELS_PER_ROUND = 1800; 

    var rotateStart = new THREE.Vector2(); 
    var rotateEnd = new THREE.Vector2(); 
    var rotateDelta = new THREE.Vector2(); 

    var zoomStart = new THREE.Vector2(); 
    var zoomEnd = new THREE.Vector2(); 
    var zoomDelta = new THREE.Vector2(); 

    var phiDelta = 0; 
    var thetaDelta = 0; 
    var scale = 1; 

    var lastPosition = new THREE.Vector3(); 

    var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 }; 
    var state = STATE.NONE; 

    // events 

    var changeEvent = { type: 'change' }; 


    this.rotateLeft = function (angle) { 

     if (angle === undefined) { 

      angle = getAutoRotationAngle(); 

     } 

     thetaDelta -= angle; 

    }; 

    this.rotateRight = function (angle) { 

     if (angle === undefined) { 

      angle = getAutoRotationAngle(); 

     } 

     thetaDelta += angle; 

    }; 

    this.rotateUp = function (angle) { 

     if (angle === undefined) { 

      angle = getAutoRotationAngle(); 

     } 

     phiDelta -= angle; 

    }; 

    this.rotateDown = function (angle) { 

     if (angle === undefined) { 

      angle = getAutoRotationAngle(); 

     } 

     phiDelta += angle; 

    }; 

    this.zoomIn = function (zoomScale) { 

     if (zoomScale === undefined) { 

      zoomScale = getZoomScale(); 

     } 

     scale /= zoomScale; 

    }; 

    this.zoomOut = function (zoomScale) { 

     if (zoomScale === undefined) { 

      zoomScale = getZoomScale(); 

     } 

     scale *= zoomScale; 

    }; 

    this.pan = function (distance) { 

     distance.transformDirection(this.object.matrix); 
     distance.multiplyScalar(scope.userPanSpeed); 

     this.object.position.add(distance); 
     this.center.add(distance); 

    }; 

    this.update = function() { 

     var position = this.object.position; 
     var offset = position.clone().sub(this.center); 

     // angle from z-axis around y-axis 

     var theta = Math.atan2(offset.x, offset.z); 

     // angle from y-axis 

     var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y); 

     if (this.autoRotate) { 

      this.rotateLeft(getAutoRotationAngle()); 

     } 

     theta += thetaDelta; 
     phi += phiDelta; 

     // restrict phi to be between desired limits 
     phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi)); 

     // restrict phi to be betwee EPS and PI-EPS 
     phi = Math.max(EPS, Math.min(Math.PI - EPS, phi)); 

     var radius = offset.length() * scale; 

     // restrict radius to be between desired limits 
     radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius)); 

     offset.x = radius * Math.sin(phi) * Math.sin(theta); 
     offset.y = radius * Math.cos(phi); 
     offset.z = radius * Math.sin(phi) * Math.cos(theta); 

     position.copy(this.center).add(offset); 

     this.object.lookAt(this.center); 

     thetaDelta = 0; 
     phiDelta = 0; 
     scale = 1; 

     if (lastPosition.distanceTo(this.object.position) > 0) { 

      this.dispatchEvent(changeEvent); 

      lastPosition.copy(this.object.position); 

     } 

    }; 


    function getAutoRotationAngle() { 

     return 2 * Math.PI/60/60 * scope.autoRotateSpeed; 

    } 

    function getZoomScale() { 

     return Math.pow(0.95, scope.userZoomSpeed); 

    } 

    function onMouseDown(event) { 

     if (scope.enabled === false) return; 
     if (scope.userRotate === false) return; 

     event.preventDefault(); 

     if (event.button === 0) { 

      state = STATE.ROTATE; 

      rotateStart.set(event.clientX, event.clientY); 

     } else if (event.button === 1) { 

      state = STATE.ZOOM; 

      zoomStart.set(event.clientX, event.clientY); 

     } else if (event.button === 2) { 

      state = STATE.PAN; 

     } 

     document.addEventListener('mousemove', onMouseMove, false); 
     document.addEventListener('mouseup', onMouseUp, false); 

    } 

    function onMouseMove(event) { 

     if (scope.enabled === false) return; 

     event.preventDefault(); 

     if (state === STATE.ROTATE) { 

      rotateEnd.set(event.clientX, event.clientY); 
      rotateDelta.subVectors(rotateEnd, rotateStart); 

      scope.rotateLeft(2 * Math.PI * rotateDelta.x/PIXELS_PER_ROUND * scope.userRotateSpeed); 
      scope.rotateUp(2 * Math.PI * rotateDelta.y/PIXELS_PER_ROUND * scope.userRotateSpeed); 

      rotateStart.copy(rotateEnd); 

     } else if (state === STATE.ZOOM) { 

      zoomEnd.set(event.clientX, event.clientY); 
      zoomDelta.subVectors(zoomEnd, zoomStart); 

      if (zoomDelta.y > 0) { 

       scope.zoomIn(); 

      } else { 

       scope.zoomOut(); 

      } 

      zoomStart.copy(zoomEnd); 

     } else if (state === STATE.PAN) { 

      var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; 
      var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; 

      scope.pan(new THREE.Vector3(- movementX, movementY, 0)); 

     } 

    } 

    function onMouseUp(event) { 

     if (scope.enabled === false) return; 
     if (scope.userRotate === false) return; 

     document.removeEventListener('mousemove', onMouseMove, false); 
     document.removeEventListener('mouseup', onMouseUp, false); 

     state = STATE.NONE; 

    } 

    function onMouseWheel(event) { 

     if (scope.enabled === false) return; 
     if (scope.userZoom === false) return; 

     var delta = 0; 

     if (event.wheelDelta) { // WebKit/Opera/Explorer 9 

      delta = event.wheelDelta; 

     } else if (event.detail) { // Firefox 

      delta = - event.detail; 

     } 

     if (delta > 0) { 

      scope.zoomOut(); 

     } else { 

      scope.zoomIn(); 

     } 

    } 

    function onKeyDown(event) { 

     if (scope.enabled === false) return; 
     if (scope.userPan === false) return; 

     switch (event.keyCode) { 

      case scope.keys.UP: 
       scope.pan(new THREE.Vector3(0, 1, 0)); 
       break; 
      case scope.keys.BOTTOM: 
       scope.pan(new THREE.Vector3(0, - 1, 0)); 
       break; 
      case scope.keys.LEFT: 
       scope.pan(new THREE.Vector3(- 1, 0, 0)); 
       break; 
      case scope.keys.RIGHT: 
       scope.pan(new THREE.Vector3(1, 0, 0)); 
       break; 
     } 

    } 

    this.domElement.addEventListener('contextmenu', function (event) { event.preventDefault(); }, false); 
    this.domElement.addEventListener('mousedown', onMouseDown, false); 
    this.domElement.addEventListener('mousewheel', onMouseWheel, false); 
    this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox 
    this.domElement.addEventListener('keydown', onKeyDown, false); 

}; 

THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype); 

回答

8

潘操作更新向量稱爲this.center,你需要重新設置它,看鍋的方法,

this.center.add(distance); 

也看到這種方法

this.resetCamera = function () { 
     this.object.position.x= camera_initial_position.xPosition; 
     this.object.position.y = camera_initial_position.yPosition; 
     this.object.position.z = camera_initial_position.zPosition; 
     this.center.x= camera_initial_target.x; 
     this.center.y= camera_initial_target.y; 
     this.center.z= camera_initial_target.z; 
    }; 

然後更新方法將k eep相機看着center矢量

5

ah.adel是否正確平移操作將更新相機控制器的中心。因此,如果您需要將攝像機重置/恢復到預定義的攝像機,則還需要設置攝像機控制器中心。

下面的代碼是一個簡單的代碼來存儲攝像機的位置,旋轉和控制中心

var camToSave = {}; 
camToSave.position = camera.position.clone(); 
camToSave.rotation = camera.rotation.clone(); 
camToSave.controlCenter = controls.center.clone(); 

使用此功能後恢復相機。

function restoreCamera(position, rotation, controlCenter){ 
    camera.position.set(position.x, position.y, position.z); 
    camera.rotation.set(rotation.x, rotation.y, rotation.z); 

    controls.center.set(controlCenter.x, controlCenter.y, controlCenter.z); 
    controls.update(); 

    render(); 
} 

調用restoreCamera函數恢復保存的攝像頭。

restoreCamera(camToSave.position, camToSave.rotation, camToSave.controlCenter); 

希望這會使用OrbitControls像這樣的時候,將有助於有這個問題

+0

ISN」它控制。目標? – Tlatis 2017-01-17 18:14:54

+2

'controls.center'在某個點被重命名爲'controls.target' – 2018-02-14 10:01:15

18

誰您可以重設相機的人:

controls.reset(); 

three.js所r.71

+1

謝謝!這是一種優雅的方式。我認爲這是一個新的增加。不適用於R.58左右? – 2015-05-02 04:12:14

+1

它被添加到r.66。 – WestLangley 2015-05-02 05:50:06

+0

['.saveState'](https://threejs.org/docs/index.html#examples/controls/OrbitControls.saveState) 保存控件的當前狀態。這可以稍後使用.reset進行恢復。 – zwcloud 2018-02-01 09:53:37

相關問題