マウス操作を可能にするために 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 です。
/**
* @作者チャオ / https://github.com/qiao
* @著者 mrdoob / http://mrdoob.com
* @author modifiedq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
*/
THREE.OrbitControls = 関数 (オブジェクト、domElement) {
this.object = オブジェクト;
this.domElement = (domElement !== 未定義) ? domElement : ドキュメント;
// API
this.enabled = true;
this.center = 新しい 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 の場合、1 ラウンドあたり 30 秒
this.minPolarAngle = 0; // ラジアン
this.maxPolarAngle = Math.PI; // ラジアン
this.minDistance = 0;
this.maxDistance = 無限;
this.keys = { 左: 37、上: 38、右: 39、下: 40 };
// 内部
var スコープ = これ;
var EPS = 0.000001;
var PIXELS_PER_ROUND = 1800;
var 回転開始 = 新しい THREE.Vector2();
var rotateEnd = 新しい THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var zoomStart = new THREE.Vector2();
var zoomEnd = 新しい THREE.Vector2();
var zoomDelta = new THREE.Vector2();
var phiDelta = 0;
var thetaDelta = 0;
var スケール = 1;
var lastPosition = 新しい THREE.Vector3();
var STATE = { なし: -1、回転: 0、ズーム: 1、パン: 2 };
var 状態 = STATE.NONE;
// イベント
var changeEvent = { type: '変更' };
this.rotateLeft = 関数 (角度) {
if ( 角度 === 未定義 ) {
angle = getAutoRotationAngle();
}
thetaDelta -= 角度;
};
this.rotateRight = 関数 (角度) {
if ( 角度 === 未定義 ) {
angle = getAutoRotationAngle();
}
thetaDelta += 角度;
};
this.rotateUp = 関数 (角度) {
if ( 角度 === 未定義 ) {
angle = getAutoRotationAngle();
}
phiDelta -= 角度;
};
this.rotateDown = 関数 (角度) {
if ( 角度 === 未定義 ) {
angle = getAutoRotationAngle();
}
phiDelta += 角度;
};
this.zoomIn = 関数 ( zoomScale ) {
if ( zoomScale === 未定義 ) {
zoomScale = getZoomScale();
}
スケール/= zoomScale;
};
this.zoomOut = 関数 ( zoomScale ) {
if ( zoomScale === 未定義 ) {
zoomScale = getZoomScale();
}
スケール *= zoomScale;
};
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 オフセット = position.clone().sub( this.center );
// z 軸から y 軸周りの角度
var theta = Math.atan2( offset.x, offset.z );
// y 軸からの角度
var phi = Math.atan2( Math.sqrt( オフセット.x * オフセット.x + オフセット.z * オフセット.z ), オフセット.y );
if ( this.autoRotate ) {
this.rotateLeft( getAutoRotationAngle() );
}
シータ += シータデルタ;
ファイ += ファイデルタ;
// phi を希望の範囲内に制限する
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// ファイを EPS と PI-EPS の間に制限する
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// 希望の範囲内になるように半径を制限します
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
offset.x = 半径 * Math.sin( ファイ ) * Math.sin( シータ );
offset.y = 半径 * Math.cos( ファイ );
offset.z = 半径 * Math.sin( ファイ ) * Math.cos( シータ );
position.copy( this.center ).add( オフセット );
this.object.lookAt( this.center );
シータデルタ = 0;
ファイデルタ = 0;
スケール = 1;
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
}
};
関数 getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
関数 getZoomScale() {
return Math.pow( 0.95, scope.userZoomSpeed );
}
関数 onMouseDown( イベント ) {
if ( scope.enabled === false ) 戻ります。
if ( scope.userRotate === false ) return;
event.preventDefault();
if ( event.button === 0 ) {
状態 = 状態.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} そうでなければ ( event.button === 1 ) {
状態 = 状態.ZOOM;
zoomStart.set( event.clientX, event.clientY );
} その他の場合 ( event.button === 2 ) {
状態 = 状態.PAN;
}
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
}
関数 onMouseMove( イベント ) {
if ( scope.enabled === false ) 戻ります。
event.preventDefault();
if (状態 === 状態.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 );
回転開始.コピー(回転終了);
} それ以外の場合 (状態 === 状態.ズーム) {
zoomEnd.set( event.clientX, event.clientY );
zoomDelta.subVectors( zoomEnd, zoomStart );
もし ( zoomDelta.y > 0 ) {
scope.zoomIn();
} そうしないと {
scope.zoomOut();
}
zoomStart.copy( zoomEnd );
} それ以外の場合 (状態 === STATE.PAN ) {
var MovementX = event.movementX || event.mozMovementX || イベント.mozMovementX || event.webkitMovementX || 0;
var motionY = event.movementY || event.mozMovementY || イベント.mozMovementY || event.webkitMovementY || 0;
scope.pan( new THREE.Vector3( - 動きX, 動きY, 0 ) );
}
}
関数 onMouseUp( イベント ) {
if ( scope.enabled === false ) 戻ります。
if ( scope.userRotate === false ) return;
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
状態 = 状態.NONE;
}
関数 onMouseWheel( イベント ) {
if ( scope.enabled === false ) 戻ります。
if ( scope.userZoom === false ) 戻ります。
var デルタ = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
デルタ = event.wheelDelta;
} else if ( event.detail ) { // Firefox
デルタ = - event.detail;
}
もし (デルタ > 0 ) {
scope.zoomOut();
} そうしないと {
scope.zoomIn();
}
}
関数 onKeyDown( イベント ) {
if ( scope.enabled === false ) 戻ります。
if ( scope.userPan === false ) 戻ります。
スイッチ ( event.keyCode ) {
ケースscope.keys.UP:
scope.pan( 新しい THREE.Vector3( 0, 1, 0 ) );
壊す;
ケースscope.keys.BOTTOM:
scope.pan( 新しい THREE.Vector3( 0, - 1, 0 ) );
壊す;
ケースscope.keys.LEFT:
scope.pan( 新しい THREE.Vector3( - 1, 0, 0 ) );
壊す;
ケース scope.keys.RIGHT:
scope.pan( 新しい THREE.Vector3( 1, 0, 0 ) );
壊す;
}
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'マウスホイール', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // ファイアフォックス
this.domElement.addEventListener( 'keydown', onKeyDown, false );
};
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );