Panolens compass sensor
Compass sensor
지난번에 구현한 compass 컴퓨터에서는 잘 작동하는데 Control을 Sensor로 설정을 하니까 역시나 동작하지 않았다.
Sensor 선택 시 어떻게 동작을 하는지 구조부터 파악 하는 것이 먼저였다. Sensor로 검색을 하면 enableControl랑 연결되어 있고 여기서 index를 받아서 this.controls에서 control을 가져온다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /** * Enable control by index * @param {PANOLENS.Controls} index - Index of camera control */ PANOLENS.Viewer.prototype.enableControl = function ( index ) { index = ( index >= 0 && index < this.controls.length ) ? index : 0; this.control.enabled = false; this.control = this.controls[ index ]; this.control.enabled = true; switch ( index ) { case PANOLENS.Controls.ORBIT: this.camera.position.copy( this.panorama.position ); this.camera.position.z += 1; break; case PANOLENS.Controls.DEVICEORIENTATION: this.camera.position.copy( this.panorama.position ); break; default: break; } this.control.update(); this.activateWidgetItem( index, undefined ); }; | cs |
this.controls
다시 this.controls로 검색하면 PANOLENS.Viewer의 멤버변수로 찾을 수 있다. this.controls는 this.OrbitControls, this.DeviceOrientationControls를 가지는 배열이다.
1 2 | // Controls this.controls = [ this.OrbitControls, this.DeviceOrientationControls ]; | cs |
여기서 this.DeviceOrientationControls가 스마튼폰, Sensor와 밀접해 보였다. this.DeviceOrientationControls는 three.js 의 new THREE.DeviceOrientationControls( this.camera, this.container);으로 생성하고 있었는데 파라미터로 카메라와 컨테이너를 메개변수로 받아서 생성하고 있었다.
1 | this.DeviceOrientationControls = new THREE.DeviceOrientationControls( this.camera, this.container, this ); | cs |
new THREE.DeviceOrientationControls
다시 DeviceOrientationControls을 검색해서 코드를 보니 여기서 디바이스의 센서값을 처리하는 부분인지 알 수 있었다. 디바이스의 센서값을 계속 가져와서 카메라를 이동시키는 작업을 하니까 this.update 함수부터 살펴보았다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | this.update = function( ignoreUpdate ) { if ( scope.enabled === false ) return; var alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) + this.alphaOffsetAngle : 0; // Z var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X' var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y'' var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O setCameraQuaternion( scope.camera.quaternion, alpha, beta, gamma, orient ); this.alpha = alpha; ignoreUpdate !== true && this.dispatchEvent( changeEvent ); }; | cs |
무언갈 뚝딱뚝딱 만들어 setCameraQuaternion을 호출하네?
setCameraQuaternion
사실 여기서 어떤 동작을 하는지 잘 모르겠다. 일단은 Control에서 Sensor 선택하면 이부분이 계속호출되고 quaternion 도 관련 있으니 여기서 Compass를 업데이트 해주는 부분을 넣으면 동작할 것 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /* * 작성자: silqwer * 설명: 나침판 회전 함수 */ PANOLENS.Viewer.prototype.onRotationChange = function (element){ var camera = this.camera; this.control.addEventListener('change', function(){ var rotationY = camera.rotation.y; var dy = 0; if ( rotationY < 0 ){ dy = THREE.Math.radToDeg( rotationY + ( 2 * Math.PI ) ); }else{ dy = THREE.Math.radToDeg( rotationY ); } dy = Math.round(dy) * -1; element.style.transform = 'rotate('+ (dy % 360) +'deg)'; }, false); }; | cs |
앞서 만든 onRotationChange 함수의 경우 카메라와 나침판 바늘역활을 하는 element가 필요하다. 두녀석을 어디서 가져올까 고민을 하다가 Panolens에서 DeviceOrientationControls을 선언하는 부분에서 추가로 파라미터를 가져와서 사용하기로 했다.
DeviceOrientationControls 수정
1 | this.DeviceOrientationControls = new THREE.DeviceOrientationControls( this.camera, this.container, this ); | cs |
생성할 때 this를 파라미터르 추가해 Viewer를 가져온다. 그리곤 setCameraQuaternion가 호출될 때마다 compass를 업데이트 시켜줄 onDeviceMoveEvent 함수를 하나 만들고 setCameraQuaternion에 추가한다.
onDeviceMoveEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * 작성자: silqwer * 설명: Sensor 모드 시 Compass 동작 함수 */ var onDeviceMoveEvent = function (panolensViewer) { var rotationY = panolensViewer.camera.rotation.y; var dy = 0; var element; if ( rotationY < 0 ){ dy = THREE.Math.radToDeg( rotationY + ( 2 * Math.PI ) ); }else{ dy = THREE.Math.radToDeg( rotationY ); } dy = Math.round(dy) * -1; element = panolensViewer.widget.compassElement.childNodes[2]; element.style.transform = 'rotate('+ (dy % 360) +'deg)'; }; | cs |
결과