使用 OrbitControls.js 重置相机 [英] Reset camera using OrbitControls.js

查看:31
本文介绍了使用 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 alterq/http://alteredqualia.com/* @author WestLangley/http://github.com/WestLangley*/THREE.OrbitControls = 函数(对象,domElement){this.object = 对象;this.domElement = ( domElement !== undefined ) ?domElement : 文档;//APIthis.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;//当 fps 为 60 时,每轮 30 秒this.minPolarAngle = 0;//弧度this.maxPolarAngle = Math.PI;//弧度this.minDistance = 0;this.maxDistance = 无穷大;this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };//内部结构var 作用域 = this;无功每股收益 = 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();变量 phiDelta = 0;var thetaDelta = 0;无功比例= 1;var lastPosition = new THREE.Vector3();var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 };var state = STATE.NONE;//事件var changeEvent = { type: 'change' };this.rotateLeft = 函数(角度){如果(角度 === 未定义){角度 = getAutoRotationAngle();}thetaDelta -= 角度;};this.rotateRight = 函数(角度){如果(角度 === 未定义){角度 = getAutoRotationAngle();}thetaDelta += 角度;};this.rotateUp = 函数(角度){如果(角度 === 未定义){角度 = getAutoRotationAngle();}phiDelta -= 角度;};this.rotateDown = 函数(角度){如果(角度 === 未定义){角度 = getAutoRotationAngle();}phiDelta += 角度;};this.zoomIn = 函数(缩放比例){如果(缩放比例 === 未定义){zoomScale = getZoomScale();}比例/= 缩放比例;};this.zoomOut = 函数(缩放比例){如果(缩放比例 === 未定义){zoomScale = getZoomScale();}比例 *= 缩放比例;};this.pan = 函数(距离){distance.transformDirection( this.object.matrix );distance.multiplyScalar(scope.userPanSpeed);this.object.position.add(距离);this.center.add(距离);};this.update = 函数 () {var position = this.object.position;var offset = position.clone().sub(this.center);//y 轴与 z 轴的夹角var theta = Math.atan2( offset.x, offset.z );//y轴的角度var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );如果(this.autoRotate){this.rotateLeft(getAutoRotationAngle());}theta += thetaDelta;phi += phiDelta;//将 phi 限制在所需的限制之间phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );//将 phi 限制在 EPS 和 PI-EPS 之间phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );var radius = offset.length() * scale;//将半径限制在所需范围之间半径 = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );offset.x = radius * Math.sin( phi ) * Math.sin( theta );offset.y = 半径 * Math.cos( phi );offset.z = 半径 * Math.sin( phi ) * Math.cos( theta );position.copy(this.center).add(offset);this.object.lookAt(this.center);θDelta = 0;phiDelta = 0;规模= 1;if ( lastPosition.distanceTo( this.object.position ) > 0 ) {this.dispatchEvent(changeEvent);lastPosition.copy( this.object.position );}};函数 getAutoRotationAngle() {返回 2 * Math.PI/60/60 * scope.autoRotateSpeed;}函数 getZoomScale() {返回 Math.pow( 0.95, scope.userZoomSpeed );}函数 onMouseDown( 事件 ) {if ( scope.enabled === false ) 返回;if ( scope.userRotate === false ) 返回;event.preventDefault();if ( event.button === 0 ) {状态 = STATE.ROTATE;rotateStart.set( event.clientX, event.clientY );} else if ( event.button === 1 ) {状态 = STATE.ZOOM;zoomStart.set( event.clientX, event.clientY );} else if ( event.button === 2 ) {状态 = STATE.PAN;}document.addEventListener('mousemove', onMouseMove, false );document.addEventListener('mouseup', onMouseUp, false );}函数 onMouseMove( 事件 ) {if ( scope.enabled === false ) 返回;event.preventDefault();如果(状态 === 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 );如果(zoomDelta.y > 0){范围.zoomIn();} 别的 {范围.zoomOut();}zoomStart.copy( zoomEnd );} else if ( state === STATE.PAN ) {var moveX = event.movementX ||event.mozMovementX ||event.webkitMovementX ||0;var motionY = event.movementY ||event.mozMovementY ||event.webkitMovementY ||0;scope.pan(new THREE.Vector3(-motionX, movementY, 0));}}函数 onMouseUp( 事件 ) {if ( scope.enabled === false ) 返回;if ( scope.userRotate === false ) 返回;document.removeEventListener('mousemove', onMouseMove, false );document.removeEventListener('mouseup', onMouseUp, false );状态 = STATE.NONE;}功能 onMouseWheel( 事件 ) {if ( scope.enabled === false ) 返回;if ( scope.userZoom === false ) 返回;无功增量 = 0;if ( event.wheelDelta ) {//WebKit/Opera/Explorer 9delta = event.wheelDelta;} else if ( event.detail ) {//火狐delta = - event.detail;}如果(增量> 0){范围.zoomOut();} 别的 {范围.zoomIn();}}函数 onKeyDown( 事件 ) {if ( scope.enabled === false ) 返回;if ( scope.userPan === false ) 返回;开关(事件.keyCode){案例范围.keys.UP:scope.pan(new THREE.Vector3(0, 1, 0));休息;案例范围.keys.BOTTOM:scope.pan(new THREE.Vector3(0, - 1, 0));休息;案例范围.keys.LEFT:scope.pan( new THREE.Vector3( - 1, 0, 0 ) );休息;案例范围.keys.RIGHT:scope.pan( new THREE.Vector3( 1, 0, 0 ) );休息;}}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 );//火狐this.domElement.addEventListener('keydown', onKeyDown, false );};THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype);

解决方案

平移操作正在更新名为 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;};

然后更新方法将使相机保持在 center 向量上.

I'm using OrbitControls.js to allow mouse interaction. I'm adding a button into the scene that allows to "reset" the camera to it's state where it was before any mouse interactions.

I have tried to save camera.position and camera.rotation before any interactions:

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

And after the "reset" button is pressed, the initial position and rotation is set:

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

It works well if pan is not used. If user pans using mouse right button, then the above code cannot "reset" camera.

What is the right method to "reset" the camera to its previous state?

Revision of three.js is r58 and this is the 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 );

解决方案

Pan operation is updating vector called this.center , you need to reset it to see pan method ,

this.center.add( distance );

set this method to:

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;
    };

and then the update method will keep the camera looking at the center vector.

这篇关于使用 OrbitControls.js 重置相机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆